import { set } from 'date-fns'
import { TimeUtils } from './time.utils'

describe('Time Utils', () => {
	describe('parseFromString method', () => {
		it('should correctly parse time as string', () => {
			expect(TimeUtils.parseFromString('13:00')).toEqual({ hours: 13, minutes: 0 })
			expect(TimeUtils.parseFromString('10:45')).toEqual({ hours: 10, minutes: 45 })
			expect(TimeUtils.parseFromString('00:00')).toEqual({ hours: 0, minutes: 0 })
			expect(TimeUtils.parseFromString('23:59')).toEqual({ hours: 23, minutes: 59 })
		})

		it('should throw error if invalid time string is provided', () => {
			expect(() => TimeUtils.parseFromString('24:00')).toThrow(new Error('Invalid time string'))
			expect(() => TimeUtils.parseFromString('-1:30')).toThrow(new Error('Invalid time string'))
			expect(() => TimeUtils.parseFromString('12:60')).toThrow(new Error('Invalid time string'))
			expect(() => TimeUtils.parseFromString('12:-30')).toThrow(new Error('Invalid time string'))
		})
	})

	describe('formatAsString method', () => {
		it('should correctly format time as string', () => {
			expect(TimeUtils.formatAsString({ hours: 13, minutes: 0 })).toEqual('13:00')
			expect(TimeUtils.formatAsString({ hours: 10, minutes: 45 })).toEqual('10:45')
			expect(TimeUtils.formatAsString({ hours: 0, minutes: 0 })).toEqual('00:00')
			expect(TimeUtils.formatAsString({ hours: 23, minutes: 59 })).toEqual('23:59')
		})
	})

	describe('extractTimeFromDate method', () => {
		it('should correctly extract time from date', () => {
			expect(TimeUtils.extractTimeFromDate(set(new Date(), { hours: 13, minutes: 0 }))).toEqual({
				hours: 13,
				minutes: 0,
			})

			expect(TimeUtils.extractTimeFromDate(set(new Date(), { hours: 10, minutes: 45 }))).toEqual({
				hours: 10,
				minutes: 45,
			})

			expect(TimeUtils.extractTimeFromDate(set(new Date(), { hours: 0, minutes: 0 }))).toEqual({ hours: 0, minutes: 0 })

			expect(TimeUtils.extractTimeFromDate(set(new Date(), { hours: 23, minutes: 59 }))).toEqual({
				hours: 23,
				minutes: 59,
			})
		})
	})

	describe('isEqual method', () => {
		it('should correctly compare equal time', () => {
			// Before
			expect(TimeUtils.isEqual({ hours: 0, minutes: 0 }, { hours: 12, minutes: 0 })).toBe(false)
			// After
			expect(TimeUtils.isEqual({ hours: 4, minutes: 30 }, { hours: 3, minutes: 19 })).toBe(false)
			// Equal
			expect(TimeUtils.isEqual({ hours: 7, minutes: 45 }, { hours: 7, minutes: 45 })).toBe(true)
		})
	})

	describe('isBefore method', () => {
		it('should return true if left time comes before righ time and false otherwise', () => {
			// Before
			expect(TimeUtils.isBefore({ hours: 0, minutes: 0 }, { hours: 12, minutes: 0 })).toBe(true)
			// After
			expect(TimeUtils.isBefore({ hours: 4, minutes: 30 }, { hours: 3, minutes: 19 })).toBe(false)
			// Equal
			expect(TimeUtils.isBefore({ hours: 7, minutes: 45 }, { hours: 7, minutes: 45 })).toBe(false)
		})
	})

	describe('isAfter method', () => {
		it('should return true if left time after righ time and false otherwise', () => {
			// Before
			expect(TimeUtils.isAfter({ hours: 0, minutes: 0 }, { hours: 12, minutes: 0 })).toBe(false)
			// After
			expect(TimeUtils.isAfter({ hours: 4, minutes: 30 }, { hours: 3, minutes: 19 })).toBe(true)
			// Equal
			expect(TimeUtils.isAfter({ hours: 7, minutes: 45 }, { hours: 7, minutes: 45 })).toBe(false)
		})
	})

	describe('addMinutes method', () => {
		it('should add given number of minutes to time', () => {
			expect(TimeUtils.addMinutes({ hours: 0, minutes: 0 }, 30)).toEqual({ hours: 0, minutes: 30 })
			expect(TimeUtils.addMinutes({ hours: 8, minutes: 30 }, 130)).toEqual({ hours: 10, minutes: 40 })
		})
		it('should reset hours count from 00 if time exceeds 23 hours', () => {
			expect(TimeUtils.addMinutes({ hours: 23, minutes: 30 }, 50)).toEqual({ hours: 0, minutes: 20 })
		})
		it('should freeze time at 23:59 if preventOverflow is true and time exceeds 23 hours', () => {
			expect(TimeUtils.addMinutes({ hours: 23, minutes: 30 }, 50, { preventOverflow: true })).toEqual({
				hours: 23,
				minutes: 59,
			})
		})
	})

	describe('addHours method', () => {
		it('should add given number of hours to time', () => {
			expect(TimeUtils.addHours({ hours: 3, minutes: 0 }, 5)).toEqual({ hours: 8, minutes: 0 })
			expect(TimeUtils.addHours({ hours: 8, minutes: 30 }, 12)).toEqual({ hours: 20, minutes: 30 })
		})
		it('should reset hours count from 00 if time exceeds 23 hours', () => {
			expect(TimeUtils.addHours({ hours: 23, minutes: 30 }, 5)).toEqual({ hours: 4, minutes: 30 })
		})
		it('should freeze time at 23:59 if preventOverflow is true and time exceeds 23 hours', () => {
			expect(TimeUtils.addHours({ hours: 23, minutes: 30 }, 5, { preventOverflow: true })).toEqual({
				hours: 23,
				minutes: 59,
			})
		})
	})
})
