import { FrDateInput } from '@/components/fr-date-input';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Label } from '@/components/ui/label';
import { useTranslation } from '@/hooks/use-translation';
import { useForm } from '@inertiajs/react';
import { AlertTriangle, Landmark, Send } from 'lucide-react';
import * as React from 'react';
import type { SupplierRow } from './columns';
import {
    dateNaissanceRequise,
    derniereDateNaissanceIso,
    estMiseAJour,
    etatTej,
    isoDateNaissance,
    libelleTypeIdentifier,
    motifIndisponibiliteHorsDate,
    TYPE_IDENTIFIER_CIN,
    type TejEcritureProp,
} from './tej';
import { TejEtatBadge } from './tej-etat-badge';

interface Props {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    /** Fiche à envoyer ; `null` quand le dialogue est fermé (il reste monté). */
    supplier: SupplierRow | null;
    ecriture: TejEcritureProp;
}

/**
 * Confirmation de l'envoi d'une fiche bénéficiaire vers TEJ.
 *
 * Ce n'est pas un « êtes-vous sûr ? ». L'action dépose une identité fiscale
 * chez la Direction générale des impôts, alors le dialogue MONTRE les trois
 * valeurs qui partent — nom, type d'identifiant, identifiant NORMALISÉ — avant
 * que l'utilisateur ne confirme. L'identifiant affiché est celui calculé par le
 * serveur : c'est la chaîne exacte du corps (`1184751K`), pas la saisie de la
 * fiche (`0000000/S`, `430106/C/A/M/000`). Confirmer une valeur qu'on ne verra
 * pas partir ne confirme rien.
 *
 * Le second garde-fou vient du fait le plus coûteux du module : TEJ NE REFUSE
 * JAMAIS UN DOUBLON. Un ré-envoi répond 200 « Création effectuée avec succès »
 * et met silencieusement à jour la fiche existante — et comme il n'existe ni
 * PUT ni PATCH côté TEJ, c'est le MÊME POST qui sert à modifier. Sur une fiche
 * déjà envoyée ou déjà connue du registre, le bouton reste donc verrouillé tant
 * qu'une case explicite n'a pas été cochée, et la requête porte alors
 * `forcer: true` (le `$forcerMiseAJour` du service).
 *
 * Le troisième garde-fou est la DATE DE NAISSANCE d'un tiers identifié par son
 * CIN : TEJ l'exige (elle seule le distingue dans le registre de l'état civil)
 * et le portail ne laisse pas passer un CIN sans date.
 *
 * Depuis le 2026-08-10 elle est PORTÉE PAR LA FICHE
 * (`beneficiaires.date_naissance`, saisie dans `supplier-dialog`) et le serveur
 * la lit tout seul. Le champ ci-dessous n'a donc plus qu'un rôle de
 * RATTRAPAGE : les fiches antérieures à la colonne n'en portent pas, et sans lui
 * l'écran afficherait « Indiquez-la au moment de l'envoi » sans offrir nulle
 * part où la saisir. Une date entrée ici sert à CET envoi et n'est pas écrite
 * sur la fiche — `apresSucces()` ne touche qu'à `tej_external_id` et
 * `tej_synced_at`.
 */
export function TejSendDialog({ open, onOpenChange, supplier, ecriture }: Props) {
    const { t } = useTranslation();

    // Alias explicite : sans lui `useForm` infère `forcer: false` en type
    // littéral et la case ne peut plus être cochée (même piège que dans
    // supplier-dialog avec `actif`).
    type TejForm = { forcer: boolean; date_naissance: string };

    const form = useForm<TejForm>({ forcer: false, date_naissance: '' });
    const { data, setData, processing, clearErrors } = form;
    const errors = form.errors as Record<string, string | undefined>;

    // Dialogue monté en permanence : on repart d'une case DÉCOCHÉE à chaque
    // ouverture. Reconduire un « forcer » d'une fiche à l'autre ferait partir
    // une mise à jour non demandée — et reconduire une DATE DE NAISSANCE la
    // ferait partir sur le CIN de quelqu'un d'autre.
    //
    // La remise à zéro se fait AUSSI à la fermeture, et pas seulement à
    // l'ouverture : l'état du formulaire survit au dialogue, si bien qu'une date
    // laissée là serait celle affichée au premier rendu de l'ouverture SUIVANTE,
    // avant que cet effet n'ait posé celle de la nouvelle fiche.
    React.useEffect(() => {
        clearErrors();
        setData({ forcer: false, date_naissance: open ? isoDateNaissance(supplier?.date_naissance) : '' });
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [open, supplier?.id]);

    const fiche = supplier?.tej;
    const etat = etatTej(fiche);
    const miseAJour = estMiseAJour(etat);
    // Le blocage « date de naissance manquante » n'en est pas un ICI : le champ
    // ci-dessous le lève. Tous les autres éteignent le bouton comme avant.
    const motif = motifIndisponibiliteHorsDate(fiche, ecriture, t);
    const confirmationManquante = miseAJour && !data.forcer;

    // Le champ suit le TYPE (une fiche CIN le montre toujours, pré-rempli le cas
    // échéant) ; l'obligation suit le SERVEUR (il ne réclame la date que tant
    // qu'il ne la trouve pas lui-même).
    const estCin = fiche?.type_identifier === TYPE_IDENTIFIER_CIN;
    const dateObligatoire = dateNaissanceRequise(fiche);
    const dateManquante = dateObligatoire && data.date_naissance === '';
    const maxDateNaissance = React.useMemo(() => derniereDateNaissanceIso(), []);

    const bloque = motif !== null || confirmationManquante || dateManquante || processing;

    const submit = (event: React.FormEvent) => {
        event.preventDefault();
        if (!supplier || motif !== null || confirmationManquante || dateManquante) return;

        // La date ne concerne QUE le CIN, et une chaîne vide n'est pas une date :
        // la clé ne part que lorsqu'elle porte une valeur, pour que la requête
        // reste aussi pauvre que ce qu'`EnvoiTejRequest` documente.
        //
        // Format : l'ISO `aaaa-mm-jj` de `FrDateInput`, tel quel. `EnvoiTejRequest`
        // valide `date_format:d/m/Y,Y-m-d` et le service reformate en `jj/mm/aaaa`
        // avant l'envoi — convertir ici ajouterait une troisième écriture de la
        // même date, donc une occasion de plus de se tromper d'un jour.
        form.transform((current) => ({
            forcer: current.forcer,
            ...(estCin && current.date_naissance !== '' ? { date_naissance: current.date_naissance } : {}),
        }));

        // Ziggy reçoit l'id NU plutôt qu'un objet nommé : la route est
        // `POST /fournisseurs/{beneficiaire}/tej` et l'écran n'a pas à dépendre
        // du nom que porte ce paramètre côté PHP.
        form.post(route('fournisseurs.tej', supplier.id), {
            preserveScroll: true,
            onSuccess: () => onOpenChange(false),
        });
    };

    return (
        <Dialog open={open} onOpenChange={onOpenChange}>
            <DialogContent
                className="sm:max-w-lg"
                /* Confirmation d'un envoi à l'État : pas de fermeture sur un
                   clic à côté, comme sur les dialogues de saisie. */
                onInteractOutside={(e) => e.preventDefault()}
            >
                <DialogHeader>
                    <DialogTitle className="flex items-center gap-2">
                        <Landmark className="h-5 w-5" />
                        {miseAJour
                            ? t('fournisseurs', 'tej_send_title_update', 'Mettre à jour cette fiche chez TEJ')
                            : t('fournisseurs', 'tej_send_title', 'Envoyer cette fiche vers TEJ')}
                    </DialogTitle>
                    <DialogDescription>
                        {t(
                            'fournisseurs',
                            'tej_send_desc',
                            'Ces valeurs seront déposées chez la Direction générale des impôts. Vérifiez-les : ce sont exactement celles qui partent.',
                        )}
                    </DialogDescription>
                </DialogHeader>

                <form onSubmit={submit} className="flex flex-col gap-4">
                    {/* Ce qui part — les trois champs d'identité du corps. */}
                    <dl className="bg-muted/40 flex flex-col gap-2 rounded-md border p-3 text-sm">
                        <div className="flex items-baseline justify-between gap-3">
                            <dt className="text-muted-foreground shrink-0">{t('fournisseurs', 'raison_sociale', 'Raison sociale')}</dt>
                            <dd className="text-right font-medium break-words">{supplier?.raison_sociale ?? '—'}</dd>
                        </div>
                        <div className="flex items-baseline justify-between gap-3">
                            <dt className="text-muted-foreground shrink-0">{t('fournisseurs', 'tej_type_identifier', "Type d'identifiant")}</dt>
                            <dd className="text-right font-medium">
                                {libelleTypeIdentifier(fiche?.type_identifier ?? null, t)}
                                {fiche?.type_identifier != null && (
                                    <span className="text-muted-foreground ml-1 font-normal">({fiche.type_identifier})</span>
                                )}
                            </dd>
                        </div>
                        <div className="flex items-baseline justify-between gap-3">
                            <dt className="text-muted-foreground shrink-0">{t('fournisseurs', 'tej_identifiant', 'Identifiant normalisé')}</dt>
                            <dd className="text-right font-mono font-medium tracking-wide tabular-nums">
                                {fiche?.identifiant ?? (
                                    <span className="text-destructive font-sans">{t('fournisseurs', 'tej_identifiant_absent', 'Absent')}</span>
                                )}
                            </dd>
                        </div>
                        <div className="flex items-baseline justify-between gap-3 border-t pt-2">
                            <dt className="text-muted-foreground shrink-0">{t('fournisseurs', 'tej_etat', 'État')}</dt>
                            <dd>
                                <TejEtatBadge fiche={fiche} />
                            </dd>
                        </div>
                    </dl>

                    <p className="text-muted-foreground text-xs">
                        {t(
                            'fournisseurs',
                            'tej_identifiant_hint',
                            "L'identifiant part sans séparateur ni espace : c'est la forme ci-dessus, pas celle saisie sur la fiche.",
                        )}
                    </p>

                    {/* Date de naissance — CIN uniquement.
                        TEJ l'exige pour ce type et pour lui seul : c'est elle qui
                        départage deux homonymes dans le registre de l'état civil
                        (`validateMadania`). La fiche la porte désormais et le
                        serveur la lit seul ; ce champ sert au RATTRAPAGE des
                        fiches antérieures à la colonne, et sa valeur n'est pas
                        réécrite sur la fiche.

                        ⚠️ Le calendrier s'ouvre dans un portail Radix, HORS du
                        dialogue : `FrDateInput` porte déjà le `pointer-events-auto`
                        sans lequel il s'afficherait sans se laisser cliquer, et le
                        `onInteractOutside` neutralisé ci-dessus empêche le choix
                        d'une date de fermer ce dialogue (errors.md, 2026-08-04). */}
                    {estCin && (
                        <div className="flex flex-col gap-1.5">
                            <Label>
                                {t('fournisseurs', 'tej_date_naissance', 'Date de naissance')}
                                {dateObligatoire && <span className="text-destructive ml-1">*</span>}
                            </Label>
                            <FrDateInput
                                value={data.date_naissance}
                                onChange={(iso) => setData('date_naissance', iso)}
                                max={maxDateNaissance}
                                inputClassName="h-9"
                            />
                            <p className="text-muted-foreground text-xs">
                                {t(
                                    'fournisseurs',
                                    'tej_date_naissance_hint',
                                    "TEJ exige la date de naissance d'un tiers identifié par son CIN. Quand la fiche en porte une, l'envoi la reprend tout seul ; sinon indiquez-la ici. Une date saisie ici sert à CET envoi et n'est pas enregistrée sur la fiche — pour l'y conserver, renseignez-la dans « Modifier ».",
                                )}
                            </p>
                            {errors.date_naissance && <p className="text-destructive text-xs">{errors.date_naissance}</p>}
                        </div>
                    )}

                    {/* Rien ne peut partir : on le dit ici aussi, le dialogue
                        pouvant rester ouvert quand le verrou tombe. */}
                    {motif !== null && (
                        <div className="flex items-start gap-2 rounded-md border border-amber-300 bg-amber-50 p-3 text-sm text-amber-900">
                            <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
                            <span>{motif}</span>
                        </div>
                    )}

                    {/* Le piège le plus coûteux du module, énoncé au moment où
                        il se déclencherait. */}
                    {motif === null && miseAJour && (
                        <div className="flex flex-col gap-2 rounded-md border border-amber-300 bg-amber-50 p-3 text-sm text-amber-900">
                            <div className="flex items-start gap-2">
                                <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
                                <span>
                                    {t(
                                        'fournisseurs',
                                        'tej_doublon_hint',
                                        'TEJ ne refuse pas les doublons : il répondra « Création effectuée avec succès » et écrasera la fiche déjà déposée. Un renvoi est donc une mise à jour, pas un essai sans conséquence.',
                                    )}
                                </span>
                            </div>
                            <div className="flex items-center gap-2 pl-6">
                                <Checkbox id="tej-forcer" checked={data.forcer} onCheckedChange={(checked) => setData('forcer', checked === true)} />
                                <Label htmlFor="tej-forcer" className="text-amber-900">
                                    {t('fournisseurs', 'tej_forcer', 'Je veux mettre à jour la fiche déjà connue de TEJ')}
                                </Label>
                            </div>
                        </div>
                    )}

                    {errors.message && <p className="text-destructive text-xs">{errors.message}</p>}
                    {errors.forcer && <p className="text-destructive text-xs">{errors.forcer}</p>}

                    <DialogFooter>
                        <Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
                            {t('fournisseurs', 'cancel', 'Annuler')}
                        </Button>
                        <Button type="submit" disabled={bloque}>
                            <Send className="mr-2 h-4 w-4" />
                            {miseAJour
                                ? t('fournisseurs', 'tej_confirm_update', 'Mettre à jour chez TEJ')
                                : t('fournisseurs', 'tej_confirm', 'Envoyer vers TEJ')}
                        </Button>
                    </DialogFooter>
                </form>
            </DialogContent>
        </Dialog>
    );
}
