import type { PeriodeListe } from './types';

/**
 * Période de la liste des factures — logique pure, sans React (testée dans
 * `periode.test.ts`). Les paramètres produits sont ceux que lit
 * `PeriodeListe::depuisRequete()` côté serveur.
 */

export type ParamsPeriode = { mois: string } | { annee: number } | { du: string; au: string };

/** Plage libre au plus long — même borne que `PeriodeListe::JOURS_MAX`. */
export const JOURS_MAX = 731;

/** `2026`, `4` → `2026-04`. */
export function cleMois(annee: number, mois: number): string {
    return `${annee}-${String(mois).padStart(2, '0')}`;
}

/** Période précédente (-1) ou suivante (+1) : un mois franchit l'année ; une plage libre n'a pas de voisine. */
export function voisine(p: PeriodeListe, pas: 1 | -1): ParamsPeriode | null {
    if (p.mode === 'mois' && p.mois !== null) {
        const d = new Date(p.annee, p.mois - 1 + pas, 1);
        return { mois: cleMois(d.getFullYear(), d.getMonth() + 1) };
    }
    if (p.mode === 'annee') return { annee: p.annee + pas };
    return null;
}

/** Flèches d'année de la bande des mois : le même mois l'année d'à côté, sinon l'année entière. */
export function anneeVoisine(p: PeriodeListe, pas: 1 | -1): ParamsPeriode {
    if (p.mode === 'mois' && p.mois !== null) return { mois: cleMois(p.annee + pas, p.mois) };
    return { annee: p.annee + pas };
}

/** « 01/04 – 30/04/2026 », ou « 15/12/2025 – 15/01/2026 » à cheval sur deux années. */
export function plage(p: Pick<PeriodeListe, 'du' | 'au'>): string {
    const [a1, m1, j1] = p.du.split('-');
    const [a2, m2, j2] = p.au.split('-');
    return a1 === a2 ? `${j1}/${m1} – ${j2}/${m2}/${a2}` : `${j1}/${m1}/${a1} – ${j2}/${m2}/${a2}`;
}

export function estMoisCourant(p: PeriodeListe, aujourdhui = new Date()): boolean {
    return p.mode === 'mois' && p.annee === aujourdhui.getFullYear() && p.mois === aujourdhui.getMonth() + 1;
}

/** Douze noms de mois dans la langue de l'écran, initiale en capitale : « Janvier » / « Janv. ». */
export function nomsMois(locale: string, format: 'long' | 'short'): string[] {
    const fmt = new Intl.DateTimeFormat(locale === 'en' ? 'en-GB' : 'fr-FR', { month: format });
    return Array.from({ length: 12 }, (_, i) => {
        const nom = fmt.format(new Date(2026, i, 1));
        return nom.charAt(0).toUpperCase() + nom.slice(1);
    });
}

/**
 * Plage à ouvrir pour montrer TOUTES les factures impayées — les tuiles « À
 * encaisser » et « En retard » portent sur toutes les périodes : de la plus
 * ancienne impayée à aujourd'hui, bornée à `JOURS_MAX`. null quand la période
 * affichée les contient déjà : un filtre suffit alors.
 */
export function plageImpayees(depuis: string | null, affichee: Pick<PeriodeListe, 'du' | 'au'>, aujourdhui: string): { du: string; au: string } | null {
    if (!depuis) return null;
    if (affichee.du <= depuis && affichee.au >= aujourdhui) return null;
    const borne = new Date(Date.parse(`${aujourdhui}T00:00:00Z`) - JOURS_MAX * 86_400_000).toISOString().slice(0, 10);
    return { du: depuis < borne ? borne : depuis, au: aujourdhui };
}

/**
 * Une plage libre est-elle envoyable ? Deux dates ISO, dans l'ordre, et pas
 * plus longue que `JOURS_MAX`. Rend la raison du refus, ou null.
 */
export function plageInvalide(du: string, au: string): 'incomplete' | 'ordre' | 'trop_longue' | null {
    const iso = /^\d{4}-\d{2}-\d{2}$/;
    if (!iso.test(du) || !iso.test(au)) return 'incomplete';
    if (du > au) return 'ordre';
    const jours = (Date.parse(`${au}T00:00:00Z`) - Date.parse(`${du}T00:00:00Z`)) / 86_400_000;
    return jours > JOURS_MAX ? 'trop_longue' : null;
}
