import React from 'react';
import { waitFor, fireEvent } from '@testing-library/react';
import renderWithTheme from '../../../../testUtils/renderWithTheme';

import Calendar from '../index';

import {
  FirstRowOfWeekCalendar,
  DayComponent,
  WeekComponent,
  SelectMonthAndYear,
} from '../WeekCalendar';
import { DayState, WeekState } from '../StyledCalendar';

describe('SelectMonthAndYear', () => {
  it('renders correctly', () => {
    const props = {
      year: 2021,
      month: 11,
      onChangeMonth: jest.fn(),
      onChangeYear: jest.fn(),
    };
    const { getByTestId } = renderWithTheme(<SelectMonthAndYear {...props} />);

    const monthSelect = getByTestId('month-select');
    expect(monthSelect).toSelectItem('Dec');
    const yearSelect = getByTestId('year-select');
    expect(yearSelect).toSelectItem('2021');
  });
});

describe('FirstRowOfWeekCalendar', () => {
  it('renders correctly', () => {
    const { getByText } = renderWithTheme(<FirstRowOfWeekCalendar />);
    expect(getByText('Week')).toBeInTheDocument();
    // shows days of week
    expect(getByText('Su')).toBeInTheDocument();
    expect(getByText('Mo')).toBeInTheDocument();
    expect(getByText('Tu')).toBeInTheDocument();
    expect(getByText('We')).toBeInTheDocument();
    expect(getByText('Th')).toBeInTheDocument();
    expect(getByText('Fr')).toBeInTheDocument();
    expect(getByText('Sa')).toBeInTheDocument();
  });
});

describe('DayComponent', () => {
  it('renders correctly', () => {
    const props = {
      day: 1,
      dateState: 'enabled' as DayState,
      onMouseOver: jest.fn(),
    };
    const { getByText } = renderWithTheme(<DayComponent {...props} />);
    expect(getByText('1')).toBeInTheDocument();
  });
});

describe('WeekComponent', () => {
  it('renders correctly', () => {
    const props = {
      showedWeekNumber: 34,
      firstDateState: 'enabled' as WeekState,
      onMouseOver: jest.fn(),
    };
    const { getByText } = renderWithTheme(<WeekComponent {...props} />);
    expect(getByText('34')).toBeInTheDocument();
  });
});

describe('Week Calendar', () => {
  it('renders correctly', async () => {
    const { getByText, getByTestId } = renderWithTheme(
      <Calendar.Week selectedFirstDateOfWeek={new Date(2021, 1, 19)} />
    );

    await waitFor(() => {
      // shows month in select
      const monthSelect = getByTestId('month-select');
      expect(monthSelect).toSelectItem('Feb');
      // shows year in select
      const yearSelect = getByTestId('year-select');
      expect(yearSelect).toSelectItem('2021');
      // shows days of week
      expect(getByText('Su')).toBeInTheDocument();
      expect(getByText('Mo')).toBeInTheDocument();
      expect(getByText('Tu')).toBeInTheDocument();
      expect(getByText('We')).toBeInTheDocument();
      expect(getByText('Th')).toBeInTheDocument();
      expect(getByText('Fr')).toBeInTheDocument();
      expect(getByText('Sa')).toBeInTheDocument();
      // shows selected date
      expect(getByText('19')).toBeInTheDocument();
      // shows disabled date
      expect(getByText('31')).toBeInTheDocument();
    });
  });
});

describe('interaction', () => {
  it('allows to select month and year', async () => {
    const { getByText, getByTestId } = renderWithTheme(
      <Calendar.Week selectedFirstDateOfWeek={new Date(2021, 1, 19)} />
    );

    const monthSelect = getByTestId('month-select');
    fireEvent.click(monthSelect);
    fireEvent.click(getByText('Mar'));

    await waitFor(() => {
      expect(monthSelect).toSelectItem('Mar');
    });

    const yearSelect = getByTestId('year-select');
    fireEvent.click(yearSelect);
    fireEvent.click(getByText('2025'));

    await waitFor(() => {
      expect(yearSelect).toSelectItem('2025');
    });
  });

  it('allows to select a new start of week date', async () => {
    const onSelectFirstDateOfWeek = jest.fn();
    const { getByText, getByTestId } = renderWithTheme(
      <Calendar.Week
        selectedFirstDateOfWeek={new Date(2021, 1, 19)}
        onSelectFirstDateOfWeek={onSelectFirstDateOfWeek}
      />
    );

    const monthSelect = getByTestId('month-select');
    fireEvent.click(monthSelect);
    fireEvent.click(getByText('Mar'));
    const yearSelect = getByTestId('year-select');
    fireEvent.click(yearSelect);
    fireEvent.click(getByText('2025'));
    fireEvent.click(getByText('29'));

    await waitFor(() => {
      expect(onSelectFirstDateOfWeek).toHaveBeenCalledTimes(1);
      expect(onSelectFirstDateOfWeek).toHaveBeenCalledWith(
        new Date(2025, 2, 23)
      );
    });
  });
});
