import { describe, expect, it } from 'vitest';
import { consequenceSuppression, effetSuppression, type BlocSuppression } from './suppression';

/** Repli du catalogue : `lang/fr/fournisseurs.php` n'a pas encore les clés `delete_…`. */
const t = (_namespace: string, key: string, fallback?: string) => fallback ?? key;

const bloc = (surcharge: Partial<BlocSuppression> = {}): BlocSuppression => ({
    lignes_retenue: 0,
    lien_tej: true,
    ...surcharge,
});

describe('effetSuppression', () => {
    it('aucune ligne citante = effacement DÉFINITIF', () => {
        expect(effetSuppression(bloc({ lignes_retenue: 0 }))).toBe('definitive');
    });

    it('une seule ligne citante suffit à CONSERVER la fiche', () => {
        expect(effetSuppression(bloc({ lignes_retenue: 1 }))).toBe('conservee');
        expect(effetSuppression(bloc({ lignes_retenue: 96 }))).toBe('conservee');
    });

    it("rend `inconnu` quand le serveur n'a pas fourni le bloc", () => {
        expect(effetSuppression(null)).toBe('inconnu');
        expect(effetSuppression(undefined)).toBe('inconnu');
    });

    /*
     * Le cas qui compte vraiment. Ce bloc est rempli par un contrôleur écrit en
     * PARALLÈLE de cet écran : « il arrive à moitié » n'est pas une hypothèse
     * d'école, c'est le déploiement en deux temps. Lire un `lignes_retenue`
     * manquant comme `0` ferait annoncer « effacée définitivement » sur une
     * fiche que le serveur va conserver — le contraire de ce que cette boîte
     * existe pour dire.
     */
    it('traite un bloc MAL FORMÉ comme une absence, jamais comme un zéro', () => {
        expect(effetSuppression({ lien_tej: true } as unknown as BlocSuppression)).toBe('inconnu');
        expect(effetSuppression({ lignes_retenue: 3 } as unknown as BlocSuppression)).toBe('inconnu');
        expect(effetSuppression({ lignes_retenue: '0', lien_tej: true } as unknown as BlocSuppression)).toBe('inconnu');
        expect(effetSuppression({ lignes_retenue: 0, lien_tej: 'oui' } as unknown as BlocSuppression)).toBe('inconnu');
        expect(effetSuppression(bloc({ lignes_retenue: -1 }))).toBe('inconnu');
        expect(effetSuppression(bloc({ lignes_retenue: 1.5 }))).toBe('inconnu');
        expect(effetSuppression(bloc({ lignes_retenue: Number.NaN }))).toBe('inconnu');
    });
});

describe('consequenceSuppression — fiche libre, donc effacée pour de bon', () => {
    it('annonce les DEUX effets : effacement ici, retrait de la liste TEJ', () => {
        const c = consequenceSuppression(bloc({ lignes_retenue: 0, lien_tej: true }), t);

        expect(c.effet).toBe('definitive');
        expect(c.lignes).toBe(0);
        expect(c.lienTej).toBe(true);
        expect(c.ici).toContain('définitivement');
        expect(c.tej).toContain('retirée de votre liste');
        // Ce que TEJ ne fait PAS : effacer le contribuable du registre national.
        // La capture du 2026-08-10 le montre — `verify` répond encore 200 après
        // la suppression. Promettre l'inverse serait faux.
        expect(c.tej).toContain('registre national');
        expect(c.irreversible).toBe(true);
    });

    it("ne promet rien chez TEJ quand la fiche n'y a jamais été envoyée", () => {
        const c = consequenceSuppression(bloc({ lignes_retenue: 0, lien_tej: false }), t);

        expect(c.effet).toBe('definitive');
        expect(c.tej).toContain("n'est pas liée à TEJ");
        expect(c.irreversible).toBe(true);
    });

    it('nomme le geste sur le bouton — jamais « Confirmer »', () => {
        expect(consequenceSuppression(bloc({ lignes_retenue: 0 }), t).confirmation).toBe('Supprimer définitivement');
    });
});

describe('consequenceSuppression — fiche citée, donc conservée', () => {
    it('accorde le singulier : une seule ligne ne « citent » pas', () => {
        const c = consequenceSuppression(bloc({ lignes_retenue: 1 }), t);

        expect(c.ici).toContain('1 ligne de retenue cite cette fiche');
        expect(c.ici).not.toContain(':count');
    });

    it('substitue le nombre au pluriel, et ne laisse aucun `:count` à l’écran', () => {
        const c = consequenceSuppression(bloc({ lignes_retenue: 4 }), t);

        expect(c.ici).toContain('4 lignes de retenue citent cette fiche');
        expect(c.ici).not.toContain(':count');
    });

    it('dit que la fiche RESTE — ici masquée, et chez TEJ intacte', () => {
        const c = consequenceSuppression(bloc({ lignes_retenue: 4, lien_tej: true }), t);

        expect(c.effet).toBe('conservee');
        expect(c.ici).toContain('CONSERVÉE');
        expect(c.ici).toContain('masquée');
        expect(c.tej).toContain('restera chez TEJ');
        expect(c.confirmation).toBe('Retirer de la liste');
    });

    /*
     * Le rouge se garde pour ce qui détruit. Une fiche conservée ne perd rien —
     * ni ligne, ni certificat, ni fiche TEJ — et alarmer là où il n'y a pas de
     * danger apprend à ignorer l'alarme le jour où elle est méritée.
     */
    it("n'est PAS marquée irréversible : rien ne disparaît", () => {
        expect(consequenceSuppression(bloc({ lignes_retenue: 1 }), t).irreversible).toBe(false);
        expect(consequenceSuppression(bloc({ lignes_retenue: 96 }), t).irreversible).toBe(false);
    });

    it('ne parle pas de TEJ pour une fiche qui n’y a jamais été envoyée', () => {
        expect(consequenceSuppression(bloc({ lignes_retenue: 3, lien_tej: false }), t).tej).toContain("n'est pas liée à TEJ");
    });
});

describe('consequenceSuppression — état inconnu', () => {
    /*
     * L'AVEU D'IGNORANCE PLUTÔT QUE LA PROMESSE. Sans le bloc, l'écran ne sait
     * pas lequel des deux gestes le clic déclenche : il le DIT, et n'annonce
     * surtout pas un effet sur TEJ qu'il serait incapable de garantir.
     */
    it('ne promet aucun effet, ni ici ni chez TEJ', () => {
        for (const absent of [null, undefined]) {
            const c = consequenceSuppression(absent, t);

            expect(c.effet).toBe('inconnu');
            expect(c.lignes).toBeNull();
            expect(c.lienTej).toBeNull();
            expect(c.tej).toBeNull();
            expect(c.irreversible).toBe(false);
            expect(c.ici).toContain("n'a pas indiqué");
            expect(c.confirmation).toBe('Supprimer');
        }
    });
});

describe('catalogue de traductions', () => {
    /*
     * Le jour où le catalogue `fournisseurs` recevra ces clés, c'est SA phrase
     * qui s'affichera — et la substitution de `:count` doit continuer à opérer
     * dessus, pas seulement sur le repli codé en dur ici.
     */
    it('substitue `:count` dans la phrase du catalogue, pas seulement dans le repli', () => {
        const catalogue = (_namespace: string, key: string, fallback?: string) =>
            key === 'delete_ici_conservee' ? 'Gardée : :count lignes.' : (fallback ?? key);

        expect(consequenceSuppression(bloc({ lignes_retenue: 7 }), catalogue).ici).toBe('Gardée : 7 lignes.');
    });

    it('laisse le catalogue reformuler chaque phrase sans changer la décision', () => {
        const catalogue = (_namespace: string, key: string, fallback?: string) => (key.startsWith('delete_') ? `[${key}]` : (fallback ?? key));
        const c = consequenceSuppression(bloc({ lignes_retenue: 0, lien_tej: true }), catalogue);

        expect(c.titre).toBe('[delete_titre_definitive]');
        expect(c.ici).toBe('[delete_ici_definitive]');
        expect(c.tej).toBe('[delete_tej_retiree]');
        expect(c.confirmation).toBe('[delete_confirmer_definitive]');
        // La décision, elle, ne vient pas du catalogue.
        expect(c.irreversible).toBe(true);
    });
});
