import { Availability } from '@dvn/takvim/api/models';
import { Unavailability } from '@dvn/takvim/api/models/Unavailability';
import { doTimesIntersect, generateAvailabilities, generateSlotsForAvailabilities, generateSlotsForAvailability } from './utils';
describe('generateAvailabilities()', () => {
  it('should return a single availability', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T10:00:00Z',
        endDate: '2021-04-02T11:00:00Z',
        meetingDuration: 30,
        recurrence: 'single',
      })
    ];
    const generatedAvailabilities = generateAvailabilities(availabilities);
    expect(generatedAvailabilities).toEqual([
      Availability.decode({
        startDate: '2021-04-02T10:00:00Z',
        endDate: '2021-04-02T11:00:00Z',
        meetingDuration: 30,
        recurrence: 'single',
      })
    ]);
  });
  it('should return 9 availabilities for a weekly recurring availability for 2 months', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T10:00:00Z',
        endDate: '2021-04-02T11:00:00Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      })
    ];
    const startDate = new Date('2021-05-02T10:00:00Z');
    const generatedAvailabilities = generateAvailabilities(availabilities, 1, startDate);
    expect(generatedAvailabilities).toEqual([
      Availability.decode({
        startDate: '2021-04-02T10:00:00.000Z',
        endDate: '2021-04-02T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-04-09T10:00:00.000Z',
        endDate: '2021-04-09T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-04-16T10:00:00.000Z',
        endDate: '2021-04-16T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-04-23T10:00:00.000Z',
        endDate: '2021-04-23T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-04-30T10:00:00.000Z',
        endDate: '2021-04-30T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-05-07T10:00:00.000Z',
        endDate: '2021-05-07T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-05-14T10:00:00.000Z',
        endDate: '2021-05-14T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-05-21T10:00:00.000Z',
        endDate: '2021-05-21T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-05-28T10:00:00.000Z',
        endDate: '2021-05-28T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-06-04T10:00:00.000Z',
        endDate: '2021-06-04T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-06-11T10:00:00.000Z',
        endDate: '2021-06-11T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-06-18T10:00:00.000Z',
        endDate: '2021-06-18T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
      Availability.decode({
        startDate: '2021-06-25T10:00:00.000Z',
        endDate: '2021-06-25T11:00:00.000Z',
        meetingDuration: 30,
        recurrence: 'weekly',
      }),
    ]);
  });
});
describe('generateSlotsForAvailability()', () => {
  it('should return two slots that fit the time exactly', () => {
    const availability = Availability.decode({
      startDate: '2021-04-02T10:00:00Z',
      endDate: '2021-04-02T11:00:00Z',
      meetingDuration: 30,
      recurrence: 'single',
    });
    const slots = generateSlotsForAvailability(availability);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T10:00:01.000Z'),
        end: new Date('2021-04-02T10:30:00.000Z'),
      },
      {
        start: new Date('2021-04-02T10:30:01.000Z'),
        end: new Date('2021-04-02T11:00:00.000Z'),
      },
    ]);
  });
  it('should return two slots only because the third slot duration does not fit the remaining time', () => {
    const availability = Availability.decode({
      startDate: '2021-04-02T10:00:00Z',
      endDate: '2021-04-02T11:30:00Z',
      meetingDuration: 30,
      breakDuration: 15,
      recurrence: 'single',
    });
    const slots = generateSlotsForAvailability(availability);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T10:00:01.000Z'),
        end: new Date('2021-04-02T10:30:00.000Z'),
      },
      {
        start: new Date('2021-04-02T10:45:01.000Z'),
        end: new Date('2021-04-02T11:15:00.000Z'),
      },
    ]);
  });
});
describe('generateSlotsForAvailabilities()', () => {
  it('should remove the second slot when the start time intersects but the end time does not', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T08:00:00Z',
        endDate: '2021-04-02T12:00:00Z',
        meetingDuration: 60,
        recurrence: 'single',
      })
    ];
    const unavailabilitiesOfOtherUser = [
      Unavailability.decode({
        startDate: new Date('2021-04-02T09:00:00Z'),
        endDate: new Date('2021-04-02T09:30:00Z'),
      }),
    ];
    const slots = generateSlotsForAvailabilities(availabilities, [], unavailabilitiesOfOtherUser);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T08:00:01.000Z'),
        end: new Date('2021-04-02T09:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T10:00:01.000Z'),
        end: new Date('2021-04-02T11:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T11:00:01.000Z'),
        end: new Date('2021-04-02T12:00:00.000Z'),
      },
    ]);
  });
  it('should remove slots before 9', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T08:00:00Z',
        endDate: '2021-04-02T12:00:00Z',
        meetingDuration: 60,
        recurrence: 'single',
      })
    ];
    const unavailabilitiesOfOtherUser = [
      Unavailability.decode({
        startDate: new Date('2021-04-02T07:00:00Z'),
        endDate: new Date('2021-04-02T09:00:00Z'),
      }),
    ];
    const slots = generateSlotsForAvailabilities(availabilities, [], unavailabilitiesOfOtherUser);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T09:00:01.000Z'),
        end: new Date('2021-04-02T10:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T10:00:01.000Z'),
        end: new Date('2021-04-02T11:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T11:00:01.000Z'),
        end: new Date('2021-04-02T12:00:00.000Z'),
      },
    ]);
  });
  it('should remove slots between 12 to 14', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T09:00:00Z',
        endDate: '2021-04-02T16:00:00Z',
        meetingDuration: 60,
        recurrence: 'single',
      })
    ];
    const unavailabilitiesOfOtherUser = [
      Unavailability.decode({
        startDate: new Date('2021-04-02T12:00:00Z'),
        endDate: new Date('2021-04-02T14:00:00Z'),
      }),
    ];
    const slots = generateSlotsForAvailabilities(availabilities, [], unavailabilitiesOfOtherUser);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T09:00:01.000Z'),
        end: new Date('2021-04-02T10:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T10:00:01.000Z'),
        end: new Date('2021-04-02T11:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T11:00:01.000Z'),
        end: new Date('2021-04-02T12:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T14:00:01.000Z'),
        end: new Date('2021-04-02T15:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T15:00:01.000Z'),
        end: new Date('2021-04-02T16:00:00.000Z'),
      },
    ]);
  });
  it('should remove slots after 18', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T15:00:00Z',
        endDate: '2021-04-02T20:00:00Z',
        meetingDuration: 45,
        recurrence: 'single',
      })
    ];
    const unavailabilitiesOfOtherUser = [
      Unavailability.decode({
        startDate: new Date('2021-04-02T18:00:00Z'),
        endDate: new Date('2021-04-02T22:00:00Z'),
      }),
    ];
    const slots = generateSlotsForAvailabilities(availabilities, [], unavailabilitiesOfOtherUser);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T15:00:01.000Z'),
        end: new Date('2021-04-02T15:45:00.000Z'),
      },
      {
        start: new Date('2021-04-02T15:45:01.000Z'),
        end: new Date('2021-04-02T16:30:00.000Z'),
      },
      {
        start: new Date('2021-04-02T16:30:01.000Z'),
        end: new Date('2021-04-02T17:15:00.000Z'),
      },
      {
        start: new Date('2021-04-02T17:15:01.000Z'),
        end: new Date('2021-04-02T18:00:00.000Z'),
      },
    ]);
  });
  it('should remove slots before 9, between 12-13 and after 18', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T08:00:00Z',
        endDate: '2021-04-02T20:00:00Z',
        meetingDuration: 75,
        breakDuration: 15,
        recurrence: 'single',
      })
    ];
    const unavailabilitiesOfOtherUser = [
      Unavailability.decode({
        startDate: new Date('2021-04-02T07:00:00Z'),
        endDate: new Date('2021-04-02T09:00:00Z'),
      }),
      Unavailability.decode({
        startDate: new Date('2021-04-02T12:00:00Z'),
        endDate: new Date('2021-04-02T13:00:00Z'),
      }),
      Unavailability.decode({
        startDate: new Date('2021-04-02T18:00:00Z'),
        endDate: new Date('2021-04-02T20:00:00Z'),
      }),
    ];
    const slots = generateSlotsForAvailabilities(availabilities, [], unavailabilitiesOfOtherUser);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T09:30:01.000Z'),
        end: new Date('2021-04-02T10:45:00.000Z'),
      },
      {
        start: new Date('2021-04-02T14:00:01.000Z'),
        end: new Date('2021-04-02T15:15:00.000Z'),
      },
      {
        start: new Date('2021-04-02T15:30:01.000Z'),
        end: new Date('2021-04-02T16:45:00.000Z'),
      },
    ]);
  });
  it('should add sessionUserConflict to the slots before 9', () => {
    const availabilities = [
      Availability.decode({
        startDate: '2021-04-02T08:00:00Z',
        endDate: '2021-04-02T12:00:00Z',
        meetingDuration: 60,
        recurrence: 'single',
      })
    ];
    const unavailabilitiesOfSessionUser = [
      Unavailability.decode({
        startDate: new Date('2021-04-02T07:00:00Z'),
        endDate: new Date('2021-04-02T09:00:00Z'),
        reason: {
          source: 'google-calendar',
          name: 'Family Breakfast'
        }
      }),
    ];
    const slots = generateSlotsForAvailabilities(availabilities, unavailabilitiesOfSessionUser, []);
    expect(slots).toEqual([
      {
        start: new Date('2021-04-02T08:00:01.000Z'),
        end: new Date('2021-04-02T09:00:00.000Z'),
        sessionUserConflict: {
          source: 'google-calendar',
          name: 'Family Breakfast'
        }
      },
      {
        start: new Date('2021-04-02T09:00:01.000Z'),
        end: new Date('2021-04-02T10:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T10:00:01.000Z'),
        end: new Date('2021-04-02T11:00:00.000Z'),
      },
      {
        start: new Date('2021-04-02T11:00:01.000Z'),
        end: new Date('2021-04-02T12:00:00.000Z'),
      },
    ]);
  });
});
describe('doTimesIntersect()', () => {
  it('should return true if first time starts before but ends in the middle of second', () => {
    expect(doTimesIntersect(new Date('2021-04-02T10:00:00.000Z'), new Date('2021-04-02T11:00:00.000Z'), new Date('2021-04-02T10:30:00.000Z'), new Date('2021-04-02T11:30:00.000Z')));
  });
  it('should return true if second time starts before but ends in the middle of first', () => {
    expect(doTimesIntersect(new Date('2021-04-02T10:30:00.000Z'), new Date('2021-04-02T11:30:00.000Z'), new Date('2021-04-02T10:00:00.000Z'), new Date('2021-04-02T11:00:00.000Z')));
  });
  it('should return true if second time starts before and ends after first', () => {
    expect(doTimesIntersect(new Date('2021-04-02T10:30:00.000Z'), new Date('2021-04-02T11:30:00.000Z'), new Date('2021-04-02T10:00:00.000Z'), new Date('2021-04-02T12:00:00.000Z')));
  });
  it('should return true if first time starts before and ends after second', () => {
    expect(doTimesIntersect(new Date('2021-04-02T10:00:00.000Z'), new Date('2021-04-02T12:00:00.000Z'), new Date('2021-04-02T10:30:00.000Z'), new Date('2021-04-02T11:30:00.000Z')));
  });
});
