import { useForm } from '@inertiajs/react';
import {
    AlertTriangle,
    ClipboardCheck,
    Package,
    Plus,
    Save,
    Trash2,
} from 'lucide-react';
import { useMemo, type FormEvent } from 'react';
import InventoryController from '@/actions/App/Http/Controllers/Admin/InventoryController';
import InputError from '@/components/input-error';
import { Badge } from '@/components/ui/badge';
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 { Textarea } from '@/components/ui/textarea';
import { formatDate } from '@/lib/utils';

export type ProductOption = { id: number; code: string; name: string };

type InventoryLine = {
    id: number;
    product: { id: number; code: string; name: string } | null;
    theoretical_quantity: number;
    actual_quantity: number | null;
    variance: number | null;
    justification: string | null;
};

type LineForm = {
    uid: string;
    product_id: string;
    theoretical_quantity: number;
    isExisting: boolean;
    actual_quantity: string;
    justification: string;
};

type Props = {
    inventoryId: number;
    countedAt: string;
    notes: string | null;
    lines: InventoryLine[];
    products: ProductOption[];
    canClose: boolean;
    canCancel: boolean;
    onCancelInventory: () => void;
};

let uidCounter = 0;

function nextUid(): string {
    uidCounter += 1;

    return `inventory-line-${uidCounter}`;
}

function lineToForm(line: InventoryLine): LineForm {
    return {
        uid: nextUid(),
        product_id: line.product ? String(line.product.id) : '',
        theoretical_quantity: line.theoretical_quantity,
        isExisting: true,
        actual_quantity:
            line.actual_quantity === null ? '' : String(line.actual_quantity),
        justification: line.justification ?? '',
    };
}

function emptyLine(): LineForm {
    return {
        uid: nextUid(),
        product_id: '',
        theoretical_quantity: 0,
        isExisting: false,
        actual_quantity: '0',
        justification: '',
    };
}

function buildPayload(data: {
    counted_at: string;
    notes: string;
    lines: LineForm[];
}) {
    return {
        counted_at: data.counted_at,
        notes: data.notes || null,
        lines: data.lines
            .filter((line) => line.product_id !== '')
            .map((line) => ({
                product_id: Number(line.product_id),
                actual_quantity:
                    line.actual_quantity === ''
                        ? null
                        : Number(line.actual_quantity),
                justification: line.justification || null,
            })),
    };
}

export function StockInventoryForm({
    inventoryId,
    countedAt,
    notes,
    lines: initialLines,
    products,
    canClose,
    canCancel,
    onCancelInventory,
}: Props) {
    const form = useForm({
        counted_at: countedAt,
        notes: notes ?? '',
        lines:
            initialLines.length > 0
                ? initialLines.map(lineToForm)
                : [emptyLine()],
    });

    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()]);
    }

    function removeLine(index: number) {
        const line = lines[index];

        if (line.isExisting) {
            return;
        }

        if (lines.length === 1) {
            return;
        }

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

    function availableProducts(currentLineIndex: number): ProductOption[] {
        const usedIds = new Set(
            lines
                .filter((_, index) => index !== currentLineIndex)
                .map((line) => line.product_id)
                .filter(Boolean),
        );

        return products.filter(
            (product) => !usedIds.has(String(product.id)),
        );
    }

    const stats = useMemo(() => {
        const filled = lines.filter((line) => line.product_id !== '');
        let varianceCount = 0;
        let adjustedUnits = 0;

        for (const line of filled) {
            if (line.actual_quantity === '') {
                continue;
            }

            const actual = Number(line.actual_quantity);
            const variance = actual - line.theoretical_quantity;

            if (variance !== 0) {
                varianceCount += 1;
                adjustedUnits += Math.abs(variance);
            }
        }

        return {
            filledCount: filled.length,
            varianceCount,
            adjustedUnits,
        };
    }, [lines]);

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

        form.transform((data) => buildPayload(data as typeof form.data));

        form.put(InventoryController.update.url(inventoryId), {
            preserveScroll: true,
        });
    }

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

        form.transform((data) => ({
            ...buildPayload(data as typeof form.data),
            lines: (data.lines as LineForm[])
                .filter((line) => line.product_id !== '')
                .map((line) => ({
                    product_id: Number(line.product_id),
                    actual_quantity: Number(line.actual_quantity || 0),
                    justification: line.justification || null,
                })),
        }));

        form.post(InventoryController.close.url(inventoryId), {
            preserveScroll: true,
        });
    }

    return (
        <form onSubmit={saveDraft}>
            <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>
                                Date de l&apos;inventaire physique et notes
                                associées.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            <div className="grid gap-4 sm:grid-cols-2">
                                <div className="grid gap-2">
                                    <Label htmlFor="counted_at">
                                        Date d&apos;inventaire
                                        <span className="ml-0.5 text-destructive">
                                            *
                                        </span>
                                    </Label>
                                    <Input
                                        id="counted_at"
                                        type="date"
                                        value={form.data.counted_at}
                                        onChange={(event) =>
                                            form.setData(
                                                'counted_at',
                                                event.target.value,
                                            )
                                        }
                                        required
                                    />
                                    <InputError
                                        message={form.errors.counted_at}
                                    />
                                </div>
                            </div>

                            <div className="grid gap-2">
                                <Label htmlFor="notes">Notes</Label>
                                <Textarea
                                    id="notes"
                                    rows={3}
                                    placeholder="Contexte, zone comptée, remarques… (optionnel)"
                                    value={form.data.notes}
                                    onChange={(event) =>
                                        form.setData(
                                            'notes',
                                            event.target.value,
                                        )
                                    }
                                />
                                <InputError message={form.errors.notes} />
                            </div>
                        </CardContent>
                    </Card>

                    <Card>
                        <CardHeader className="flex-row items-center justify-between space-y-0">
                            <div className="space-y-1.5">
                                <CardTitle>Comptage produits</CardTitle>
                                <CardDescription>
                                    Comparez le stock théorique au stock réel
                                    compté. Justifiez chaque écart avant
                                    validation.
                                </CardDescription>
                            </div>
                            <Button
                                type="button"
                                variant="outline"
                                size="sm"
                                onClick={addLine}
                                disabled={products.length === 0}
                            >
                                <Plus />
                                Ajouter
                            </Button>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            {lines.map((line, index) => {
                                const product = products.find(
                                    (item) =>
                                        String(item.id) === line.product_id,
                                );
                                const actual =
                                    line.actual_quantity === ''
                                        ? null
                                        : Number(line.actual_quantity);
                                const variance =
                                    actual === null
                                        ? null
                                        : actual - line.theoretical_quantity;
                                const hasVariance =
                                    variance !== null && variance !== 0;

                                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 min-w-0 items-center gap-2.5">
                                                <span className="flex size-6 shrink-0 items-center justify-center rounded-full bg-primary/10 text-xs font-semibold text-primary">
                                                    {index + 1}
                                                </span>
                                                <span className="truncate text-sm font-medium">
                                                    {product
                                                        ? `${product.code} — ${product.name}`
                                                        : 'Nouvelle ligne'}
                                                </span>
                                                {hasVariance && (
                                                    <Badge
                                                        variant="secondary"
                                                        className="shrink-0"
                                                    >
                                                        Écart{' '}
                                                        {variance > 0
                                                            ? '+'
                                                            : ''}
                                                        {variance}
                                                    </Badge>
                                                )}
                                            </div>
                                            {!line.isExisting && (
                                                <Button
                                                    type="button"
                                                    variant="ghost"
                                                    size="icon"
                                                    className="size-8 shrink-0 text-muted-foreground hover:text-destructive"
                                                    onClick={() =>
                                                        removeLine(index)
                                                    }
                                                    disabled={
                                                        lines.length === 1
                                                    }
                                                    aria-label="Supprimer la ligne"
                                                >
                                                    <Trash2 />
                                                </Button>
                                            )}
                                        </div>

                                        <div className="grid gap-4 p-4 sm:grid-cols-2">
                                            {!line.isExisting ? (
                                                <div className="grid gap-2 sm:col-span-2">
                                                    <Label className="text-xs text-muted-foreground">
                                                        Produit
                                                        <span className="ml-0.5 text-destructive">
                                                            *
                                                        </span>
                                                    </Label>
                                                    <Select
                                                        value={
                                                            line.product_id ||
                                                            undefined
                                                        }
                                                        onValueChange={(
                                                            value,
                                                        ) =>
                                                            updateLine(index, {
                                                                product_id:
                                                                    value,
                                                            })
                                                        }
                                                    >
                                                        <SelectTrigger>
                                                            <SelectValue placeholder="Sélectionner un produit" />
                                                        </SelectTrigger>
                                                        <SelectContent>
                                                            {availableProducts(
                                                                index,
                                                            ).map((item) => (
                                                                <SelectItem
                                                                    key={
                                                                        item.id
                                                                    }
                                                                    value={String(
                                                                        item.id,
                                                                    )}
                                                                >
                                                                    {item.code}{' '}
                                                                    — {item.name}
                                                                </SelectItem>
                                                            ))}
                                                        </SelectContent>
                                                    </Select>
                                                    <InputError
                                                        message={
                                                            lineErrors[
                                                                `lines.${index}.product_id`
                                                            ]
                                                        }
                                                    />
                                                </div>
                                            ) : null}

                                            <div className="grid gap-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Stock théorique
                                                </Label>
                                                <Input
                                                    value={
                                                        line.theoretical_quantity
                                                    }
                                                    disabled
                                                    className="bg-muted/50"
                                                />
                                            </div>

                                            <div className="grid gap-2">
                                                <Label className="text-xs text-muted-foreground">
                                                    Stock réel
                                                    <span className="ml-0.5 text-destructive">
                                                        *
                                                    </span>
                                                </Label>
                                                <Input
                                                    type="number"
                                                    min={0}
                                                    value={line.actual_quantity}
                                                    onChange={(event) =>
                                                        updateLine(index, {
                                                            actual_quantity:
                                                                event.target
                                                                    .value,
                                                        })
                                                    }
                                                />
                                                <InputError
                                                    message={
                                                        lineErrors[
                                                            `lines.${index}.actual_quantity`
                                                        ]
                                                    }
                                                />
                                            </div>

                                            {hasVariance ? (
                                                <div className="grid gap-2 sm:col-span-2">
                                                    <Label className="text-xs text-muted-foreground">
                                                        Justification de
                                                        l&apos;écart
                                                        <span className="ml-0.5 text-destructive">
                                                            *
                                                        </span>
                                                    </Label>
                                                    <Textarea
                                                        rows={2}
                                                        placeholder="Expliquez la cause de l'écart (casse, erreur de saisie, produit manquant…)"
                                                        value={
                                                            line.justification
                                                        }
                                                        onChange={(event) =>
                                                            updateLine(index, {
                                                                justification:
                                                                    event.target
                                                                        .value,
                                                            })
                                                        }
                                                    />
                                                    <InputError
                                                        message={
                                                            lineErrors[
                                                                `lines.${index}.justification`
                                                            ]
                                                        }
                                                    />
                                                </div>
                                            ) : null}
                                        </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 un produit
                            </Button>
                        </CardContent>
                    </Card>
                </div>

                <div className="space-y-6 lg:col-span-1">
                    <Card className="lg:sticky lg:top-6">
                        <CardHeader>
                            <CardTitle>Récapitulatif</CardTitle>
                            <CardDescription>
                                Vérifiez les écarts avant de clôturer le
                                constat.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            <div className="flex items-center justify-between gap-4 text-sm">
                                <span className="text-muted-foreground">
                                    Date
                                </span>
                                <span className="font-medium tabular-nums">
                                    {form.data.counted_at
                                        ? formatDate(form.data.counted_at)
                                        : '—'}
                                </span>
                            </div>
                            <div className="flex items-center justify-between text-sm">
                                <span className="text-muted-foreground">
                                    Produits comptés
                                </span>
                                <span className="flex items-center gap-1.5 font-medium tabular-nums">
                                    <Package className="size-4 text-muted-foreground" />
                                    {stats.filledCount}
                                </span>
                            </div>
                            <div className="flex items-center justify-between text-sm">
                                <span className="text-muted-foreground">
                                    Écarts détectés
                                </span>
                                <span className="flex items-center gap-1.5 font-medium tabular-nums">
                                    <AlertTriangle className="size-4 text-amber-500" />
                                    {stats.varianceCount}
                                </span>
                            </div>
                            <div className="flex items-center justify-between border-t pt-4">
                                <span className="text-sm font-medium">
                                    Unités à ajuster
                                </span>
                                <span className="text-xl font-semibold tabular-nums">
                                    {stats.adjustedUnits}
                                </span>
                            </div>

                            <div className="space-y-2 border-t pt-4">
                                <Button
                                    type="submit"
                                    className="w-full"
                                    disabled={form.processing}
                                >
                                    <Save />
                                    Enregistrer le brouillon
                                </Button>
                                {canClose && (
                                    <Button
                                        type="button"
                                        variant="default"
                                        className="w-full"
                                        disabled={form.processing}
                                        onClick={closeInventory}
                                    >
                                        <ClipboardCheck />
                                        Clôturer le constat
                                    </Button>
                                )}
                                {canCancel && (
                                    <Button
                                        type="button"
                                        variant="outline"
                                        className="w-full text-destructive hover:text-destructive"
                                        disabled={form.processing}
                                        onClick={onCancelInventory}
                                    >
                                        Annuler l&apos;inventaire
                                    </Button>
                                )}
                            </div>
                        </CardContent>
                    </Card>
                </div>
            </div>
        </form>
    );
}
