import { describe, expect, it } from 'vitest';
import { anneeVoisine, cleMois, estMoisCourant, nomsMois, plage, plageImpayees, plageInvalide, voisine } from './periode';
import type { PeriodeListe } from './types';

const avril: PeriodeListe = { mode: 'mois', du: '2026-04-01', au: '2026-04-30', annee: 2026, mois: 4 };
const annee: PeriodeListe = { mode: 'annee', du: '2026-01-01', au: '2026-12-31', annee: 2026, mois: null };
const libre: PeriodeListe = { mode: 'personnalise', du: '2025-12-15', au: '2026-01-15', annee: 2025, mois: null };

describe('période de la liste des factures', () => {
    it('écrit le mois sur deux chiffres', () => {
        expect(cleMois(2026, 4)).toBe('2026-04');
        expect(cleMois(2026, 12)).toBe('2026-12');
    });

    it('passe au mois voisin, en franchissant l’année', () => {
        expect(voisine(avril, 1)).toEqual({ mois: '2026-05' });
        expect(voisine({ ...avril, mois: 1, du: '2026-01-01', au: '2026-01-31' }, -1)).toEqual({ mois: '2025-12' });
        expect(voisine({ ...avril, mois: 12, du: '2026-12-01', au: '2026-12-31' }, 1)).toEqual({ mois: '2027-01' });
    });

    it('passe à l’année voisine ; une plage libre n’a pas de voisine', () => {
        expect(voisine(annee, -1)).toEqual({ annee: 2025 });
        expect(voisine(libre, 1)).toBeNull();
    });

    it('les flèches d’année gardent le mois choisi', () => {
        expect(anneeVoisine(avril, -1)).toEqual({ mois: '2025-04' });
        expect(anneeVoisine(annee, 1)).toEqual({ annee: 2027 });
        expect(anneeVoisine(libre, 1)).toEqual({ annee: 2026 });
    });

    it('affiche la plage en jj/mm, l’année une seule fois quand elle ne change pas', () => {
        expect(plage(avril)).toBe('01/04 – 30/04/2026');
        expect(plage(libre)).toBe('15/12/2025 – 15/01/2026');
    });

    it('reconnaît le mois en cours', () => {
        expect(estMoisCourant(avril, new Date(2026, 3, 18))).toBe(true);
        expect(estMoisCourant(avril, new Date(2026, 8, 28))).toBe(false);
        expect(estMoisCourant(annee, new Date(2026, 3, 18))).toBe(false);
    });

    it('nomme les mois dans la langue de l’écran', () => {
        expect(nomsMois('fr', 'long')[3]).toBe('Avril');
        expect(nomsMois('fr', 'long')).toHaveLength(12);
        expect(nomsMois('en', 'long')[3]).toBe('April');
    });

    it('refuse une plage incomplète, à l’envers ou trop longue', () => {
        expect(plageInvalide('2026-04-01', '')).toBe('incomplete');
        expect(plageInvalide('2026-04-30', '2026-04-01')).toBe('ordre');
        expect(plageInvalide('2024-01-01', '2026-02-01')).toBe('trop_longue');
        expect(plageInvalide('2026-04-01', '2026-04-01')).toBeNull();
        expect(plageInvalide('2025-01-01', '2026-12-31')).toBeNull();
    });

    it('ouvre la plage des impayées seulement quand la période ne les montre pas', () => {
        // Aucune impayée : rien à ouvrir.
        expect(plageImpayees(null, avril, '2026-04-20')).toBeNull();
        // Le mois affiché contient la plus ancienne et aujourd'hui : un filtre suffit.
        expect(plageImpayees('2026-04-03', avril, '2026-04-20')).toBeNull();
        // Le 1er mai, les impayées d'avril sont hors du mois affiché.
        const mai: PeriodeListe = { mode: 'mois', du: '2026-05-01', au: '2026-05-31', annee: 2026, mois: 5 };
        expect(plageImpayees('2026-04-03', mai, '2026-05-01')).toEqual({ du: '2026-04-03', au: '2026-05-01' });
        // Une année passée ne va pas jusqu'à aujourd'hui.
        expect(plageImpayees('2026-02-01', annee, '2027-01-10')).toEqual({ du: '2026-02-01', au: '2027-01-10' });
        // Bornée à JOURS_MAX, que le serveur accepte.
        const bornee = plageImpayees('2020-01-01', avril, '2026-04-20');
        expect(bornee?.au).toBe('2026-04-20');
        expect(plageInvalide(bornee!.du, bornee!.au)).toBeNull();
    });
});
