import * as formatting from '@transferwise/formatting';
import { shallow } from 'enzyme';

import * as dateUtils from '../../../common/dateUtils';
import TableLink from '../../tableLink';

import DayCalendarTable from '.';

const locale = 'en-GB';
jest.mock('react-intl', () => ({
  injectIntl: (Component) =>
    function (props) {
      return <Component {...props} intl={{ locale }} />;
    },
  defineMessages: (translations) => translations,
}));

jest.mock('@transferwise/formatting', () => ({
  formatDate: jest.fn().mockReturnValue('XXXX'),
}));

jest.mock('../../../common/dateUtils', () => ({
  getDayNames: () => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
  isWithinRange: jest.fn().mockReturnValue(true),
}));

jest.mock('../../getStartOfDay', () => ({
  getStartOfDay: (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate()),
}));

describe('DayCalendarTable', () => {
  let component;
  let props;

  beforeEach(() => {
    props = {
      viewMonth: 11,
      viewYear: 2018,
      onSelect: jest.fn(),
    };
    component = shallow(<DayCalendarTable {...props} />).dive();
  });

  it('shows weekday names in table header', () => {
    const ths = component.find('thead th');
    expect(ths).toHaveLength(7);
    expect(ths.at(0).text()).toContain('Mon');
    expect(ths.at(6).text()).toContain('Sun');
  });

  it('shows all days of month (2018 December)', () => {
    expect(component.find('tbody tr')).toHaveLength(6);
    expect(component.find('tbody td')).toHaveLength(42);
    expect(component.find(TableLink)).toHaveLength(31);
  });

  it('shows empty items before first day of month (Sat, 1st December 2018)', () => {
    expect(getTableDataAt(0).children()).toHaveLength(0);
    expect(getTableDataAt(4).children()).toHaveLength(0);
    expect(getTableDataAt(5).children()).toHaveLength(1);
    expect(getTableDataAt(6).children()).toHaveLength(1);
  });

  it('display empty cells after the last day (Mon, 31st 2018 December)', () => {
    expect(getTableDataAt(35).children()).toHaveLength(1);
    expect(getTableDataAt(36).children()).toHaveLength(0);
    expect(getTableDataAt(37).children()).toHaveLength(0);
  });

  it('passes day value and type to TableLink', () => {
    expect(getTableLinkAt(0).prop('item')).toBe(1);
    expect(getTableLinkAt(0).prop('type')).toBe('day');
  });

  it('shows formatted days', () => {
    expect(getTableLinkAt(0).prop('title')).toBe('XXXX');
    expect(formatting.formatDate).toHaveBeenCalledWith(new Date(2018, 11, 1), locale, {
      day: 'numeric',
    });
  });

  it('shows full date as link title', () => {
    expect(getTableLinkAt(0).prop('longTitle')).toBe('XXXX');
    expect(formatting.formatDate).toHaveBeenCalledWith(new Date(2018, 11, 1), locale);
  });

  it('show selectedDate as active', () => {
    component.setProps({ selectedDate: new Date(2018, 11, 27) });
    expect(component.find(TableLink).find({ active: true }).prop('item')).toBe(27);
  });

  it('sets property "disabled" for table links (calls isWithinRange)', () => {
    const selectedDate = new Date(2018, 11, 26);
    const min = new Date(2018, 11, 26);
    const max = new Date(2018, 11, 27);
    component.setProps({ selectedDate, min, max });
    expect(dateUtils.isWithinRange).toHaveBeenCalledWith(selectedDate, min, max);
    expect(getTableLinkAt(0).prop('disabled')).toBe(false);
  });

  it('highlights today', () => {
    const today = new Date();
    component.setProps({
      selectedDate: today,
      viewMonth: today.getMonth(),
      viewYear: today.getFullYear(),
    });
    expect(component.find(TableLink).find({ today: true }).prop('item')).toBe(today.getDate());
  });

  it('passes selectDay to TableLink', () => {
    expect(getTableLinkAt(0).prop('onClick')).toBe(component.instance().selectDay);
  });

  it('calls onSelect when day gets selected', () => {
    component.instance().selectDay(1);
    expect(props.onSelect).toHaveBeenCalledWith(new Date(2018, 11, 1));
  });

  it('sets autofocus to true when 5 is the selected day', () => {
    component.setProps({ selectedDate: new Date(2018, 11, 5) });
    expect(getTableLinkAt(4).prop('autofocus')).toBe(true);
  });

  it('does not set autofocus to true when 5 is the selected day but not the right month', () => {
    component.setProps({ selectedDate: new Date(2018, 10, 5) });
    expect(getTableLinkAt(4).prop('autofocus')).toBe(false);
  });

  it('does not set autofocus to true when 5 is the selected day but not the right year', () => {
    component.setProps({ selectedDate: new Date(2017, 11, 5) });
    expect(getTableLinkAt(4).prop('autofocus')).toBe(false);
  });

  it('sets autofocus to true when selected date is null and current day is visible', () => {
    const today = new Date();
    component.setProps({
      selectedDate: today,
      viewMonth: today.getMonth(),
      viewYear: today.getFullYear(),
    });
    expect(component.find(TableLink).find({ today: true }).prop('autofocus')).toBe(true);
  });

  const getTableLinkAt = (i) => component.find(TableLink).at(i);
  const getTableDataAt = (i) => component.find('tbody td').at(i);
});
