import {
  getMonthMatrix,
  generateMonthOptions,
  generateYearOptions,
  getSingleCalendarDayState,
  getDoubleCalendarDayState,
  getMonthPickerOptions,
  getWeekCalendarDayState,
  getWeekCalendarState,
} from '../utils';

describe('getMonthMatrix', () => {
  it('returns correct month matrix', () => {
    const month = 4; // May
    const year = 2021; // 2021
    const expectedMatrix = [
      [
        { date: new Date(year, month - 1, 25), disabled: true },
        { date: new Date(year, month - 1, 26), disabled: true },
        { date: new Date(year, month - 1, 27), disabled: true },
        { date: new Date(year, month - 1, 28), disabled: true },
        { date: new Date(year, month - 1, 29), disabled: true },
        { date: new Date(year, month - 1, 30), disabled: true },
        { date: new Date(year, month, 1), disabled: false },
      ],
      [
        { date: new Date(year, month, 2), disabled: false },
        { date: new Date(year, month, 3), disabled: false },
        { date: new Date(year, month, 4), disabled: false },
        { date: new Date(year, month, 5), disabled: false },
        { date: new Date(year, month, 6), disabled: false },
        { date: new Date(year, month, 7), disabled: false },
        { date: new Date(year, month, 8), disabled: false },
      ],
      [
        { date: new Date(year, month, 9), disabled: false },
        { date: new Date(year, month, 10), disabled: false },
        { date: new Date(year, month, 11), disabled: false },
        { date: new Date(year, month, 12), disabled: false },
        { date: new Date(year, month, 13), disabled: false },
        { date: new Date(year, month, 14), disabled: false },
        { date: new Date(year, month, 15), disabled: false },
      ],
      [
        { date: new Date(year, month, 16), disabled: false },
        { date: new Date(year, month, 17), disabled: false },
        { date: new Date(year, month, 18), disabled: false },
        { date: new Date(year, month, 19), disabled: false },
        { date: new Date(year, month, 20), disabled: false },
        { date: new Date(year, month, 21), disabled: false },
        { date: new Date(year, month, 22), disabled: false },
      ],
      [
        { date: new Date(year, month, 23), disabled: false },
        { date: new Date(year, month, 24), disabled: false },
        { date: new Date(year, month, 25), disabled: false },
        { date: new Date(year, month, 26), disabled: false },
        { date: new Date(year, month, 27), disabled: false },
        { date: new Date(year, month, 28), disabled: false },
        { date: new Date(year, month, 29), disabled: false },
      ],
      [
        { date: new Date(year, month, 30), disabled: false },
        { date: new Date(year, month, 31), disabled: false },
        { date: new Date(year, month + 1, 1), disabled: true },
        { date: new Date(year, month + 1, 2), disabled: true },
        { date: new Date(year, month + 1, 3), disabled: true },
        { date: new Date(year, month + 1, 4), disabled: true },
        { date: new Date(year, month + 1, 5), disabled: true },
      ],
    ];

    expect(getMonthMatrix({ month, year })).toEqual(expectedMatrix);
  });

  it('returns correct month matrix with min/max dates', () => {
    const month = 4; // May
    const year = 2021; // 2021
    const minDate = new Date(year, month, 2);
    const maxDate = new Date(year, month, 29);
    const expectedMatrix = [
      [
        { date: new Date(year, month - 1, 25), disabled: true },
        { date: new Date(year, month - 1, 26), disabled: true },
        { date: new Date(year, month - 1, 27), disabled: true },
        { date: new Date(year, month - 1, 28), disabled: true },
        { date: new Date(year, month - 1, 29), disabled: true },
        { date: new Date(year, month - 1, 30), disabled: true },
        { date: new Date(year, month, 1), disabled: true },
      ],
      [
        { date: new Date(year, month, 2), disabled: false },
        { date: new Date(year, month, 3), disabled: false },
        { date: new Date(year, month, 4), disabled: false },
        { date: new Date(year, month, 5), disabled: false },
        { date: new Date(year, month, 6), disabled: false },
        { date: new Date(year, month, 7), disabled: false },
        { date: new Date(year, month, 8), disabled: false },
      ],
      [
        { date: new Date(year, month, 9), disabled: false },
        { date: new Date(year, month, 10), disabled: false },
        { date: new Date(year, month, 11), disabled: false },
        { date: new Date(year, month, 12), disabled: false },
        { date: new Date(year, month, 13), disabled: false },
        { date: new Date(year, month, 14), disabled: false },
        { date: new Date(year, month, 15), disabled: false },
      ],
      [
        { date: new Date(year, month, 16), disabled: false },
        { date: new Date(year, month, 17), disabled: false },
        { date: new Date(year, month, 18), disabled: false },
        { date: new Date(year, month, 19), disabled: false },
        { date: new Date(year, month, 20), disabled: false },
        { date: new Date(year, month, 21), disabled: false },
        { date: new Date(year, month, 22), disabled: false },
      ],
      [
        { date: new Date(year, month, 23), disabled: false },
        { date: new Date(year, month, 24), disabled: false },
        { date: new Date(year, month, 25), disabled: false },
        { date: new Date(year, month, 26), disabled: false },
        { date: new Date(year, month, 27), disabled: false },
        { date: new Date(year, month, 28), disabled: false },
        { date: new Date(year, month, 29), disabled: false },
      ],
      [
        { date: new Date(year, month, 30), disabled: true },
        { date: new Date(year, month, 31), disabled: true },
        { date: new Date(year, month + 1, 1), disabled: true },
        { date: new Date(year, month + 1, 2), disabled: true },
        { date: new Date(year, month + 1, 3), disabled: true },
        { date: new Date(year, month + 1, 4), disabled: true },
        { date: new Date(year, month + 1, 5), disabled: true },
      ],
    ];

    expect(getMonthMatrix({ month, year, minDate, maxDate })).toEqual(
      expectedMatrix
    );
  });
});

describe('generateYearOptions', () => {
  it('returns correct year options', () => {
    const minDate = new Date(2021, 5, 1);
    const maxDate = new Date(2025, 1, 1);
    const expectedYears = [
      { value: 2021, text: '2021' },
      { value: 2022, text: '2022' },
      { value: 2023, text: '2023' },
      { value: 2024, text: '2024' },
      { value: 2025, text: '2025' },
    ];

    expect(generateYearOptions({ minDate, maxDate })).toEqual(expectedYears);
  });
});

describe('generateMonthOptions', () => {
  const minDate = new Date(2021, 5, 1);
  const maxDate = new Date(2025, 1, 1);

  it('returns all months', () => {
    const expectMonths = [
      { value: 0, text: 'Jan' },
      { value: 1, text: 'Feb' },
      { value: 2, text: 'Mar' },
      { value: 3, text: 'Apr' },
      { value: 4, text: 'May' },
      { value: 5, text: 'Jun' },
      { value: 6, text: 'Jul' },
      { value: 7, text: 'Aug' },
      { value: 8, text: 'Sep' },
      { value: 9, text: 'Oct' },
      { value: 10, text: 'Nov' },
      { value: 11, text: 'Dec' },
    ];

    expect(generateMonthOptions({ minDate, maxDate, year: 2022 })).toEqual(
      expectMonths
    );
  });

  it('disabled months prior to minDate', () => {
    const expectMonths = [
      { value: 0, text: 'Jan', disabled: true },
      { value: 1, text: 'Feb', disabled: true },
      { value: 2, text: 'Mar', disabled: true },
      { value: 3, text: 'Apr', disabled: true },
      { value: 4, text: 'May', disabled: true },
      { value: 5, text: 'Jun' },
      { value: 6, text: 'Jul' },
      { value: 7, text: 'Aug' },
      { value: 8, text: 'Sep' },
      { value: 9, text: 'Oct' },
      { value: 10, text: 'Nov' },
      { value: 11, text: 'Dec' },
    ];

    expect(generateMonthOptions({ minDate, maxDate, year: 2021 })).toEqual(
      expectMonths
    );
  });

  it('disabled months following maxDate', () => {
    const expectMonths = [
      { value: 0, text: 'Jan' },
      { value: 1, text: 'Feb' },
      { value: 2, text: 'Mar', disabled: true },
      { value: 3, text: 'Apr', disabled: true },
      { value: 4, text: 'May', disabled: true },
      { value: 5, text: 'Jun', disabled: true },
      { value: 6, text: 'Jul', disabled: true },
      { value: 7, text: 'Aug', disabled: true },
      { value: 8, text: 'Sep', disabled: true },
      { value: 9, text: 'Oct', disabled: true },
      { value: 10, text: 'Nov', disabled: true },
      { value: 11, text: 'Dec', disabled: true },
    ];

    expect(generateMonthOptions({ minDate, maxDate, year: 2026 })).toEqual(
      expectMonths
    );
  });
});

describe('getSingleCalendarDayState', () => {
  it.each`
    dateOfWeek                                          | selectedDate             | state
    ${{ date: new Date(), disabled: true }}             | ${undefined}             | ${'disabled'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${new Date(2021, 1, 19)} | ${'selected'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${undefined}             | ${'enabled'}
    ${{ date: new Date(), disabled: false }}            | ${undefined}             | ${'today'}
  `('returns $state', ({ dateOfWeek, selectedDate, state }) => {
    expect(getSingleCalendarDayState({ dateOfWeek, selectedDate })).toEqual(
      state
    );
  });
});

describe('getWeekCalendarState', () => {
  it.each`
    dateOfWeek                                          | selectedDate             | state
    ${{ date: new Date(), disabled: true }}             | ${undefined}             | ${'disabled'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${new Date(2021, 1, 19)} | ${'inHoveringWeek'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${undefined}             | ${'inHoveringWeek'}
    ${{ date: new Date(), disabled: false }}            | ${undefined}             | ${'enabled'}
  `(
    'returns $state when dateOfWeek is $dateOfWeek and selectedDate is $selectedDate',
    ({ dateOfWeek, selectedDate, state }) => {
      const tempDate = new Date(2021, 1, 19);
      expect(
        getWeekCalendarState({ dateOfWeek, selectedDate, tempDate })
      ).toEqual(state);
    }
  );

  it.each`
    dateOfWeek                                          | tempDate                 | state
    ${{ date: new Date(), disabled: true }}             | ${undefined}             | ${'disabled'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${new Date(2021, 1, 19)} | ${'inHoveringWeek'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${undefined}             | ${'enabled'}
    ${{ date: new Date(), disabled: false }}            | ${undefined}             | ${'enabled'}
  `(
    'returns $state when when dateOfWeek is $dateOfWeek and tempDate is $tempDate',
    ({ dateOfWeek, tempDate, state }) => {
      const selectedDate = new Date(2021, 1, 19);
      expect(
        getWeekCalendarState({ dateOfWeek, selectedDate, tempDate })
      ).toEqual(state);
    }
  );
});

describe('getWeekCalendarDayState', () => {
  it.each`
    dateOfWeek                                          | selectedDate             | state
    ${{ date: new Date(), disabled: true }}             | ${undefined}             | ${'today'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${new Date(2021, 1, 19)} | ${'selectedWeekDate'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${undefined}             | ${'inHoveringWeekDate'}
    ${{ date: new Date(), disabled: false }}            | ${undefined}             | ${'today'}
  `(
    'returns $state when when dateOfWeek is $dateOfWeek and selectedDate is $selectedDate',
    ({ dateOfWeek, selectedDate, state }) => {
      const tempDate = new Date(2021, 1, 19);
      expect(
        getWeekCalendarDayState({ dateOfWeek, selectedDate, tempDate })
      ).toEqual(state);
    }
  );

  it.each`
    dateOfWeek                                          | tempDate                 | state
    ${{ date: new Date(), disabled: true }}             | ${undefined}             | ${'today'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${new Date(2021, 1, 19)} | ${'selectedWeekDate'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${undefined}             | ${'selectedWeekDate'}
    ${{ date: new Date(), disabled: false }}            | ${undefined}             | ${'today'}
  `(
    'returns $state when when dateOfWeek is $dateOfWeek and tempDate is $tempDate',
    ({ dateOfWeek, tempDate, state }) => {
      const selectedDate = new Date(2021, 1, 19);
      expect(
        getWeekCalendarDayState({ dateOfWeek, selectedDate, tempDate })
      ).toEqual(state);
    }
  );
});

describe('getDoubleCalendarDayState', () => {
  it.each`
    dateOfWeek                                          | isSettingStartDate | isSettingEndDate | dateClickCount | startDate                | endDate                  | tempDate                 | state
    ${{ date: new Date(), disabled: true }}             | ${false}           | ${false}         | ${0}           | ${undefined}             | ${undefined}             | ${undefined}             | ${'disabled'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${false}           | ${true}          | ${1}           | ${new Date(2021, 4, 12)} | ${undefined}             | ${undefined}             | ${'disabled'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${true}            | ${false}         | ${1}           | ${undefined}             | ${new Date(2021, 1, 1)}  | ${undefined}             | ${'disabled'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${false}           | ${false}         | ${0}           | ${new Date(2021, 1, 19)} | ${new Date(2021, 1, 19)} | ${undefined}             | ${'selectedRangeDate'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${false}           | ${false}         | ${0}           | ${new Date(2021, 1, 19)} | ${undefined}             | ${undefined}             | ${'selectedStartDate'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${false}           | ${false}         | ${0}           | ${undefined}             | ${new Date(2021, 1, 19)} | ${undefined}             | ${'selectedEndDate'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${true}            | ${false}         | ${0}           | ${undefined}             | ${new Date(2021, 1, 20)} | ${new Date(2021, 1, 18)} | ${'inHoveringRange'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${false}           | ${true}          | ${0}           | ${new Date(2021, 1, 18)} | ${undefined}             | ${new Date(2021, 1, 20)} | ${'inHoveringRange'}
    ${{ date: new Date(), disabled: false }}            | ${false}           | ${false}         | ${0}           | ${undefined}             | ${undefined}             | ${undefined}             | ${'today'}
    ${{ date: new Date(2021, 1, 19), disabled: false }} | ${false}           | ${false}         | ${0}           | ${undefined}             | ${undefined}             | ${undefined}             | ${'enabled'}
  `(
    'retunrs $state',
    ({
      dateOfWeek,
      isSettingStartDate,
      isSettingEndDate,
      dateClickCount,
      startDate,
      endDate,
      tempDate,
      state,
    }) => {
      expect(
        getDoubleCalendarDayState({
          dateOfWeek,
          isSettingStartDate,
          isSettingEndDate,
          dateClickCount,
          startDate,
          endDate,
          tempDate,
        })
      ).toEqual(state);
    }
  );
});

describe('getMonthPickerOptions', () => {
  it('returns correct month options', () => {
    const minDate = new Date(2021, 2);
    const maxDate = new Date(2021, 5);
    const year = 2021;
    const expectedResult = [
      {
        text: 'Jan',
        date: new Date(2020, 12),
        disabled: true,
      },
      {
        text: 'Feb',
        date: new Date(year, 1),
        disabled: true,
      },
      {
        text: 'Mar',
        date: new Date(year, 2),
        disabled: false,
      },
      {
        text: 'Apr',
        date: new Date(year, 3),
        disabled: false,
      },
      {
        text: 'May',
        date: new Date(year, 4),
        disabled: false,
      },
      {
        text: 'Jun',
        date: new Date(year, 5),
        disabled: false,
      },
      {
        text: 'Jul',
        date: new Date(year, 6),
        disabled: true,
      },
      {
        text: 'Aug',
        date: new Date(year, 7),
        disabled: true,
      },
      {
        text: 'Sep',
        date: new Date(year, 8),
        disabled: true,
      },

      {
        text: 'Oct',
        date: new Date(year, 9),
        disabled: true,
      },
      {
        text: 'Nov',
        date: new Date(year, 10),
        disabled: true,
      },
      {
        text: 'Dec',
        date: new Date(year, 11),
        disabled: true,
      },
    ];

    expect(getMonthPickerOptions({ minDate, maxDate, year })).toEqual(
      expectedResult
    );
  });
});
