import { useCallback, useEffect, useState } from 'react';
import { FormProvider, type UseFormProps, useForm } from 'react-hook-form';

import { Stack } from '@mui/material';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { addDays, isSameDay, startOfWeek } from 'date-fns';

import FormDatePicker, { type FormDatePickerProps } from './form';
import DatePicker from '.';

const meta: Meta<typeof DatePicker> = {
  component: DatePicker,
  title: 'Design System/Inputs/DatePickers/Date',
  tags: ['autodocs'],
  argTypes: {
    label: { control: 'text' },
    helperText: { control: 'text' },
    disabled: { control: 'boolean' },
    disableFuture: { control: 'boolean' },
    disablePast: { control: 'boolean' },
    enableClear: { control: 'boolean' },
    timezone: { control: 'text' },
    value: { control: false },
    onChange: { control: false },
    slotProps: { control: false },
    sx: { control: false },
  },
  args: {
    label: 'Label',
    helperText: 'Helper Text',
  },
  decorators: [
    Story => (
      <LocalizationProvider dateAdapter={AdapterDateFns}>
        <Story />
      </LocalizationProvider>
    ),
  ],
};

export default meta;

type Story = StoryObj<typeof DatePicker>;

export const Default: Story = {
  render: args => {
    return <DatePicker {...args} />;
  },
};

type RenderFormStoryProps = {
  defaultValues?: Record<string, Date | null>;
  formOptions?: UseFormProps;
  datePickerProps: FormDatePickerProps;
};

const FormStoryTemplate = ({
  defaultValues,
  formOptions,
  datePickerProps,
}: RenderFormStoryProps) => {
  const form = useForm({
    defaultValues: defaultValues || { myDatePicker: new Date() },
    ...formOptions,
  });

  const watchedValues = form.watch();

  return (
    <>
      <pre>{JSON.stringify(watchedValues)}</pre>
      <FormProvider {...form}>
        <FormDatePicker {...datePickerProps} />
      </FormProvider>
    </>
  );
};

export const FormDatePickerDefault: Story = {
  render: () => (
    <FormStoryTemplate
      datePickerProps={{
        inputProps: {},
        name: 'myDatePicker',
      }}
    />
  ),
};

export const FormDatePickerSmall: Story = {
  render: () => (
    <FormStoryTemplate
      datePickerProps={{
        inputProps: {
          size: 'small',
          sx: {
            width: '150px',
          },
        },
        name: 'myDatePicker',
      }}
    />
  ),
};

export const Disabled: Story = {
  render: () => {
    const form = useForm({
      defaultValues: {
        myDatePicker: null,
      },
    });

    return (
      <FormProvider {...form}>
        <FormDatePicker
          inputProps={{
            disabled: true,
          }}
          name="myDatePicker"
        />
      </FormProvider>
    );
  },
};

export const DisableFuture: Story = {
  render: () => (
    <FormStoryTemplate
      datePickerProps={{
        inputProps: {
          label: 'Choose date',
          disableFuture: true,
        },
        name: 'myDatePicker',
      }}
    />
  ),
};

export const DisablePast: Story = {
  render: () => (
    <FormStoryTemplate
      datePickerProps={{
        inputProps: {
          label: 'Choose date',
          disablePast: true,
        },
        name: 'myDatePicker',
      }}
    />
  ),
};

export const Timezone: Story = {
  render: () => (
    <>
      <FormStoryTemplate
        datePickerProps={{
          inputProps: {
            label: 'Choose date',
            timezone: 'Asia/Anadyr',
            disablePast: true,
          },
          name: 'myDatePicker',
        }}
      />
    </>
  ),
};

export const ClearableField: Story = {
  render: () => (
    <FormStoryTemplate
      datePickerProps={{
        inputProps: {
          helperText: 'Date picker with clearable field',
          label: 'Choose date (optional)',
          enableClear: true,
        },
        name: 'myDatePicker',
      }}
    />
  ),
};

export const Errors: Story = {
  render: () => {
    const form = useForm({
      defaultValues: {
        start: null,
        end: null,
      },
    });

    const endDate = form.watch('end') as Date | null;
    const startDate = form.watch('start') as Date | null;

    useEffect(() => {
      if (endDate && isNaN(endDate.getTime())) {
        form.setError('end', {
          type: 'validate',
          message: 'Invalid date',
        });
      } else {
        if (startDate && endDate && startDate > endDate) {
          form.setError('end', {
            type: 'validate',
            message: 'End date must be after start date',
          });
        } else {
          form.clearErrors('end');
        }
      }
    }, [startDate, endDate]);

    return (
      <>
        <pre>{JSON.stringify(form.getValues())}</pre>
        <pre>{JSON.stringify(form.formState.errors, null, 2)}</pre>
        <FormProvider {...form}>
          <Stack sx={{ gap: 2 }}>
            <FormDatePicker
              inputProps={{
                label: 'From',
              }}
              name="start"
            />
            <FormDatePicker
              inputProps={{
                label: 'To',
              }}
              name="end"
            />
          </Stack>
        </FormProvider>
      </>
    );
  },
};

const MOCK_HOLIDAYS = [
  new Date(2026, 0, 1),
  new Date(2026, 2, 24),
  new Date(2026, 3, 2),
  new Date(2026, 3, 3),
  new Date(2026, 3, 10),
  new Date(2026, 4, 25),
  new Date(2026, 5, 20),
  new Date(2026, 6, 20),
  new Date(2026, 7, 20),
  new Date(2026, 8, 20),
  new Date(2026, 9, 20),
  new Date(2026, 10, 20),
  new Date(2026, 11, 20),
  new Date(2027, 0, 1),
  new Date(2027, 2, 24),
  new Date(2027, 3, 2),
  new Date(2027, 3, 3),
  new Date(2027, 3, 10),
  new Date(2027, 4, 25),
  new Date(2027, 5, 20),
  new Date(2027, 6, 20),
];

// Simulate a request to the backend to get the holidays for a given year
const fetchHolidaysByYear = (year: number): Promise<Date[]> =>
  new Promise(resolve =>
    setTimeout(
      () => resolve(MOCK_HOLIDAYS.filter(d => d.getFullYear() === year)),
      600,
    ),
  );

export const DisabledDates: Story = {
  render: () => {
    const [visibleYear, setVisibleYear] = useState(() =>
      new Date().getFullYear(),
    );
    const [holidays, setHolidays] = useState<Date[]>([]);

    useEffect(() => {
      fetchHolidaysByYear(visibleYear).then(setHolidays);
    }, [visibleYear]);

    const shouldDisableDate = useCallback(
      (day: Date) => holidays.some(h => isSameDay(h, day)),
      [holidays],
    );

    return (
      <FormStoryTemplate
        datePickerProps={{
          inputProps: {
            label: 'Choose date',
            helperText: 'Disabled specific dates',
            shouldDisableDate,
            onYearChange: date => setVisibleYear(date.getFullYear()),
          },
          name: 'myDatePicker',
        }}
      />
    );
  },
};

export const DatesWithTooltip: Story = {
  render: () => {
    const shouldDisableDate = useCallback(
      (day: Date) => day.getDate() > 15,
      [],
    );

    const getDayTooltip = useCallback((day: Date) => day.toDateString(), []);

    return (
      <FormStoryTemplate
        datePickerProps={{
          inputProps: {
            label: 'Choose date',
            helperText: 'Hover over a date to see the tooltip',
            shouldDisableDate,
            getDayTooltip,
          },
          name: 'myDatePicker',
        }}
      />
    );
  },
};

const HOLIDAY_SATURDAY = new Date(2026, 3, 4);
const SUNDAY = 0;
const SATURDAY = 6;

export const AllowedWeekendDays: Story = {
  render: () => {
    const shouldDisableDate = useCallback((day: Date) => {
      const dayOfWeek = day.getDay();
      if (dayOfWeek !== SUNDAY && dayOfWeek !== SATURDAY) return true;
      if (isSameDay(day, HOLIDAY_SATURDAY)) return true;
      return false;
    }, []);

    return (
      <FormStoryTemplate
        datePickerProps={{
          inputProps: { shouldDisableDate },
          name: 'myDatePicker',
        }}
      />
    );
  },
};

const TIMEOFF_HOLIDAYS = [
  new Date(2026, 3, 6), // Monday,
  new Date(2026, 3, 20), //Monday,
  new Date(2026, 3, 21), //Tuesday,
];

export const FirstAvailableFromMonday: Story = {
  render: () => {
    const shouldDisableDate = useCallback((day: Date) => {
      const dayOfWeek = day.getDay();
      if (dayOfWeek === SUNDAY || dayOfWeek === SATURDAY) return true;
      const monday = startOfWeek(day, { weekStartsOn: 1 });

      const firstAvailable = Array.from({ length: 5 }, (_, i) =>
        addDays(monday, i),
      ).find(candidate => !TIMEOFF_HOLIDAYS.some(h => isSameDay(h, candidate)));
      return firstAvailable ? !isSameDay(day, firstAvailable) : true;
    }, []);
    return (
      <FormStoryTemplate
        datePickerProps={{
          inputProps: {
            label: 'Fecha de inicio',
            helperText:
              'Solo lunes hábiles (o siguiente día hábil si es feriado)',
            shouldDisableDate,
            disablePast: true,
          },
          name: 'myDatePicker',
        }}
      />
    );
  },
};

export const SlotPropsOverride: Story = {
  render: () => {
    const form = useForm({
      defaultValues: {
        myDatePicker: null,
      },
    });

    return (
      <FormProvider {...form}>
        <FormDatePicker
          inputProps={{
            slotProps: {
              day: {
                sx: {
                  color: '#2C2C2C',
                  '&.Mui-selected, &.Mui-selected.Mui-focusVisible': {
                    backgroundColor: '#2C2C2C!important',
                    color: '#FFFFFF',
                  },
                  '&.MuiPickersDay-today': {
                    borderColor: '#2C2C2C',
                  },
                },
              },
              actionBar: {
                sx: {
                  '& .MuiButton-root': {
                    color: '#2C2C2C',
                  },
                },
              },
            },
          }}
          name="myDatePicker"
        />
      </FormProvider>
    );
  },
};
