import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { TableCell, TableRow } from '@/components/ui/table';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useTranslation } from '@/hooks/use-translation';
import { router } from '@inertiajs/react';
import { AlertTriangle, CheckCircle2, FileDown, MoreHorizontal, Pencil, RotateCcw, Trash2, Upload, Wallet } from 'lucide-react';
import * as React from 'react';
import { fmtDateFr, fmtMillimes, fmtTaux } from './format';
import { tauxCorrespondant } from './taux';
import type { RetenueCan, RetenueLigne, TauxOption } from './types';

/**
 * Un montant déclaré qui s'écarte du montant calculé vaut « saisi à la main ».
 * Tolérance d'un demi-millime : les deux valeurs viennent de `decimal(14,3)`,
 * une comparaison stricte de flottants serait fragile pour rien.
 */
const estSaisiManuellement = (ligne: RetenueLigne) => Math.abs(ligne.montant_brut - ligne.montant_brut_calcule) >= 0.0005;

interface Props {
    ligne: RetenueLigne;
    /** Numéro d'ordre affiché (1-based) — pas l'id. */
    numero: number;
    declarationId: number;
    /** Taux proposés — valables pour les deux familles de bénéficiaires. */
    taux: TauxOption[];
    /** Montants / taux / note figés (déclaration clôturée ou déclarée). */
    /** Conservé pour la SEULE règle permissive qui l'utilise encore : le certificat. */
    locked: boolean;
    /** Même le suivi de paiement est figé (déclaration déposée). */
    can: RetenueCan;
    onEdit: (ligne: RetenueLigne) => void;
    onPayment: (ligne: RetenueLigne) => void;
    onDelete: (ligne: RetenueLigne) => void;
    /** Ouvre l'aperçu du fichier de dépôt pour CETTE ligne seulement. */
    onDeposerTej: (ligne: RetenueLigne) => void;
}

/**
 * Une ligne du tableau, éditable en place sur le montant et le taux.
 *
 * Aucune retenue n'est recalculée ici : `montant_retenue` et `montant_net`
 * viennent des props. Modifier le montant envoie un PATCH et c'est la réponse
 * serveur qui met le tableau à jour.
 */
export function EditableLineRow({ ligne, numero, declarationId, taux, locked, can, onEdit, onPayment, onDelete, onDeposerTej }: Props) {
    const { t } = useTranslation();

    const estProprietaire = ligne.beneficiaire_type === 'proprietaire';
    /*
     * ⚠️ UNE LIGNE DÉPOSÉE N'EST PLUS MODIFIABLE, même en brouillon.
     *
     * `tej_uuid` non nul = le certificat existe à la DGI avec ses montants.
     * Le verrou de clôture ne suffisait pas : il regarde le STATUT, et les 20
     * déclarations importées du compte réel portent 239 certificats en restant
     * en brouillon. Le serveur refuse désormais (`RetenueLigneService::
     * updateLigne`) ; l'écran ne doit pas proposer ce qu'il refusera.
     *
     * Le suivi de paiement, lui, reste ouvert : le virement de janvier se saisit
     * en février, y compris sur une ligne déjà déposée.
     */
    // ⚠️ PLUS DE `!locked` : le statut de la période ne décide plus de rien
    // (2026-08-26). Ce qui gèle une ligne, c'est SON certificat déposé.
    const editable = can.update && ligne.tej_uuid === null;
    const [montant, setMontant] = React.useState(String(ligne.montant_brut));

    // Resync quand le serveur renvoie une nouvelle valeur (PATCH, génération…).
    React.useEffect(() => setMontant(String(ligne.montant_brut)), [ligne.montant_brut]);

    const patch = (data: Record<string, string | number | null>) => {
        router.patch(route('retenue.lignes.update', { id: declarationId, ligne: ligne.id }), data, {
            preserveScroll: true,
            preserveState: true,
        });
    };

    const commitMontant = () => {
        const valeur = Number(montant.replace(',', '.'));
        if (!Number.isFinite(valeur) || valeur < 0) {
            setMontant(String(ligne.montant_brut));
            return;
        }
        if (valeur === ligne.montant_brut) return;
        patch({ montant_brut: valeur });
    };

    /** Taux figé sur la ligne : « 10,00 % — Loyers » (le libellé peut manquer). */
    const tauxFige = ligne.taux_libelle ? `${fmtTaux(ligne.taux)} — ${ligne.taux_libelle}` : null;
    /** Option correspondant au taux figé, `null` si le taux a été saisi à la main. */
    const optionTaux = tauxCorrespondant(taux, ligne);

    const montantManuel = estSaisiManuellement(ligne);

    // Le numéro imprimé est celui de TEJ. Tant que le mois n'est pas déposé, la
    // ligne n'en a pas : le libellé reste neutre plutôt que d'afficher un
    // numéro maison qui ne correspondrait à rien sur TEJ.
    const certificatLabel = ligne.tej_reference
        ? t('retenue', 'certificate_redownload').replace(':numero', ligne.tej_reference)
        : t('retenue', 'certificate_download');

    const ouvrirCertificat = () => {
        // Téléchargement PDF : surtout pas une visite Inertia.
        window.open(route('retenue.certificat', { id: declarationId, ligne: ligne.id }), '_blank');
    };

    /**
     * Un certificat atteste un DÉPÔT, pas une clôture.
     *
     * La condition était `can.certificat && locked`, et la clôture était le seul
     * moyen de l'obtenir. Le bouton « Clôturer » ayant été retiré le
     * 2026-08-24, s'en tenir là aurait rendu les certificats inatteignables sur
     * toute déclaration déposée ligne par ligne — qui reste en brouillon tant
     * qu'il lui manque une ligne.
     *
     * `tej_uuid` non nul est un critère PLUS JUSTE que `locked` : il dit que
     * CETTE ligne est enregistrée chez la DGI, donc que son montant est figé
     * (le hook `updating` du modèle interdit d'y toucher). C'est exactement ce
     * que le refus d'origine cherchait à garantir.
     *
     * `locked` est conservé en second terme pour les mois déjà clôturés en base
     * avant ce changement : rien de ce qui s'imprimait hier ne cesse de
     * s'imprimer.
     */
    const showCertificat = can.certificat && (locked || ligne.tej_uuid !== null);
    /**
     * Déposable tant que la ligne n'a PAS de certificat chez TEJ.
     *
     * `tej_uuid` non nul veut dire que le certificat existe déjà là-bas : le
     * redéposer le compterait deux fois, et la plateforme ne refuse pas les
     * doublons. C'est le seul filet, il est donc porté par l'écran ET par le
     * service.
     */
    const deposable = can.declare && ligne.tej_uuid === null;
    const dejaDepose = ligne.tej_uuid !== null;
    // Le suivi de paiement est TOUJOURS proposé : il n'a jamais quitté le
    // manager, la DGI n'en sait rien. Le menu a donc toujours au moins une entrée.
    const hasActions = true;

    return (
        <TableRow className="align-middle">
            <TableCell className="text-muted-foreground text-center tabular-nums">{numero}</TableCell>

            <TableCell>
                <Badge variant="outline" className="font-normal">
                    {t('retenue', estProprietaire ? 'type_proprietaire' : 'type_fournisseur')}
                </Badge>
            </TableCell>

            {/* Une seule colonne pour les deux familles : le logement d'un
                propriétaire, la facture d'un fournisseur. */}
            <TableCell className="max-w-[220px]">
                {estProprietaire ? (
                    <span className="block truncate" title={ligne.property_nom ?? ''}>
                        {ligne.property_nom ?? <span className="text-muted-foreground">—</span>}
                    </span>
                ) : ligne.facture_numero ? (
                    <span className="flex flex-col text-xs leading-tight">
                        <span className="truncate font-medium">{ligne.facture_numero}</span>
                        {ligne.facture_date && <span className="text-muted-foreground tabular-nums">{fmtDateFr(ligne.facture_date)}</span>}
                    </span>
                ) : (
                    <span className="text-muted-foreground">—</span>
                )}
            </TableCell>

            <TableCell className="max-w-[240px]">
                <div className="flex items-center gap-1.5">
                    <span className="truncate font-medium" title={ligne.beneficiaire_nom}>
                        {ligne.beneficiaire_nom}
                    </span>
                    {!ligne.identite_complete && (
                        <Tooltip>
                            <TooltipTrigger asChild>
                                <span className="text-amber-600">
                                    <AlertTriangle className="h-4 w-4" />
                                </span>
                            </TooltipTrigger>
                            <TooltipContent>{t('retenue', 'identity_incomplete')}</TooltipContent>
                        </Tooltip>
                    )}
                </div>
            </TableCell>

            <TableCell className="tabular-nums">{ligne.beneficiaire_matricule_fiscal ?? <span className="text-muted-foreground">—</span>}</TableCell>
            <TableCell className="tabular-nums">{ligne.beneficiaire_cin ?? <span className="text-muted-foreground">—</span>}</TableCell>

            {/* Montant : édition en place → PATCH montant_brut */}
            <TableCell className="text-right">
                <div className="flex items-center justify-end gap-1.5">
                    {montantManuel && (
                        <Tooltip>
                            <TooltipTrigger asChild>
                                <Badge variant="secondary" className="cursor-default">
                                    {t('retenue', 'manual_badge')}
                                </Badge>
                            </TooltipTrigger>
                            <TooltipContent>
                                {t('retenue', 'manual_tooltip').replace(':montant', fmtMillimes(ligne.montant_brut_calcule))}
                            </TooltipContent>
                        </Tooltip>
                    )}
                    {editable ? (
                        <Input
                            type="number"
                            step="0.001"
                            min="0"
                            inputMode="decimal"
                            value={montant}
                            onChange={(e) => setMontant(e.target.value)}
                            onBlur={commitMontant}
                            onKeyDown={(e) => {
                                if (e.key === 'Enter') (e.target as HTMLInputElement).blur();
                            }}
                            className="h-8 w-32 text-right tabular-nums"
                            aria-label={t('retenue', 'col_gross')}
                        />
                    ) : (
                        <span className="tabular-nums">{fmtMillimes(ligne.montant_brut)}</span>
                    )}
                    {editable && montantManuel && (
                        <Tooltip>
                            <TooltipTrigger asChild>
                                <Button
                                    type="button"
                                    variant="ghost"
                                    size="icon"
                                    className="h-8 w-8"
                                    onClick={() => patch({ montant_brut: ligne.montant_brut_calcule })}
                                    aria-label={t('retenue', 'reset_to_computed')}
                                >
                                    <RotateCcw className="h-3.5 w-3.5" />
                                </Button>
                            </TooltipTrigger>
                            <TooltipContent>{t('retenue', 'reset_to_computed')}</TooltipContent>
                        </Tooltip>
                    )}
                </div>
            </TableCell>

            {/* Retenue + taux appliqué (figé sur la ligne) */}
            <TableCell className="text-right">
                <div className="flex flex-col items-end gap-1">
                    <span className="font-medium text-amber-700 tabular-nums">{fmtMillimes(ligne.montant_retenue)}</span>
                    {editable ? (
                        <Select value={optionTaux?.code ?? undefined} onValueChange={(v) => patch({ taux_code: v })}>
                            <SelectTrigger className="h-7 w-[190px] text-xs">
                                {/* Taux personnalisé : aucune option à sélectionner,
                                    on le montre via le placeholder. Le remplacer par
                                    un taux proposé reste possible ; pour en saisir
                                    un autre à la main, passer par « Modifier ». */}
                                <SelectValue placeholder={tauxFige ?? t('retenue', 'select_rate')} />
                            </SelectTrigger>
                            <SelectContent>
                                {taux.map((option) => (
                                    <SelectItem key={option.code} value={option.code}>
                                        {fmtTaux(option.taux)} — {option.libelle}
                                    </SelectItem>
                                ))}
                            </SelectContent>
                        </Select>
                    ) : (
                        <span className="text-muted-foreground text-xs">{tauxFige ?? fmtTaux(ligne.taux)}</span>
                    )}
                </div>
            </TableCell>

            <TableCell className="text-right font-semibold text-emerald-700 tabular-nums">{fmtMillimes(ligne.montant_net)}</TableCell>

            <TableCell>
                {ligne.est_paye ? (
                    <button type="button" onClick={() => onPayment(ligne)} className="text-left text-xs leading-tight disabled:cursor-default">
                        <Badge variant="outline" className="border-emerald-300 bg-emerald-50 text-emerald-800">
                            {ligne.libelle_paiement ?? t('retenue', 'paid')}
                        </Badge>
                    </button>
                ) : (
                    <Button type="button" variant="ghost" size="sm" onClick={() => onPayment(ligne)} className="text-muted-foreground h-8">
                        <Wallet className="mr-1.5 h-3.5 w-3.5" />
                        {t('retenue', 'unpaid')}
                    </Button>
                )}
            </TableCell>

            <TableCell className="bg-background sticky right-0 z-10 text-right shadow-[-8px_0_8px_-8px_rgba(0,0,0,0.15)]">
                {hasActions && (
                    <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                            <Button variant="ghost" size="icon" className="h-8 w-8" aria-label={t('retenue', 'col_actions')}>
                                <MoreHorizontal className="h-4 w-4" />
                            </Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent align="end">
                            {editable && (
                                <DropdownMenuItem onSelect={() => onEdit(ligne)}>
                                    <Pencil className="mr-2 h-4 w-4" />
                                    {t('retenue', 'edit_line')}
                                </DropdownMenuItem>
                            )}
                            <DropdownMenuItem onSelect={() => onPayment(ligne)}>
                                <Wallet className="mr-2 h-4 w-4" />
                                {t('retenue', 'mark_paid')}
                            </DropdownMenuItem>
                            {showCertificat && (
                                <DropdownMenuItem onSelect={ouvrirCertificat}>
                                    <FileDown className="mr-2 h-4 w-4" />
                                    {certificatLabel}
                                </DropdownMenuItem>
                            )}
                            {deposable && (
                                <>
                                    <DropdownMenuSeparator />
                                    {/* Ouvre l'aperçu — jamais un envoi direct.
                                        Un dépôt ne s'annule pas, il ne se corrige
                                        que par un rectificatif : le fichier doit
                                        être lu avant de partir. */}
                                    <DropdownMenuItem onSelect={() => onDeposerTej(ligne)}>
                                        <Upload className="mr-2 h-4 w-4" />
                                        Envoyer à TEJ…
                                    </DropdownMenuItem>
                                </>
                            )}
                            {dejaDepose && (
                                <DropdownMenuItem disabled>
                                    <CheckCircle2 className="mr-2 h-4 w-4" />
                                    Déposé{ligne.tej_statut ? ` — ${ligne.tej_statut}` : ''}
                                </DropdownMenuItem>
                            )}
                            {can.delete && ligne.tej_uuid === null && (
                                <>
                                    <DropdownMenuSeparator />
                                    <DropdownMenuItem variant="destructive" onSelect={() => onDelete(ligne)}>
                                        <Trash2 className="mr-2 h-4 w-4" />
                                        {t('retenue', 'delete_line')}
                                    </DropdownMenuItem>
                                </>
                            )}
                        </DropdownMenuContent>
                    </DropdownMenu>
                )}
            </TableCell>
        </TableRow>
    );
}
