import { toLocalIso } from '@/components/fr-date';
import { FrDateInput } from '@/components/fr-date-input';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Spinner } from '@/components/ui/spinner';
import { useTranslation } from '@/hooks/use-translation';
import { router } from '@inertiajs/react';
import { useEffect, useState, type FormEvent } from 'react';
import { TYPE_LIBELLE } from '../format';
import type { FactureType } from '../types';

interface NumberingDialogProps {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    /** Numéro que portera la prochaine pièce de chaque série, ex. `FAC-000091`. */
    prochains: Record<FactureType, string>;
    /** Date (ISO) de la dernière pièce Swiver déjà déclarée, par série. */
    planchers: Record<FactureType, string | null>;
    /** Année de la série reprise (celle des `prochains`). */
    annee: number;
}

const TYPES: FactureType[] = ['facture', 'proforma', 'avoir'];

/** `FAC-000091` → préfixe `FAC`, 91, sur 6 chiffres. */
function decomposer(numero: string): { prefixe: string; valeur: number; largeur: number } {
    const m = /^(.*?)-?(\d+)$/.exec(numero);
    if (!m) return { prefixe: numero, valeur: 1, largeur: 6 };
    return { prefixe: m[1], valeur: Number.parseInt(m[2], 10), largeur: m[2].length };
}

export function NumberingDialog({ open, onOpenChange, prochains, planchers, annee }: NumberingDialogProps) {
    const { t } = useTranslation();
    const tr = (cle: string, fr: string) => t('factures', cle, fr);

    const [type, setType] = useState<FactureType>('facture');
    const [saisie, setSaisie] = useState(() => String(decomposer(prochains.facture).valeur));
    // Dernière pièce émise dans Swiver, gardée pour mémoire.
    const [derniereDate, setDerniereDate] = useState(planchers.facture ?? '');
    const [erreur, setErreur] = useState<string | null>(null);
    const [envoi, setEnvoi] = useState(false);

    // Chaque ouverture repart de la série « Facture » et de son prochain numéro réel.
    useEffect(() => {
        if (!open) return;
        setType('facture');
        setSaisie(String(decomposer(prochains.facture).valeur));
        setDerniereDate(planchers.facture ?? '');
        setErreur(null);
    }, [open, prochains, planchers]);

    const actuel = decomposer(prochains[type]);
    const valeur = Number.parseInt(saisie, 10);
    const saisieValide = Number.isInteger(valeur) && valeur >= 1 && valeur <= 999999;
    const recule = saisieValide && valeur < actuel.valeur;
    const apercu = saisieValide ? `${actuel.prefixe}-${String(valeur).padStart(actuel.largeur, '0')}` : null;

    const libelleApercu: Record<FactureType, string> = {
        facture: tr('numerotation.apercu_facture', 'La prochaine facture sera'),
        proforma: tr('numerotation.apercu_proforma', 'La prochaine proforma sera'),
        avoir: tr('numerotation.apercu_avoir', 'Le prochain avoir sera'),
    };

    const changerType = (valeurType: string) => {
        const suivant = TYPES.find((ty) => ty === valeurType) ?? 'facture';
        setType(suivant);
        setSaisie(String(decomposer(prochains[suivant]).valeur));
        setDerniereDate(planchers[suivant] ?? '');
        setErreur(null);
    };

    const fermer = (ouvert: boolean) => {
        if (envoi) return;
        onOpenChange(ouvert);
    };

    const enregistrer = (event: FormEvent) => {
        event.preventDefault();
        if (!saisieValide || recule) return;

        router.put(
            route('factures.numerotation'),
            { type, annee, prochain: valeur, derniere_date: derniereDate || null },
            {
                preserveScroll: true,
                // Garde le dialogue ouvert si le serveur refuse le numéro.
                preserveState: true,
                onStart: () => setEnvoi(true),
                onFinish: () => setEnvoi(false),
                onSuccess: () => onOpenChange(false),
                onError: (errors) => setErreur(errors.prochain ?? Object.values(errors)[0] ?? null),
            },
        );
    };

    return (
        <Dialog open={open} onOpenChange={fermer}>
            <DialogContent className="sm:max-w-md">
                <form onSubmit={enregistrer} className="grid gap-5">
                    <DialogHeader>
                        <DialogTitle>{tr('numerotation.titre', 'Reprendre la numérotation')}</DialogTitle>
                        <DialogDescription>
                            {tr(
                                'numerotation.explication',
                                "Pour continuer la série de Swiver sans doublon ni trou, indiquez le numéro que doit porter la prochaine pièce de l'année. On ne peut qu'avancer : un numéro déjà émis ne se redonne jamais.",
                            )}
                        </DialogDescription>
                    </DialogHeader>

                    <div className="grid gap-4 sm:grid-cols-2">
                        <div className="grid gap-1.5">
                            <Label htmlFor="numerotation-type">{tr('numerotation.type', 'Série')}</Label>
                            <Select value={type} onValueChange={changerType} disabled={envoi}>
                                <SelectTrigger id="numerotation-type">
                                    <SelectValue />
                                </SelectTrigger>
                                <SelectContent>
                                    {TYPES.map((ty) => (
                                        <SelectItem key={ty} value={ty}>
                                            {TYPE_LIBELLE[ty]}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                        </div>
                        <div className="grid gap-1.5">
                            <Label htmlFor="numerotation-prochain">{tr('numerotation.prochain', 'Prochain numéro')}</Label>
                            <Input
                                id="numerotation-prochain"
                                inputMode="numeric"
                                autoComplete="off"
                                value={saisie}
                                disabled={envoi}
                                onChange={(e) => {
                                    setSaisie(e.target.value.replace(/\D/g, '').slice(0, 6));
                                    setErreur(null);
                                }}
                                className="font-mono tabular-nums"
                                aria-invalid={Boolean(erreur) || recule || undefined}
                            />
                        </div>
                    </div>

                    <div className="grid gap-1.5">
                        <Label htmlFor="numerotation-date">{tr('numerotation.derniere_date', 'Date de la dernière pièce Swiver')}</Label>
                        <FrDateInput
                            id="numerotation-date"
                            value={derniereDate}
                            onChange={(iso) => {
                                setDerniereDate(iso);
                                setErreur(null);
                            }}
                            min={`${annee}-01-01`}
                            max={toLocalIso(new Date())}
                            disabled={envoi}
                        />
                        <p className="text-muted-foreground text-xs">
                            {tr(
                                'numerotation.derniere_date_aide',
                                "Gardée pour mémoire : elle n'empêche pas de dater une pièce du Manager avant ce jour.",
                            )}
                        </p>
                    </div>

                    <div className="bg-muted/40 rounded-lg border px-3 py-2.5 text-sm">
                        <div className="text-muted-foreground">
                            {tr('numerotation.actuel', 'Actuellement (:annee) :').replace(':annee', String(annee))}{' '}
                            <span className="text-foreground font-mono">{prochains[type]}</span>
                        </div>
                        {apercu && (
                            <div className="mt-1">
                                {libelleApercu[type]} <span className="text-primary font-mono font-semibold">{apercu}</span>
                            </div>
                        )}
                    </div>

                    {recule && (
                        <p className="text-sm text-rose-700">
                            {tr('numerotation.recul', "On ne peut qu'avancer : le numéro doit être au moins :numero.").replace(
                                ':numero',
                                prochains[type],
                            )}
                        </p>
                    )}
                    {erreur && <p className="text-sm text-rose-700">{erreur}</p>}

                    <DialogFooter>
                        <Button type="button" variant="outline" onClick={() => fermer(false)} disabled={envoi}>
                            {tr('numerotation.annuler', 'Annuler')}
                        </Button>
                        <Button type="submit" className="bg-secondary hover:bg-secondary/90" disabled={envoi || !saisieValide || recule}>
                            {envoi && <Spinner size="sm" className="text-white" />}
                            {tr('numerotation.enregistrer', 'Enregistrer')}
                        </Button>
                    </DialogFooter>
                </form>
            </DialogContent>
        </Dialog>
    );
}
