import { useForm } from '@inertiajs/react';
import { Paperclip, Plus, Trash2, Upload, X } from 'lucide-react';
import { useRef } from 'react';
import type { FormEvent } from 'react';
import ExpenseReportController from '@/actions/App/Http/Controllers/Admin/ExpenseReportController';
import InputError from '@/components/input-error';
import { Button } from '@/components/ui/button';
import {
    Card,
    CardContent,
    CardDescription,
    CardHeader,
    CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { formatCurrency } from '@/lib/utils';
import { useCompanyCurrency } from '@/hooks/use-company-currency';

export type CategoryOption = { value: string; label: string };

export type ExpenseLineData = {
    id: number;
    category: string;
    description: string;
    amount: string | number;
    spent_at: string | null;
    receipt_name: string | null;
    receipt_url: string | null;
    has_receipt: boolean;
};

export type ExpenseReportFormData = {
    id: number;
    code: string;
    title: string;
    lines: ExpenseLineData[];
};

type LineForm = {
    uid: string;
    id: number | null;
    category: string;
    description: string;
    amount: string;
    spent_at: string;
    receipt: File | null;
    existing_receipt_name: string | null;
    existing_receipt_url: string | null;
};

type Props = {
    categories: CategoryOption[];
    report?: ExpenseReportFormData | null;
    onCancel: () => void;
};

let uidCounter = 0;
function nextUid(): string {
    uidCounter += 1;
    return `line-${uidCounter}`;
}

function emptyLine(defaultCategory: string): LineForm {
    return {
        uid: nextUid(),
        id: null,
        category: defaultCategory,
        description: '',
        amount: '',
        spent_at: new Date().toISOString().slice(0, 10),
        receipt: null,
        existing_receipt_name: null,
        existing_receipt_url: null,
    };
}

export function ExpenseReportForm({
    categories,
    report = null,
    onCancel,
}: Props) {
    const isEditing = report !== null;
    const { symbol: currencySymbol } = useCompanyCurrency();
    const defaultCategory = categories[0]?.value ?? 'other';
    const fileInputs = useRef<Record<string, HTMLInputElement | null>>({});

    const form = useForm({
        title: report?.title ?? '',
        lines:
            report && report.lines.length > 0
                ? report.lines.map(
                      (line): LineForm => ({
                          uid: nextUid(),
                          id: line.id,
                          category: line.category,
                          description: line.description,
                          amount: String(line.amount),
                          spent_at: line.spent_at ?? '',
                          receipt: null,
                          existing_receipt_name: line.receipt_name,
                          existing_receipt_url: line.receipt_url,
                      }),
                  )
                : [emptyLine(defaultCategory)],
    });

    const lines = form.data.lines as LineForm[];
    const lineErrors = form.errors as Record<string, string>;

    function setLines(next: LineForm[]) {
        form.setData('lines', next);
    }

    function updateLine(index: number, patch: Partial<LineForm>) {
        setLines(
            lines.map((line, i) => (i === index ? { ...line, ...patch } : line)),
        );
    }

    function addLine() {
        setLines([...lines, emptyLine(defaultCategory)]);
    }

    function removeLine(index: number) {
        if (lines.length === 1) {
            return;
        }

        setLines(lines.filter((_, i) => i !== index));
    }

    function clearReceipt(index: number, uid: string) {
        updateLine(index, { receipt: null });
        const input = fileInputs.current[uid];
        if (input) {
            input.value = '';
        }
    }

    const total = lines.reduce(
        (sum, line) => sum + (Number(line.amount) || 0),
        0,
    );

    function submit(event: FormEvent) {
        event.preventDefault();

        if (isEditing && report) {
            form.transform((data) => ({ ...data, _method: 'put' }));
            form.post(ExpenseReportController.update.url(report.id), {
                forceFormData: true,
            });

            return;
        }

        form.post(ExpenseReportController.store.url(), {
            forceFormData: true,
        });
    }

    return (
        <form onSubmit={submit}>
            <div className="grid gap-6 lg:grid-cols-3">
                <div className="space-y-6 lg:col-span-2">
                    <Card>
                        <CardHeader>
                            <CardTitle>Informations générales</CardTitle>
                            <CardDescription>
                                Donnez un objet clair à votre note de frais.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            {isEditing && report && (
                                <div className="grid max-w-xs gap-2">
                                    <Label htmlFor="er-code">Référence</Label>
                                    <Input
                                        id="er-code"
                                        value={report.code}
                                        disabled
                                        readOnly
                                        className="font-mono"
                                    />
                                </div>
                            )}

                            <div className="grid gap-2">
                                <Label htmlFor="er-title">
                                    Objet de la note
                                </Label>
                                <Input
                                    id="er-title"
                                    placeholder="Ex. Déplacement client — Paris"
                                    value={form.data.title}
                                    onChange={(event) =>
                                        form.setData('title', event.target.value)
                                    }
                                    required
                                    autoFocus
                                />
                                <InputError message={form.errors.title} />
                            </div>
                        </CardContent>
                    </Card>

                    <Card>
                        <CardHeader className="flex-row items-center justify-between space-y-0">
                            <div className="space-y-1.5">
                                <CardTitle>Dépenses</CardTitle>
                                <CardDescription>
                                    {lines.length}{' '}
                                    {lines.length > 1 ? 'lignes' : 'ligne'} ·
                                    ajoutez un justificatif pour chaque dépense.
                                </CardDescription>
                            </div>
                            <Button
                                type="button"
                                variant="outline"
                                size="sm"
                                onClick={addLine}
                            >
                                <Plus />
                                Ajouter
                            </Button>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            {lines.map((line, index) => {
                                return (
                                    <div
                                        key={line.uid}
                                        className="overflow-hidden rounded-xl border bg-background"
                                    >
                                        <div className="flex items-center justify-between gap-2 border-b bg-muted/40 px-4 py-2.5">
                                            <div className="flex items-center gap-2.5">
                                                <span className="flex size-6 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary">
                                                    {index + 1}
                                                </span>
                                                <span className="text-sm font-medium">
                                                    {Number(line.amount) > 0
                                                        ? formatCurrency(
                                                              Number(
                                                                  line.amount,
                                                              ),
                                                          )
                                                        : 'Nouvelle dépense'}
                                                </span>
                                            </div>
                                            <Button
                                                type="button"
                                                variant="ghost"
                                                size="icon"
                                                className="size-8 text-muted-foreground hover:text-destructive"
                                                onClick={() => removeLine(index)}
                                                disabled={lines.length === 1}
                                                aria-label="Supprimer la dépense"
                                            >
                                                <Trash2 />
                                            </Button>
                                        </div>

                                        <div className="grid gap-4 p-4 sm:grid-cols-2">
                                            <div className="grid gap-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Catégorie
                                                </Label>
                                                <Select
                                                    value={line.category}
                                                    onValueChange={(value) =>
                                                        updateLine(index, {
                                                            category: value,
                                                        })
                                                    }
                                                >
                                                    <SelectTrigger className="w-full">
                                                        <SelectValue />
                                                    </SelectTrigger>
                                                    <SelectContent>
                                                        {categories.map(
                                                            (category) => (
                                                                <SelectItem
                                                                    key={
                                                                        category.value
                                                                    }
                                                                    value={
                                                                        category.value
                                                                    }
                                                                >
                                                                    {
                                                                        category.label
                                                                    }
                                                                </SelectItem>
                                                            ),
                                                        )}
                                                    </SelectContent>
                                                </Select>
                                            </div>

                                            <div className="grid gap-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Date de la dépense
                                                </Label>
                                                <Input
                                                    type="date"
                                                    value={line.spent_at}
                                                    onChange={(event) =>
                                                        updateLine(index, {
                                                            spent_at:
                                                                event.target
                                                                    .value,
                                                        })
                                                    }
                                                    required
                                                />
                                            </div>

                                            <div className="grid gap-2 sm:col-span-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Description
                                                </Label>
                                                <Input
                                                    placeholder="Ex. Billet de train aller-retour"
                                                    value={line.description}
                                                    onChange={(event) =>
                                                        updateLine(index, {
                                                            description:
                                                                event.target
                                                                    .value,
                                                        })
                                                    }
                                                    required
                                                />
                                            </div>

                                            <div className="grid gap-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Montant ({currencySymbol})
                                                </Label>
                                                <Input
                                                    type="number"
                                                    step="1"
                                                    min="1"
                                                    inputMode="numeric"
                                                    placeholder="0"
                                                    value={line.amount}
                                                    onChange={(event) =>
                                                        updateLine(index, {
                                                            amount: event.target
                                                                .value,
                                                        })
                                                    }
                                                    required
                                                />
                                            </div>

                                            <div className="grid gap-2 sm:col-span-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Justificatif (photo / scan)
                                                    <span className="ml-0.5 text-destructive">
                                                        *
                                                    </span>
                                                </Label>

                                                {line.receipt ? (
                                                    <div className="flex items-center justify-between gap-2 rounded-lg border bg-muted/40 px-3 py-2">
                                                        <span className="flex min-w-0 items-center gap-2 text-sm">
                                                            <Paperclip className="size-4 shrink-0 text-muted-foreground" />
                                                            <span className="truncate">
                                                                {
                                                                    line.receipt
                                                                        .name
                                                                }
                                                            </span>
                                                        </span>
                                                        <Button
                                                            type="button"
                                                            variant="ghost"
                                                            size="icon"
                                                            className="size-7 shrink-0"
                                                            onClick={() =>
                                                                clearReceipt(
                                                                    index,
                                                                    line.uid,
                                                                )
                                                            }
                                                            aria-label="Retirer le fichier"
                                                        >
                                                            <X />
                                                        </Button>
                                                    </div>
                                                ) : (
                                                    <label
                                                        htmlFor={`receipt-${line.uid}`}
                                                        className="flex cursor-pointer items-center gap-3 rounded-lg border border-dashed px-3 py-2.5 text-sm text-muted-foreground transition-colors hover:border-primary/50 hover:bg-muted/40"
                                                    >
                                                        <Upload className="size-4 shrink-0" />
                                                        <span>
                                                            Cliquez pour
                                                            téléverser un fichier
                                                            (JPG, PNG, PDF)
                                                        </span>
                                                    </label>
                                                )}

                                                <input
                                                    ref={(el) => {
                                                        fileInputs.current[
                                                            line.uid
                                                        ] = el;
                                                    }}
                                                    id={`receipt-${line.uid}`}
                                                    type="file"
                                                    className="hidden"
                                                    accept=".jpg,.jpeg,.png,.pdf"
                                                    onChange={(event) =>
                                                        updateLine(index, {
                                                            receipt:
                                                                event.target
                                                                    .files?.[0] ??
                                                                null,
                                                        })
                                                    }
                                                />

                                                {line.existing_receipt_url &&
                                                    !line.receipt && (
                                                        <a
                                                            href={
                                                                line.existing_receipt_url
                                                            }
                                                            target="_blank"
                                                            rel="noopener noreferrer"
                                                            className="inline-flex items-center gap-1.5 text-sm text-primary underline-offset-4 hover:underline"
                                                        >
                                                            <Paperclip className="size-3.5" />
                                                            {line.existing_receipt_name ??
                                                                'Justificatif actuel'}
                                                        </a>
                                                    )}

                                                <InputError
                                                    message={
                                                        lineErrors[
                                                            `lines.${index}.receipt`
                                                        ]
                                                    }
                                                />
                                            </div>
                                        </div>
                                    </div>
                                );
                            })}

                            <InputError message={form.errors.lines} />

                            <Button
                                type="button"
                                variant="ghost"
                                className="w-full border border-dashed text-muted-foreground hover:text-foreground"
                                onClick={addLine}
                            >
                                <Plus />
                                Ajouter une dépense
                            </Button>
                        </CardContent>
                    </Card>
                </div>

                <div className="lg:col-span-1">
                    <Card className="lg:sticky lg:top-6">
                        <CardHeader>
                            <CardTitle>Récapitulatif</CardTitle>
                            <CardDescription>
                                Vérifiez le total avant d'enregistrer.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            <div className="flex items-center justify-between text-sm">
                                <span className="text-muted-foreground">
                                    Nombre de dépenses
                                </span>
                                <span className="font-medium tabular-nums">
                                    {lines.length}
                                </span>
                            </div>
                            <div className="flex items-center justify-between border-t pt-4">
                                <span className="text-sm font-medium">
                                    Total
                                </span>
                                <span className="text-xl font-semibold tabular-nums">
                                    {formatCurrency(total)}
                                </span>
                            </div>

                            <div className="flex flex-col gap-2 pt-2">
                                <Button
                                    type="submit"
                                    disabled={form.processing}
                                >
                                    {isEditing
                                        ? 'Enregistrer les modifications'
                                        : 'Créer la note de frais'}
                                </Button>
                                <Button
                                    type="button"
                                    variant="outline"
                                    onClick={onCancel}
                                >
                                    Annuler
                                </Button>
                            </div>
                        </CardContent>
                    </Card>
                </div>
            </div>
        </form>
    );
}
