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 SearchableSelect from '@/components/ui/select-search';
import { router } from '@inertiajs/react';
import axios from 'axios';
import { Loader2, ReceiptText } from 'lucide-react';
import * as React from 'react';
import { toast } from 'sonner';
import type { LedgerRow } from './types';

interface Props {
    open: boolean;
    onOpenChange: (v: boolean) => void;
    row: LedgerRow;
}

function fmtAmount(n: number): string {
    return n.toLocaleString('fr-TN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

/**
 * "Joindre un reçu" — lightweight traceability for a manual cash-out row.
 * Picks who received the cash and generates a Receipt linked to the row; the
 * user lands on the receipt page to print / have it signed. No per-person
 * ledger, no allocation workflow — the row stays a plain manual sortie.
 */
type Mode = 'equipier' | 'externe' | 'existant';

interface AvailableReceipt {
    // Index signature exigée par SearchableSelect.
    [key: string]: unknown;
    id: number;
    name: string;
    amount: number;
}

export function AttachReceiptDialog({ open, onOpenChange, row }: Props) {
    const [mode, setMode] = React.useState<Mode>('equipier');
    const [teamMembers, setTeamMembers] = React.useState<{ id: number; name: string }[]>([]);
    const [receiverId, setReceiverId] = React.useState<string>('');
    const [receiverName, setReceiverName] = React.useState<string>('');
    const [receipts, setReceipts] = React.useState<AvailableReceipt[]>([]);
    const [receiptId, setReceiptId] = React.useState<string>('');
    const [note, setNote] = React.useState<string>('');
    const [submitting, setSubmitting] = React.useState(false);

    React.useEffect(() => {
        if (open && teamMembers.length === 0) {
            axios
                .get<{ id: number; name: string }[]>('/fond-de-caisse/team-members')
                .then((res) => setTeamMembers(res.data))
                .catch(() => toast.error("Impossible de charger l'équipe"));
        }
    }, [open, teamMembers.length]);

    // Reçus déjà existants et encore libres — chargés à la demande.
    React.useEffect(() => {
        if (open && mode === 'existant' && receipts.length === 0) {
            axios
                .get<AvailableReceipt[]>('/fond-de-caisse/available-receipts')
                .then((res) => setReceipts(res.data))
                .catch(() => toast.error('Impossible de charger les reçus disponibles'));
        }
    }, [open, mode, receipts.length]);

    // Un montant différent n'est pas bloquant (acompte, arrondi), mais doit se voir.
    const pickedReceipt = receipts.find((r) => String(r.id) === receiptId);
    const amountMismatch =
        pickedReceipt !== undefined && Math.abs(pickedReceipt.amount - row.amount) > 0.01;

    /**
     * Radix pose `pointer-events: none` sur le <body> tant qu'un Dialog est
     * ouvert et ne le retire qu'à la FERMETURE. Or cette action redirige vers
     * la page du reçu : le dialog est démonté par la navigation sans jamais se
     * fermer, et la page d'arrivée reste entièrement inerte (« je ne peux plus
     * rien cliquer »). Filet de sécurité : on restaure toujours au démontage.
     */
    React.useEffect(
        () => () => {
            document.body.style.pointerEvents = '';
        },
        [],
    );

    const submit = () => {
        if (mode === 'equipier' && !receiverId) {
            toast.error("Choisissez qui a reçu l'argent.");
            return;
        }
        if (mode === 'externe' && receiverName.trim() === '') {
            toast.error('Saisissez le nom de la personne qui a reçu l\'argent.');
            return;
        }
        if (mode === 'existant' && !receiptId) {
            toast.error('Choisissez le reçu à rattacher.');
            return;
        }
        setSubmitting(true);
        // Fermé AVANT la navigation, pas dans onSuccess : à ce moment-là la
        // redirection a déjà eu lieu et le nettoyage de Radix ne tourne plus.
        onOpenChange(false);
        router.post(
            route('fond-de-caisse.attach-receipt', { id: row.id }),
            {
                receipt_id: mode === 'existant' ? Number(receiptId) : undefined,
                receiver_user_id: mode === 'equipier' ? Number(receiverId) : undefined,
                receiver_name: mode === 'externe' ? receiverName.trim() : undefined,
                note: note || undefined,
            },
            {
                preserveScroll: true,
                onFinish: () => setSubmitting(false),
            },
        );
    };

    return (
        <Dialog open={open} onOpenChange={onOpenChange}>
            <DialogContent>
                <DialogHeader>
                    <DialogTitle className="flex items-center gap-2">
                        <ReceiptText className="h-5 w-5" /> Joindre un reçu
                    </DialogTitle>
                    <DialogDescription>
                        Tracer qui a reçu {fmtAmount(row.amount)} TND — «&nbsp;{row.designation}&nbsp;». Un
                        reçu est généré ; vous pourrez l'imprimer et le faire signer.
                    </DialogDescription>
                </DialogHeader>

                <div className="space-y-4 py-2">
                    <div className="grid grid-cols-3 gap-1 rounded-md bg-muted p-1">
                        {(
                            [
                                ['equipier', 'Équipier'],
                                ['externe', 'Hors équipe'],
                                ['existant', 'Reçu existant'],
                            ] as [Mode, string][]
                        ).map(([value, label]) => (
                            <button
                                key={value}
                                type="button"
                                onClick={() => setMode(value)}
                                className={
                                    'rounded px-2 py-1.5 text-sm transition-colors ' +
                                    (mode === value
                                        ? 'bg-background font-medium shadow-sm'
                                        : 'text-muted-foreground hover:text-foreground')
                                }
                            >
                                {label}
                            </button>
                        ))}
                    </div>

                    {mode === 'equipier' && (
                        <div className="space-y-1.5">
                            <Label>Reçu par</Label>
                            <SearchableSelect
                                value={receiverId}
                                onValueChange={setReceiverId}
                                items={teamMembers}
                                placeholder="Choisir un équipier…"
                                allOptionLabel=""
                                notFoundMessage="Aucun membre trouvé"
                                className="bg-background text-foreground h-11 w-full justify-between rounded-md px-3 text-base font-normal"
                            />
                        </div>
                    )}

                    {mode === 'externe' && (
                        <div className="space-y-1.5">
                            <Label>Nom de la personne</Label>
                            <Input
                                value={receiverName}
                                onChange={(e) => setReceiverName(e.target.value)}
                                placeholder="ex. Naser — menuisier"
                                className="h-11"
                            />
                            <p className="text-muted-foreground text-xs">
                                Personne sans compte : le reçu ne peut pas être signé électroniquement.
                                Imprimez-le et faites-le signer à la main.
                            </p>
                        </div>
                    )}

                    {mode === 'existant' && (
                        <div className="space-y-1.5">
                            <Label>Reçu à rattacher</Label>
                            <SearchableSelect
                                value={receiptId}
                                onValueChange={setReceiptId}
                                items={receipts}
                                placeholder="Choisir un reçu…"
                                allOptionLabel=""
                                notFoundMessage="Aucun reçu disponible"
                                className="bg-background text-foreground h-11 w-full justify-between rounded-md px-3 text-base font-normal"
                            />
                            {amountMismatch && (
                                <p className="text-amber-700 text-xs">
                                    ⚠️ Ce reçu vaut {fmtAmount(pickedReceipt!.amount)} TND alors que la ligne
                                    en fait {fmtAmount(row.amount)}. Rattachement possible, mais vérifiez.
                                </p>
                            )}
                        </div>
                    )}

                    {mode !== 'existant' && (
                        <div className="space-y-1.5">
                            <Label>Note (optionnel)</Label>
                            <Input value={note} onChange={(e) => setNote(e.target.value)} placeholder={row.designation} />
                        </div>
                    )}
                </div>

                <DialogFooter>
                    <Button variant="outline" onClick={() => onOpenChange(false)} disabled={submitting}>
                        Annuler
                    </Button>
                    <Button
                        onClick={submit}
                        disabled={
                            submitting ||
                            (mode === 'equipier' && !receiverId) ||
                            (mode === 'externe' && receiverName.trim() === '') ||
                            (mode === 'existant' && !receiptId)
                        }
                    >
                        {submitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
                        {mode === 'existant' ? 'Rattacher le reçu' : 'Générer le reçu'}
                    </Button>
                </DialogFooter>
            </DialogContent>
        </Dialog>
    );
}
