import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import classNames from 'classnames';
import { DateTime } from 'luxon';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { getSystemTimeZone } from '../../../lib/dates.js';
import { useGenerateAccessCodeCode } from '../../../lib/seam/access-codes/use-generate-access-code-code.js';
import { isLockDevice } from '../../../lib/seam/locks/lock-device.js';
import { AccessCodeFormDatePicker } from '../../../lib/ui/AccessCodeForm/AccessCodeFormDatePicker.js';
import { AccessCodeFormTimes } from '../../../lib/ui/AccessCodeForm/AccessCodeFormTimes.js';
import { AccessCodeFormTimeZonePicker } from '../../../lib/ui/AccessCodeForm/AccessCodeFormTimeZonePicker.js';
import { Button } from '../../../lib/ui/Button.js';
import { FormField } from '../../../lib/ui/FormField.js';
import { InputLabel } from '../../../lib/ui/InputLabel.js';
import { ContentHeader } from '../../../lib/ui/layout/ContentHeader.js';
import { RadioField } from '../../../lib/ui/RadioField/RadioField.js';
import { TextField } from '../../../lib/ui/TextField/TextField.js';
import { useToggle } from '../../../lib/ui/use-toggle.js';
export function AccessCodeForm({ className, ...props }) {
    return (_jsx("div", { className: classNames('seam-access-code-form', className), children: _jsx(Content, { ...props }) }));
}
function Content({ onBack, accessCode, device, onSubmit, isSubmitting, responseErrors, }) {
    const [type, setType] = useState(accessCode?.type ?? 'ongoing');
    const [datePickerVisible, setDatePickerVisible] = useState(false);
    const [timeZone, setTimeZone] = useState(getSystemTimeZone());
    const [startDate, setStartDate] = useState(getAccessCodeDate('starts_at', accessCode) ?? getNow(timeZone));
    const [endDate, setEndDate] = useState(getAccessCodeDate('ends_at', accessCode) ?? getOneDayFromNow(timeZone));
    const save = (data) => {
        if (isSubmitting) {
            return;
        }
        const start = startDate.toISO();
        if (start == null) {
            throw new Error(`Invalid start date: ${startDate.invalidReason}`);
        }
        const end = endDate.toISO();
        if (end == null) {
            throw new Error(`Invalid end date: ${endDate.invalidReason}`);
        }
        onSubmit({
            name: data.name,
            code: data.code,
            type,
            device,
            startDate: start,
            endDate: end,
            timeZone,
        });
    };
    const { register, handleSubmit, formState: { errors }, setValue, } = useForm({
        defaultValues: {
            name: accessCode?.name ?? '',
            code: accessCode?.code ?? '',
        },
    });
    const [timeZonePickerVisible, toggleTimeZonePicker] = useToggle();
    const { isLoading: isGeneratingCode, mutate: generateCode } = useGenerateAccessCodeCode();
    const submit = () => { };
    if (timeZonePickerVisible) {
        return (_jsx(AccessCodeFormTimeZonePicker, { value: timeZone, onChange: (timeZone) => {
                setTimeZone(timeZone);
                setStartDate(startDate.setZone(timeZone));
                setEndDate(endDate.setZone(timeZone));
            }, onClose: toggleTimeZonePicker }));
    }
    if (datePickerVisible) {
        return (_jsx(AccessCodeFormDatePicker, { startDate: startDate, setStartDate: setStartDate, endDate: endDate, setEndDate: setEndDate, timeZone: timeZone, onChangeTimeZone: toggleTimeZonePicker, onBack: () => {
                setDatePickerVisible(false);
            } }));
    }
    const title = accessCode == null ? t.addNewAccessCode : t.editAccessCode;
    const handleGenerateCode = () => {
        generateCode({
            device_id: device.device_id,
        }, {
            onSuccess: ({ code: generatedCode }) => {
                if (generatedCode != null) {
                    setValue('code', generatedCode);
                }
            },
        });
    };
    const hasCodeError = errors.code != null || responseErrors?.code != null;
    const codeLengthRequirement = getCodeLengthRequirement(device);
    const codeLengthRequirementMessage = codeLengthRequirement != null
        ? t.codeLengthRequirement(codeLengthRequirement)
        : null;
    const hasCodeInputs = accessCode?.type !== 'time_bound' || accessCode.is_offline_access_code;
    return (_jsxs(_Fragment, { children: [_jsx(ContentHeader, { title: title, subheading: device.properties.name, onBack: onBack }), _jsx("div", { className: 'seam-main', children: _jsxs("form", { onSubmit: (event) => {
                        void handleSubmit(save)(event);
                    }, children: [_jsxs(FormField, { children: [_jsx(InputLabel, { children: t.nameInputLabel }), _jsx(TextField, { size: 'large', clearable: true, hasError: errors.name != null, helperText: errors.name?.message, inputProps: {
                                        ...register('name', {
                                            required: t.nameRequiredError,
                                            maxLength: {
                                                value: 60,
                                                message: t.nameOverCharacterLimitError,
                                            },
                                        }),
                                    } })] }), hasCodeInputs && (_jsxs(_Fragment, { children: [_jsxs(FormField, { className: 'seam-code-field', children: [_jsx(InputLabel, { children: t.codeInputLabel }), _jsx(TextField, { size: 'large', clearable: true, hasError: hasCodeError, helperText: responseErrors?.code ?? errors.code?.message, inputProps: {
                                                ...register('code', {
                                                    required: t.codeRequiredError,
                                                    validate: (value) => validateCodeLength(device, value),
                                                }),
                                            } }), _jsxs("div", { className: classNames('seam-bottom', {
                                                'has-hints': codeLengthRequirementMessage != null,
                                            }), children: [codeLengthRequirementMessage != null && (_jsxs("ul", { className: classNames('seam-requirements', {
                                                        'seam-error': hasCodeError,
                                                    }), children: [_jsx("li", { children: codeLengthRequirementMessage }), _jsx("li", { children: t.codeNumbersOnlyRequirement })] })), _jsx(Button, { size: 'small', onMouseDown: (e) => {
                                                        e.preventDefault(); // Disable stealing input focus
                                                        handleGenerateCode();
                                                    }, disabled: isGeneratingCode, children: t.codeGenerateButton })] })] }), _jsxs(FormField, { children: [_jsx(InputLabel, { children: t.timingInputLabel }), _jsx(RadioField, { value: type, onChange: setType, name: 'type', options: [
                                                {
                                                    label: t.typeOngoingLabel,
                                                    value: 'ongoing',
                                                },
                                                {
                                                    label: t.typeTimeBoundLabel,
                                                    value: 'time_bound',
                                                },
                                            ] }), _jsx(_Fragment, { children: type === 'time_bound' && (_jsx(AccessCodeFormTimes, { startDate: startDate, endDate: endDate, onEdit: () => {
                                                    setDatePickerVisible(true);
                                                } })) })] })] })), responseErrors?.unknown != null && (_jsx("div", { className: 'seam-unknown-error', children: responseErrors?.unknown })), _jsxs("div", { className: 'seam-actions', children: [_jsx(Button, { onClick: onBack, children: t.cancel }), _jsx(Button, { variant: 'solid', disabled: isSubmitting, onMouseDown: submit, type: 'submit', children: t.save })] })] }) })] }));
}
const validateCodeLength = (device, value) => {
    if (!isLockDevice(device)) {
        return true;
    }
    if (device.properties.supported_code_lengths == null) {
        return true;
    }
    if (device.properties.supported_code_lengths.includes(value.length)) {
        return true;
    }
    return t.codeLengthError(device.properties.supported_code_lengths.join(', '));
};
const getCodeLengthRequirement = (device) => {
    if (!isLockDevice(device)) {
        return null;
    }
    const codeLengths = device.properties.supported_code_lengths;
    if (codeLengths == null) {
        return null;
    }
    if (codeLengths.length === 1) {
        return `${codeLengths[0]}`;
    }
    if (isSequential(codeLengths.join(''))) {
        return `${codeLengths[0]}-${codeLengths[codeLengths.length - 1]}`;
    }
    return codeLengths.join(', ');
};
// 0 - 99 in a string
// 0123456789101112...99
const sequentialNumbers = Array.from({ length: 100 }, (_, index) => index).join('');
const isSequential = (numbers) => sequentialNumbers.includes(numbers);
const getAccessCodeDate = (date, accessCode) => {
    if (accessCode == null) {
        return null;
    }
    if (accessCode.type !== 'time_bound') {
        return null;
    }
    return DateTime.fromISO(accessCode[date]);
};
const getNow = (timeZone) => DateTime.now().setZone(timeZone);
const getOneDayFromNow = (timeZone) => DateTime.now().setZone(timeZone).plus({ days: 1 });
const t = {
    addNewAccessCode: 'Add new access code',
    editAccessCode: 'Edit access code',
    nameOverCharacterLimitError: '60 characters max',
    nameRequiredError: 'Name is required',
    nameInputLabel: 'Name the new code',
    codeGenerateButton: 'Generate code',
    codeInputLabel: 'Enter the code (PIN)',
    codeRequiredError: 'Code is required',
    codeLengthError: (lengths) => `Code length must be one of the following: ${lengths}`,
    codeLengthRequirement: (lengths) => `${lengths} digit code`,
    codeNumbersOnlyRequirement: 'Numbers only',
    cancel: 'Cancel',
    save: 'Save',
    timingInputLabel: 'Timing',
    typeOngoingLabel: 'Ongoing',
    typeTimeBoundLabel: 'Start/end times',
};
//# sourceMappingURL=AccessCodeForm.js.map