import { fireEvent, render } from '@testing-library/react';
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
import TimePicker, { timeOptions } from '../time-picker';
import type { TimePickerProps } from '../time-picker';

dayjs.extend(utc);
dayjs.extend(timezone);

const interval = 60;

describe('timeOptions', () => {
    const valueFormat = 'HH:mm:ss';
    const labelTimeFormat = 'HH:mm';
    const labelFormatter = (input: string) => input;

    test('returns interval at every hour, with formatted label', () =>
        expect(
            timeOptions({
                interval,
                valueFormat,
                labelTimeFormat,
                labelFormatter,
            })
        ).toEqual(
            Array.from(Array(24).keys())
                .reduce(
                    (acc, hour) => [
                        ...acc,
                        `${hour.toString().padStart(2, '0')}:00:00`,
                    ],
                    [] as string[]
                )
                .map(value => ({
                    value,
                    label: dayjs(`2020-01-01T${value}Z`)
                        .tz('Etc/Gmt')
                        .format('HH:mm'),
                }))
        ));
});

describe('<TimePicker>', () => {
    const onChange = jest.fn();
    const value = '00:00:00';

    const defaultProps: TimePickerProps = {
        interval,
        value,
        onChange,
    };

    const renderWrapper = (props: Partial<TimePickerProps> = {}) =>
        render(<TimePicker {...defaultProps} {...props} />);

    test('matches snapshot', () => {
        const { container } = renderWrapper();
        expect(container).toMatchSnapshot();
    });

    describe('onChange', () => {
        test('invoked with value when option pressed', () => {
            const { container } = renderWrapper();

            const selectControl =
                container.getElementsByClassName('Select__control');
            fireEvent.mouseDown(selectControl[0]);

            const selectMenu = container.getElementsByClassName('Select__menu');
            const selectOptions =
                selectMenu[0].getElementsByClassName('Select__option');
            fireEvent.click(selectOptions[1]);

            expect(onChange).toHaveBeenCalledWith('01:00:00');
        });

        test('invoked when new option is created', () => {
            const { container, getByText } = renderWrapper();

            const input = container.getElementsByTagName('input').item(0);
            const customOption = '08:35';
            fireEvent.change(input!, { target: { value: customOption } });

            const selectMenu = container.getElementsByClassName('Select__menu');
            const selectOptions =
                selectMenu[0].getElementsByClassName('Select__option');
            fireEvent.click(selectOptions[0]);

            const selectControl =
                container.getElementsByClassName('Select__control');
            fireEvent.mouseDown(selectControl[0]);
            const customOptionElement = getByText('08:35');

            expect(onChange).toHaveBeenCalledWith('08:35:00');
            expect(customOptionElement).toBeInTheDocument();
        });

        test('not invoked when custom time is invalid', () => {
            const mockOnChange = jest.fn();
            const { container, queryByText } = renderWrapper({
                onChange: mockOnChange,
            });

            const input = container.getElementsByTagName('input').item(0);
            const customOption = '8:35';
            fireEvent.change(input!, { target: { value: customOption } });

            const selectMenu = container.getElementsByClassName('Select__menu');
            const selectOptions =
                selectMenu[0].getElementsByClassName('Select__option');
            fireEvent.click(selectOptions[0]);

            const selectControl =
                container.getElementsByClassName('Select__control');
            fireEvent.mouseDown(selectControl[0]);
            const customOptionElement = queryByText('08:35');

            expect(mockOnChange).not.toHaveBeenCalled();
            expect(customOptionElement).not.toBeInTheDocument();
        });
    });
});
