import { Dropdown } from '@theorchard/suite-components';
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import React, { useState } from 'react';
import type { FC } from 'react';

dayjs.extend(customParseFormat);
dayjs.extend(localizedFormat);

export interface TimePickerProps {
    interval: number;
    value?: string;
    className?: string;
    labelTimeFormat?: string;
    labelFormatter?: (input: string) => string;
    valueFormat?: string;
    maxMenuHeight?: number;
    onChange: (time: string) => void;
    enabled?: boolean;
}

const customInputFormats = [
    'h:mma',
    'hh:mma',
    'h:mm a',
    'hh:mm a',
    'h:mmA',
    'hh:mmA',
    'h:mm A',
    'hh:mm A',
    'HH:mm',
];

/**
 * Returns DropdownProps representing times for a single date,
 * corresponding to the provided interval, starting at midnight.
 * Uses labelFormat and valueFormat for display and returned values.
 *
 * @param interval number of minutes for interval
 * @param labelTimeFormat format string to use for label's time property
 * @param labelFormatter formatting function to use for the label, with
 * labelTimeFormat applied to input
 * @param valueFormat format string to use for value property
 * @returns an array of DropdownOption containing ISO 8601 values in HH:mm:ss format,
 * and human readable h:mm b labels
 */
export const timeOptions = ({
    interval,
    labelTimeFormat,
    labelFormatter,
    valueFormat,
}: {
    interval: number;
    labelTimeFormat: string;
    labelFormatter: (input: string) => string;
    valueFormat: string;
}) => {
    const start = dayjs().startOf('day');
    const end = start.endOf('day');
    const dates = [];

    let current = start;
    while (current.isBefore(end)) {
        dates.push(current);
        current = current.add(interval, 'minute');
    }

    return dates.map(date => ({
        label: labelFormatter(date.format(labelTimeFormat)),
        value: date.format(valueFormat),
    }));
};

export const TimePicker: FC<TimePickerProps> = ({
    interval,
    value,
    className,
    labelTimeFormat = 'HH:mm',
    labelFormatter = input => input,
    valueFormat = 'HH:mm:ss',
    maxMenuHeight = 800,
    onChange,
    enabled = true,
}) => {
    const [options, setOptions] = useState(
        timeOptions({ interval, labelTimeFormat, labelFormatter, valueFormat })
    );
    return (
        <Dropdown.Creatable
            isDisabled={!enabled}
            className={className}
            options={options}
            value={options.find(({ value: v }) => value === v)}
            onChange={selected => {
                if (!selected) return;
                onChange(selected.value);
            }}
            maxMenuHeight={maxMenuHeight}
            onCreateOption={inputValue => {
                const customTime = dayjs(inputValue, customInputFormats, true);
                if (customTime.isValid()) {
                    const customOption = {
                        label: labelFormatter(
                            customTime.format(labelTimeFormat)
                        ),
                        value: customTime.format(valueFormat),
                    };
                    setOptions(
                        [...options, customOption].sort((a, b) => {
                            return (
                                dayjs(a.value, valueFormat).valueOf() -
                                dayjs(b.value, valueFormat).valueOf()
                            );
                        })
                    );
                    onChange(customOption.value);
                }
            }}
        />
    );
};

export default TimePicker;
