import {
  anneePrecedente,
  anneeSuivante,
  daysBetween,
  getAnnee,
  isAnnee,
  toCaminoDate,
  toCaminoAnnee,
  dateAddDays,
  dateAddMonths,
  dateValidate,
  setDayInMonth,
  dateFormat,
  isBefore,
  intervalleAnnees,
  caminoDateValidator,
  CaminoDate,
  getDay,
  dateTimeFormat,
} from './date'
import { test, expect } from 'vitest'

test('toCaminoDate', () => {
  expect(() => toCaminoDate('123123')).toThrowError()
  expect(() => toCaminoDate(new Date('plop'))).toThrowError()
  expect(() => toCaminoDate('2000-42-42')).toThrowError()
  expect(() => caminoDateValidator.parse('2000-42-42')).toThrowError()
})

test('dateFormat', () => {
  expect(dateFormat(toCaminoDate('2022-12-01'))).toBe('01-12-2022')
  expect(dateFormat(null)).toBe('')
  expect(dateFormat(undefined)).toBe('')
})
test('dateTimeFormat', () => {
  expect(dateTimeFormat(new Date('1995-12-17T03:24:00Z'))).toMatchInlineSnapshot(`"17/12/1995 04:24:00"`)
})

test('getAnnee', () => {
  expect(getAnnee(toCaminoDate('2022-12-01'))).toBe('2022')
  expect(getAnnee(toCaminoDate('1812-01-02'))).toBe('1812')
  expect(() => getAnnee(toCaminoDate('toto'))).toThrowErrorMatchingInlineSnapshot('[Error: Invalid date string: toto]')
  expect(() => getAnnee(toCaminoDate('12'))).toThrowErrorMatchingInlineSnapshot('[Error: Invalid date string: 12]')
  expect(() => getAnnee(toCaminoDate('20220'))).toThrowErrorMatchingInlineSnapshot('[Error: Invalid date string: 20220]')
})

test('isAnnee', () => {
  expect(isAnnee('2022')).toBe(true)
  expect(isAnnee('1812')).toBe(true)
  expect(isAnnee('toto')).toBe(false)
  expect(isAnnee('12')).toBe(false)
  expect(isAnnee('20220')).toBe(false)
})
test('getDay', () => {
  expect(getDay(toCaminoDate('2022-01-01'))).toBe(1)
  expect(getDay(toCaminoDate('1812-12-26'))).toBe(26)
  expect(getDay(toCaminoDate('2025-01-15'))).toBe(15)
  expect(getDay(toCaminoDate('2024-12-31'))).toBe(31)
})

test('toCaminoAnnee', () => {
  expect(toCaminoAnnee('2022')).toBe('2022')
  expect(toCaminoAnnee('1812')).toBe('1812')
  expect(toCaminoAnnee(2022)).toBe('2022')
  expect(toCaminoAnnee(1812)).toBe('1812')
  expect(() => toCaminoAnnee('toto')).toThrowErrorMatchingInlineSnapshot("[Error: l'année toto n'est pas une année valide]")
  expect(() => toCaminoAnnee('12')).toThrowErrorMatchingInlineSnapshot("[Error: l'année 12 n'est pas une année valide]")
  expect(() => toCaminoAnnee('20220')).toThrowErrorMatchingInlineSnapshot("[Error: l'année 20220 n'est pas une année valide]")
})

test('daysBetween', () => {
  expect(daysBetween(toCaminoDate('2020-06-02'), toCaminoDate('2020-06-10'))).toBe(8)
  expect(daysBetween(toCaminoDate('2020-01-02'), toCaminoDate('2020-01-31'))).toBe(29)
  // bisextile
  expect(daysBetween(toCaminoDate('2020-01-02'), toCaminoDate('2021-01-02'))).toBe(366)
  expect(daysBetween(toCaminoDate('2021-01-02'), toCaminoDate('2022-01-02'))).toBe(365)
  expect(daysBetween(toCaminoDate('2021-01-02'), toCaminoDate('2021-01-01'))).toBe(-1)

  expect(daysBetween(toCaminoDate('2012-09-14'), toCaminoDate('2013-05-13'))).toBe(241)
  expect(daysBetween(toCaminoDate('2012-09-14'), toCaminoDate('2013-01-14'))).toBe(122)
  expect(daysBetween(toCaminoDate('2013-01-14'), toCaminoDate('2013-05-13'))).toBe(119)
})
test('anneeSuivante', () => {
  expect(anneeSuivante(toCaminoAnnee('2022'))).toBe(toCaminoAnnee('2023'))
})
test('anneePrecedente', () => {
  expect(anneePrecedente(toCaminoAnnee('2022'))).toBe(toCaminoAnnee('2021'))
})
test('intervalleAnnees', () => {
  expect(intervalleAnnees(toCaminoAnnee('1997'), toCaminoAnnee('1999'))).toStrictEqual([toCaminoAnnee('1997'), toCaminoAnnee('1998'), toCaminoAnnee('1999')])
  expect(() => intervalleAnnees(toCaminoAnnee('1999'), toCaminoAnnee('1980'))).toThrowErrorMatchingInlineSnapshot(`[Error: L'année de départ 1999 doit être inférieure à l'année d'arrivée 1980]`)
})

test("retourne une erreur si aucune date n'est fournie", () => {
  let tested = dateValidate(null)

  expect(tested).toStrictEqual({ valid: false, error: 'Date manquante' })

  tested = dateValidate(undefined)

  expect(tested).toStrictEqual({ valid: false, error: 'Date manquante' })
})

test('retourne la date si elle est valide', () => {
  const res = dateValidate('1910-01-01')

  expect(res).toStrictEqual({ valid: true, date: toCaminoDate('1910-01-01') })
})

test.each(['1910-123123123-123123113', '2000-42-42'])('retourne une erreur la date est invalide', date => {
  const res = dateValidate(date)

  expect(res).toStrictEqual({ valid: false, error: 'Date invalide' })
})

test.each([
  ['2020-01-01', 1, '2020-01-02'],
  ['2020-01-01', 10, '2020-01-11'],
  ['2020-01-01', 31, '2020-02-01'],
  ['2020-12-31', 1, '2021-01-01'],
])('ajoute des jours à une date', (date, days, result) => {
  expect(dateAddDays(toCaminoDate(date), days)).toBe(result)
})

test("ajoute une date qui n'en est pas une", () => {
  expect(() => dateAddDays('plop' as CaminoDate, 12)).toThrowErrorMatchingInlineSnapshot(`[Error: Cette camino date plop n'est pas vraiment une caminoDate]`)
})

test.each([
  { date: '2020-01-01', months: 1, expected: '2020-02-01' },
  { date: '2020-01-01', months: 12, expected: '2021-01-01' },
  { date: '2020-01-01', months: 3, expected: '2020-04-01' },
  { date: '2020-01-30', months: 3, expected: '2020-04-30' },
  { date: '2020-01-31', months: 3, expected: '2020-05-01' },
  { date: '2020-12-01', months: 3, expected: '2021-03-01' },
  { date: '2024-01-31', months: 1, expected: '2024-03-02' },
  { date: '2029-01-31', months: 1, expected: '2029-03-03' },
])('ajoute $months mois à la date $date, attendu $expected', ({ date, months, expected }) => {
  expect(dateAddMonths(toCaminoDate(date), months)).toBe(expected)
})

test("la méthode dateAddMonths n'est pas idempotente", () => {
  const date = '2022-05-30'

  expect(dateAddMonths(dateAddMonths(toCaminoDate(date), -3), 3)).toBe('2022-06-02')
})

test('setDayInMonth', () => {
  expect(setDayInMonth(toCaminoDate('2022-01-01'), 3)).toBe(toCaminoDate('2022-01-03'))
  expect(setDayInMonth(toCaminoDate('2022-01-31'), 3)).toBe(toCaminoDate('2022-01-03'))
})

test('isBefore', () => {
  expect(isBefore(toCaminoDate('2022-01-01'), toCaminoDate('2022-01-03'))).toBe(true)
  expect(isBefore(toCaminoDate('2022-01-31'), toCaminoDate('2022-01-03'))).toBe(false)
  expect(isBefore(toCaminoDate('2022-01-31'), toCaminoDate('2022-01-31'))).toBe(false)
  expect(isBefore(toCaminoDate('2022-01-31'), toCaminoDate('2022-01-01'))).toBe(false)
  // @ts-ignore
  expect(isBefore(toCaminoDate('2022-01-31'), null)).toBe(false)
})
