import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Pending } from '@/components/ui/pending';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useTranslation } from '@/hooks/use-translation';
import { cn } from '@/lib/utils';
import { AlertTriangle, RefreshCcw } from 'lucide-react';
import * as React from 'react';
import { fmtDateFr, fmtMillimes, libelleMois } from '../format';
import { remplir } from './api';
import {
    compteursParFiltre,
    estDateValide,
    estSelectionnable,
    FILTRES_APERCU,
    lignesFiltrees,
    retenueDiffere,
    type FiltreApercu,
} from './preview-filtres';
import type { Apercu, LigneApercu, OngletApercu, SourceDate, StatutLigne } from './types';

interface Props {
    apercu: Apercu;
    /** L'aperçu est en train d'être relu (date changée, « Relire »). */
    chargement: boolean;
    filtres: ReadonlySet<FiltreApercu>;
    onBasculerFiltre: (filtre: FiltreApercu) => void;
    decochees: ReadonlySet<string>;
    onBasculerLigne: (cle: string) => void;
    onAppliquerDate: (gid: number, date: string) => void;
    onRelire: () => void;
}

type Traduire = ReturnType<typeof useTranslation>['t'];

/** Pastilles : libellé et teinte, active ou non. */
const PASTILLES: Record<FiltreApercu, { cle: string; defaut: string; actif: string }> = {
    a_importer: { cle: 'import_filtre_a_importer', defaut: 'À importer', actif: 'border-emerald-300 bg-emerald-50 text-emerald-900' },
    bloquee: { cle: 'import_filtre_bloquee', defaut: 'Bloquées', actif: 'border-red-300 bg-red-50 text-red-900' },
    deja_faite: { cle: 'import_filtre_deja_faite', defaut: 'Déjà faites', actif: 'border-sky-300 bg-sky-50 text-sky-900' },
    ignoree: { cle: 'import_filtre_ignoree', defaut: 'Ignorées', actif: 'border-slate-300 bg-slate-100 text-slate-900' },
};

/** Étape 2 — ce que le fichier donnerait, onglet par onglet. Rien n'est écrit. */
export function EtapeApercu({ apercu, chargement, filtres, onBasculerFiltre, decochees, onBasculerLigne, onAppliquerDate, onRelire }: Props) {
    const { t } = useTranslation();
    const compteurs = compteursParFiltre(apercu.compteurs);

    return (
        <div className="flex flex-col gap-3">
            <div className="flex flex-wrap items-center justify-between gap-2">
                {/* Ancre de visite guidée : les pastilles portent les compteurs
                    ET le filtre — c'est la lecture de l'aperçu en un coup d'œil. */}
                <div className="flex flex-wrap items-center gap-1.5" data-tour="retenue-import-apercu">
                    {FILTRES_APERCU.map((filtre) => {
                        const actif = filtres.has(filtre);
                        const pastille = PASTILLES[filtre];

                        return (
                            <button
                                key={filtre}
                                type="button"
                                aria-pressed={actif}
                                onClick={() => onBasculerFiltre(filtre)}
                                className={cn(
                                    'inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-colors',
                                    actif ? pastille.actif : 'bg-background text-muted-foreground hover:bg-accent',
                                )}
                            >
                                {t('retenue', pastille.cle, pastille.defaut)}
                                <span className="tabular-nums">{compteurs[filtre]}</span>
                            </button>
                        );
                    })}
                </div>
                <Button variant="outline" size="sm" onClick={onRelire} disabled={chargement}>
                    <RefreshCcw className="mr-1.5 h-3.5 w-3.5" />
                    {t('retenue', 'import_relire', 'Relire')}
                </Button>
            </div>

            <Pending pending={chargement} className="flex flex-col gap-3" message={t('retenue', 'import_apercu_chargement', 'Lecture des lignes…')}>
                {apercu.onglets.length === 0 && (
                    <p className="text-muted-foreground py-6 text-center text-sm">{t('retenue', 'import_apercu_vide', 'Aucune ligne lue.')}</p>
                )}
                {apercu.onglets.map((onglet) => (
                    <SectionOnglet
                        key={onglet.gid}
                        onglet={onglet}
                        filtres={filtres}
                        decochees={decochees}
                        onBasculerLigne={onBasculerLigne}
                        onAppliquerDate={onAppliquerDate}
                        chargement={chargement}
                    />
                ))}
            </Pending>
        </div>
    );
}

function SectionOnglet({
    onglet,
    filtres,
    decochees,
    onBasculerLigne,
    onAppliquerDate,
    chargement,
}: {
    onglet: OngletApercu;
    filtres: ReadonlySet<FiltreApercu>;
    decochees: ReadonlySet<string>;
    onBasculerLigne: (cle: string) => void;
    onAppliquerDate: (gid: number, date: string) => void;
    chargement: boolean;
}) {
    const { t } = useTranslation();
    const visibles = lignesFiltrees(onglet.lignes, filtres);

    return (
        <section className="flex flex-col rounded-lg border">
            <header className="flex flex-col gap-2 border-b px-3 py-2.5 sm:flex-row sm:items-end sm:justify-between">
                <div className="flex min-w-0 flex-col">
                    <h3 className="truncate text-sm font-semibold">{onglet.titre}</h3>
                    <span className="text-muted-foreground text-xs">
                        {onglet.mois
                            ? remplir(t('retenue', 'import_mois_declaration', 'Mois de déclaration : :mois'), {
                                  mois: libelleMois(onglet.mois).toLowerCase(),
                              })
                            : t('retenue', 'import_mois_inconnu', 'Mois de déclaration inconnu : choisissez la date de paiement.')}
                    </span>
                </div>
                <DateOnglet
                    gid={onglet.gid}
                    appliquee={onglet.date_onglet}
                    source={onglet.date_source}
                    chargement={chargement}
                    onAppliquer={onAppliquerDate}
                />
            </header>

            {visibles.length === 0 ? (
                <p className="text-muted-foreground px-3 py-4 text-sm">
                    {t('retenue', 'import_onglet_vide', 'Aucune ligne pour les filtres choisis.')}
                </p>
            ) : (
                <>
                    {/* ≥ 640 px : un tableau, qui défile dans sa boîte s'il le
                        faut — jamais la page. En dessous : des cartes. */}
                    <div className="hidden overflow-x-auto sm:block">
                        <Table className="text-sm">
                            <TableHeader>
                                <TableRow>
                                    <TableHead className="w-8">
                                        <span className="sr-only">{t('retenue', 'import_col_importer', 'Importer')}</span>
                                    </TableHead>
                                    <TableHead className="w-12">{t('retenue', 'import_col_numero', 'N°')}</TableHead>
                                    <TableHead>{t('retenue', 'import_col_nom', 'Nom dans le fichier / bénéficiaire')}</TableHead>
                                    <TableHead>{t('retenue', 'import_col_identifiant', 'Identifiant')}</TableHead>
                                    <TableHead className="text-right">{t('retenue', 'import_col_brut', 'Brut')}</TableHead>
                                    <TableHead className="text-right">{t('retenue', 'import_col_retenue', 'Retenue')}</TableHead>
                                    <TableHead>{t('retenue', 'import_col_date', 'Date')}</TableHead>
                                    <TableHead>{t('retenue', 'import_col_statut', 'Statut')}</TableHead>
                                </TableRow>
                            </TableHeader>
                            <TableBody>
                                {visibles.map((ligne) => (
                                    <TableRow key={ligne.cle} className={cn(ligne.statut === 'bloquee' && 'bg-red-50/40')}>
                                        <TableCell className="align-top">
                                            <CaseLigne ligne={ligne} decochees={decochees} onBasculer={onBasculerLigne} />
                                        </TableCell>
                                        <TableCell className="text-muted-foreground align-top tabular-nums">{ligne.numero}</TableCell>
                                        <TableCell className="max-w-[260px] align-top whitespace-normal">
                                            <Noms ligne={ligne} />
                                        </TableCell>
                                        <TableCell className="align-top">
                                            <Identifiant ligne={ligne} />
                                        </TableCell>
                                        <TableCell className="text-right align-top tabular-nums">{montant(ligne.montant_brut)}</TableCell>
                                        <TableCell className="text-right align-top">
                                            <Retenue ligne={ligne} />
                                        </TableCell>
                                        <TableCell className="align-top tabular-nums">{fmtDateFr(ligne.date_paiement) || '—'}</TableCell>
                                        <TableCell className="max-w-[240px] align-top whitespace-normal">
                                            <Statut ligne={ligne} />
                                        </TableCell>
                                    </TableRow>
                                ))}
                            </TableBody>
                        </Table>
                    </div>

                    <ul className="divide-y sm:hidden">
                        {visibles.map((ligne) => (
                            <li key={ligne.cle} className={cn('flex gap-3 px-3 py-2.5', ligne.statut === 'bloquee' && 'bg-red-50/40')}>
                                <div className="w-4 shrink-0 pt-0.5">
                                    <CaseLigne ligne={ligne} decochees={decochees} onBasculer={onBasculerLigne} />
                                </div>
                                <div className="flex min-w-0 flex-1 flex-col gap-1.5">
                                    <div className="flex items-start justify-between gap-2">
                                        <span className="text-muted-foreground text-xs tabular-nums">
                                            {remplir(t('retenue', 'import_ligne_numero', 'Ligne :numero'), { numero: ligne.numero })}
                                        </span>
                                        <Identifiant ligne={ligne} />
                                    </div>
                                    <Noms ligne={ligne} />
                                    <div className="flex flex-wrap items-baseline gap-x-3 gap-y-0.5 text-xs">
                                        <span>
                                            {t('retenue', 'import_col_brut', 'Brut')}{' '}
                                            <span className="tabular-nums">{montant(ligne.montant_brut)}</span>
                                        </span>
                                        <span className="inline-flex items-center gap-1">
                                            {t('retenue', 'import_col_retenue', 'Retenue')} <Retenue ligne={ligne} />
                                        </span>
                                        <span className="text-muted-foreground tabular-nums">{fmtDateFr(ligne.date_paiement) || '—'}</span>
                                    </div>
                                    <Statut ligne={ligne} />
                                </div>
                            </li>
                        ))}
                    </ul>
                </>
            )}
        </section>
    );
}

const montant = (n: number | null) => (n === null ? '—' : fmtMillimes(n));

function libelleSource(source: SourceDate | null, t: Traduire): string {
    switch (source) {
        case 'entete':
            return t('retenue', 'import_date_source_entete', 'Date lue en tête de l’onglet.');
        case 'colonne':
            return t('retenue', 'import_date_source_colonne', 'Date lue dans la colonne des dates.');
        case 'forcee':
            return t('retenue', 'import_date_source_forcee', 'Date choisie ici.');
        default:
            return t('retenue', 'import_date_source_aucune', 'Aucune date trouvée dans l’onglet.');
    }
}

/**
 * La date de paiement de l'onglet — appliquée aux lignes sans date propre.
 *
 * Elle ne part qu'avec « Appliquer » (ou Entrée), jamais à la frappe : chaque
 * changement relit le fichier, et le serveur en limite le nombre par minute.
 */
function DateOnglet({
    gid,
    appliquee,
    source,
    chargement,
    onAppliquer,
}: {
    gid: number;
    appliquee: string | null;
    source: SourceDate | null;
    chargement: boolean;
    onAppliquer: (gid: number, date: string) => void;
}) {
    const { t } = useTranslation();
    const [brouillon, setBrouillon] = React.useState(appliquee ?? '');

    React.useEffect(() => {
        setBrouillon(appliquee ?? '');
    }, [appliquee]);

    const modifiable = estDateValide(brouillon) && brouillon !== (appliquee ?? '');
    const id = `import-date-${gid}`;

    const appliquer = () => {
        if (modifiable && !chargement) onAppliquer(gid, brouillon);
    };

    return (
        <div className="flex flex-col gap-1 sm:items-end">
            <label htmlFor={id} className="text-muted-foreground text-xs">
                {t('retenue', 'import_date_paiement', 'Date de paiement')}
            </label>
            <div className="flex items-center gap-2">
                <Input
                    id={id}
                    type="date"
                    value={brouillon}
                    onChange={(e) => setBrouillon(e.target.value)}
                    onKeyDown={(e) => {
                        if (e.key === 'Enter') {
                            e.preventDefault();
                            appliquer();
                        }
                    }}
                    className="h-8 w-[150px]"
                />
                {modifiable && (
                    <Button size="sm" variant="outline" onClick={appliquer} disabled={chargement}>
                        {t('retenue', 'import_date_appliquer', 'Appliquer')}
                    </Button>
                )}
            </div>
            <span className="text-muted-foreground text-[11px]">{libelleSource(source, t)}</span>
        </div>
    );
}

function CaseLigne({ ligne, decochees, onBasculer }: { ligne: LigneApercu; decochees: ReadonlySet<string>; onBasculer: (cle: string) => void }) {
    const { t } = useTranslation();
    if (!estSelectionnable(ligne)) return null;

    return (
        <Checkbox
            checked={!decochees.has(ligne.cle)}
            onCheckedChange={() => onBasculer(ligne.cle)}
            aria-label={remplir(t('retenue', 'import_case_ligne', 'Importer la ligne :numero'), { numero: ligne.numero })}
        />
    );
}

/** Le nom tel qu'écrit dans le fichier, puis le bénéficiaire que le manager y reconnaît. */
function Noms({ ligne }: { ligne: LigneApercu }) {
    const { t } = useTranslation();
    const b = ligne.beneficiaire;

    return (
        <div className="flex min-w-0 flex-col gap-0.5">
            <span className="font-medium break-words">{ligne.nom_fichier}</span>
            {ligne.logement && <span className="text-muted-foreground text-xs break-words">{ligne.logement}</span>}
            {b ? (
                <span className="text-xs">
                    <span className="text-muted-foreground">{t('retenue', 'import_beneficiaire', 'Bénéficiaire :')} </span>
                    {b.nom}
                </span>
            ) : (
                <span className="text-muted-foreground text-xs italic">
                    {t('retenue', 'import_beneficiaire_aucun', 'Aucun bénéficiaire reconnu')}
                </span>
            )}
            {b && !b.complet && (
                <span className="flex gap-1 text-xs text-amber-800">
                    <AlertTriangle className="mt-0.5 h-3 w-3 shrink-0" />
                    <span>
                        {t('retenue', 'import_fiche_incomplete', 'Fiche incomplète :')} {b.manque.join(', ')}
                    </span>
                </span>
            )}
        </div>
    );
}

function Identifiant({ ligne }: { ligne: LigneApercu }) {
    if (!ligne.identifiant) return <span className="text-muted-foreground">—</span>;

    return (
        <span className="inline-flex items-center gap-1.5 whitespace-nowrap">
            {ligne.type_identifiant && (
                <Badge variant="outline" className="px-1.5 text-[10px]">
                    {ligne.type_identifiant === 'cin' ? 'CIN' : 'M/F'}
                </Badge>
            )}
            <span className="font-mono text-xs">{ligne.identifiant}</span>
        </span>
    );
}

/** La retenue que le manager déclarera — et l'alerte quand le fichier dit autre chose. */
function Retenue({ ligne }: { ligne: LigneApercu }) {
    const { t } = useTranslation();

    return (
        <span className="inline-flex items-center justify-end gap-1 tabular-nums">
            {retenueDiffere(ligne) && ligne.retenue_fichier !== null && (
                <Tooltip>
                    <TooltipTrigger asChild>
                        <span className="text-amber-600" tabIndex={0}>
                            <AlertTriangle className="h-3.5 w-3.5" />
                            <span className="sr-only">{t('retenue', 'import_retenue_differente', 'Retenue différente du fichier')}</span>
                        </span>
                    </TooltipTrigger>
                    <TooltipContent>
                        {remplir(t('retenue', 'import_retenue_fichier_dit', 'Le fichier dit :montant'), {
                            montant: fmtMillimes(ligne.retenue_fichier),
                        })}
                    </TooltipContent>
                </Tooltip>
            )}
            {montant(ligne.retenue_calculee)}
        </span>
    );
}

const STATUTS: Record<StatutLigne, { cle: string; defaut: string; classe: string }> = {
    a_importer: { cle: 'import_statut_a_importer', defaut: 'À importer', classe: 'border-emerald-200 bg-emerald-50 text-emerald-800' },
    avertissement: { cle: 'import_statut_avertissement', defaut: 'À importer — à vérifier', classe: 'border-amber-200 bg-amber-50 text-amber-800' },
    bloquee: { cle: 'import_statut_bloquee', defaut: 'Bloquée', classe: 'border-red-200 bg-red-50 text-red-800' },
    deja_faite: { cle: 'import_statut_deja_faite', defaut: 'Déjà faite', classe: 'border-sky-200 bg-sky-50 text-sky-800' },
    ignoree: { cle: 'import_statut_ignoree', defaut: 'Ignorée', classe: 'border-slate-200 bg-slate-50 text-slate-700' },
};

function Statut({ ligne }: { ligne: LigneApercu }) {
    const { t } = useTranslation();
    const statut = STATUTS[ligne.statut];

    return (
        <div className="flex flex-col gap-1">
            <div className="flex flex-wrap items-center gap-1.5">
                <Badge variant="outline" className={statut.classe}>
                    {t('retenue', statut.cle, statut.defaut)}
                </Badge>
                {ligne.ligne_manager?.reference && (
                    <span className="text-muted-foreground font-mono text-[11px]">{ligne.ligne_manager.reference}</span>
                )}
            </div>
            {ligne.motifs.length > 0 && (
                <ul className="text-muted-foreground list-disc pl-4 text-xs">
                    {ligne.motifs.map((motif, i) => (
                        <li key={i}>{motif}</li>
                    ))}
                </ul>
            )}
        </div>
    );
}
