/** @jsxRuntime classic */
/** @jsx jsx */
import React, { useState, useEffect, Fragment } from 'react';
import { useTheme } from '@emotion/react';
import { StyledCalendar } from '../style';
import cx from 'classnames';
import { BnBack, BnForward } from '../../../icons';
import dayjs, { Dayjs } from 'dayjs';
import { DateProps, WeekDay } from './Date';
import { jsx, css } from '@emotion/react';
import { SelectOptions } from '../../Options';
import { IOption } from '../../Select';

type TStep = 'year' | 'month' | 'day';

const yearsCss = css`
  width: 250px;
  height: 300px;
  overflow-y: scroll;
  div {
    text-align: center;
  }
`;

export const DateOfBirth = ({
  defaultValue,
  disabledDates,
  mode = 'date',
  value,
  onChange,
}: DateProps) => {
  const getValueFormat = () => {
    if (mode === 'date') {
      return 'DD / MM / YYYY';
    } else if (mode === 'datetime') {
      return 'DD / MM / YYYY HH:mm';
    } else {
      return 'HH:mm';
    }
  };
  const colors = useTheme();
  const currentDate = dayjs();
  const [selectedMonth, setSelectedMonth] = useState<{
    month: number;
    year: number;
  }>({
    month: defaultValue ? dayjs(defaultValue).month() : dayjs().month(),
    year: defaultValue ? dayjs(defaultValue).year() : dayjs().year(),
  });
  const [weeksAndDays, setWeeksAndDays] = useState<any[]>([]);
  const [hoverPlaceholder, setHoverPlaceholder] = useState<string | undefined>(
    undefined
  );
  const [selectedDay, setSelectedDay] = useState<dayjs.Dayjs>(
    defaultValue ? dayjs(defaultValue) : dayjs()
  );
  const [inputValue, setInputValue] = useState<string | undefined>(
    value ? dayjs(value).format(getValueFormat()) : undefined
  );
  const [isOptionsOpen, setIsOptionsOpen] = useState<boolean>(false);
  const [step, setStep] = useState<TStep>('year');
  const [years, setYears] = useState<IOption[]>([]);
  const [months, setMonths] = useState<IOption[]>([]);
  const [selectedYear, setSelectedYear] = useState<number>();

  useEffect(() => {
    const potentialYears = [];
    const potentialMonths = [];
    for (
      let i = Number(dayjs().format('YYYY'));
      i > Number(dayjs().format('YYYY')) - 100;
      i--
    ) {
      potentialYears.push({
        label: String(i),
        value: i,
      });
    }
    for (let j = 1; j < 13; j++) {
      potentialMonths.push({
        label: String(j),
        value: j,
      });
    }
    setMonths(potentialMonths);
    setYears(potentialYears);
  }, []);

  const weekDays = [
    dayjs().day(1).format('dd').slice(0, 1),
    dayjs().day(2).format('dd').slice(0, 1),
    dayjs().day(3).format('dd').slice(0, 1),
    dayjs().day(4).format('dd').slice(0, 1),
    dayjs().day(5).format('dd').slice(0, 1),
    dayjs().day(6).format('dd').slice(0, 1),
    dayjs().day(0).format('dd').slice(0, 1),
  ];

  const getWeekday = (date: string) => {
    return dayjs(date).day();
  };

  const createCalendar = () => {
    let currentMonthDays = [
      ...Array(
        dayjs(
          `${selectedMonth.year}-${selectedMonth.month + 1}-01`
        ).daysInMonth()
      ),
    ].map((_, index) => {
      return {
        date: dayjs(
          `${selectedMonth.year}-${selectedMonth.month + 1}-${index + 1}`
        ).format('YYYY-MM-DD'),
        dayOfMonth: index + 1,
        isCurrentMonth: true,
        isDisabled:
          disabledDates &&
          disabledDates(
            dayjs(
              `${selectedMonth.year}-${selectedMonth.month + 1}-${index + 1}`
            )
          ),
      };
    });

    const currentMonthFirstDay = getWeekday(currentMonthDays[0].date);

    const previousMonth = dayjs(
      `${selectedMonth.year}-${selectedMonth.month + 1}-01`
    ).subtract(1, 'month');

    const daysOfPreviousMonth = currentMonthFirstDay
      ? currentMonthFirstDay - 1
      : 6;

    const lastMondayOfPreviousMonth = dayjs(currentMonthDays[0].date)
      .subtract(daysOfPreviousMonth, 'day')
      .date();

    let previousMonthDays = [...Array(daysOfPreviousMonth)].map((_, index) => {
      return {
        date: dayjs(
          `${previousMonth.year()}-${previousMonth.month() + 1}-${
            lastMondayOfPreviousMonth + index
          }`
        ).format('YYYY-MM-DD'),
        dayOfMonth: lastMondayOfPreviousMonth + index,
        isCurrentMonth: false,
        isDisabled:
          disabledDates &&
          disabledDates(
            dayjs(
              `${previousMonth.year()}-${previousMonth.month() + 1}-${
                lastMondayOfPreviousMonth + index
              }`
            )
          ),
      };
    });

    const currentMonthLastDay = getWeekday(
      `${selectedMonth.year}-${selectedMonth.month + 1}-${
        currentMonthDays.length
      }`
    );

    const nextMonth = dayjs(
      `${selectedMonth.year}-${selectedMonth.month + 1}-01`
    ).add(1, 'month');

    const daysOfNextMonth = currentMonthLastDay
      ? 7 - currentMonthLastDay
      : currentMonthLastDay;

    let nextMonthDays = [...Array(daysOfNextMonth)].map((_, index) => {
      return {
        date: dayjs(
          `${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`
        ).format('YYYY-MM-DD'),
        dayOfMonth: index + 1,
        isCurrentMonth: false,
        isDisabled:
          disabledDates &&
          disabledDates(
            dayjs(`${nextMonth.year()}-${nextMonth.month() + 1}-${index + 1}`)
          ),
      };
    });

    let days = [...previousMonthDays, ...currentMonthDays, ...nextMonthDays];

    return days;
  };

  const goBack = () => {
    setSelectedMonth({
      month: dayjs(
        dayjs()
          .month(selectedMonth.month)
          .year(selectedMonth.year)
          .subtract(1, 'month')
      ).month(),
      year: dayjs(
        dayjs()
          .month(selectedMonth.month)
          .year(selectedMonth.year)
          .subtract(1, 'month')
      ).year(),
    });
  };

  const goForward = () => {
    setSelectedMonth({
      month: dayjs(
        dayjs()
          .month(selectedMonth.month)
          .year(selectedMonth.year)
          .add(1, 'month')
      ).month(),
      year: dayjs(
        dayjs()
          .month(selectedMonth.month)
          .year(selectedMonth.year)
          .add(1, 'month')
      ).year(),
    });
  };

  useEffect(() => {
    let days = createCalendar();
    const chunkDays = () => {
      let results = [];
      while (days.length) {
        results.push(days.splice(0, 7));
      }
      return results;
    };

    setWeeksAndDays(chunkDays());
  }, [selectedMonth]);

  const selectYear = (year: number) => {
    setSelectedYear(year);
    setStep('month');
  };

  const selectMonth = (month: number) => {
    setSelectedMonth({
      year: selectedYear || dayjs().year(),
      month: month - 1,
    });
    setStep('day');
  };

  return (
    <Fragment>
      {step === 'year' && (
        <div css={yearsCss}>
          <SelectOptions options={years} onSelect={selectYear} />
        </div>
      )}
      {step === 'month' && (
        <div css={yearsCss}>
          <SelectOptions options={months} onSelect={selectMonth} />
        </div>
      )}
      {step === 'day' && (
        <StyledCalendar theme={{ ...colors }}>
          <div className="calendar_header">
            <button onClick={() => goBack()}>
              <BnBack />
            </button>
            {dayjs().month(selectedMonth.month).format('MMMM')}
            <button onClick={() => goForward()}>
              <BnForward />
            </button>
          </div>
          <div className="calendar_body">
            <table>
              <thead>
                <tr>
                  {weekDays.map((weekDay: string, key: number) => (
                    <th key={key}>{weekDay}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {weeksAndDays?.map((week: WeekDay[], i: number) => (
                  <tr key={i}>
                    {week.map((day: WeekDay, a: number) => (
                      <td key={a}>
                        <div
                          className={cx({
                            disabledDay: day.isDisabled,
                            notCurrentMonth: !day.isCurrentMonth,
                            selected:
                              day.date === selectedDay.format('YYYY-MM-DD'),
                            today: day.date === dayjs().format('YYYY-MM-DD'),
                          })}
                          onMouseEnter={() =>
                            !day.isDisabled &&
                            setHoverPlaceholder(
                              dayjs(day.date)
                                .set('hour', selectedDay.get('hour'))
                                .set('minute', selectedDay.get('minute'))
                                .format(getValueFormat())
                            )
                          }
                          onMouseOut={() => setHoverPlaceholder(undefined)}
                          onClick={() => {
                            if (!day.isDisabled) {
                              setInputValue(
                                dayjs(day.date)
                                  .set('hour', selectedDay.get('hour'))
                                  .set('minute', selectedDay.get('minute'))
                                  .format(getValueFormat())
                              );
                              if (onChange) {
                                onChange(
                                  dayjs(day.date, 'YYYY-MM-DD')
                                    .set('hour', selectedDay.get('hour'))
                                    .set('minute', selectedDay.get('minute'))
                                );
                              }
                              setSelectedDay(dayjs(day.date));
                              // selectedDay.set(
                              //   'date',
                              //   dayjs(day.date, 'YYYY-MM-DD').get('date')
                              // )
                              //   );
                              if (!day.isCurrentMonth) {
                                setSelectedMonth({
                                  month: dayjs(day.date).month(),
                                  year: dayjs(day.date).year(),
                                });
                              }
                              setIsOptionsOpen(false);
                            }
                          }}
                        >
                          {dayjs(day.date).format('D')}
                        </div>
                      </td>
                    ))}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </StyledCalendar>
      )}
    </Fragment>
  );
};
