import { useForm } from '@inertiajs/react';
import { ArrowDownToLine, Package, Plus, Trash2 } from 'lucide-react';
import { useMemo, type FormEvent } from 'react';
import StockReturnController from '@/actions/App/Http/Controllers/Admin/StockReturnController';
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 { Textarea } from '@/components/ui/textarea';
import { formatDate } from '@/lib/utils';

export type ProductOption = { id: number; code: string; name: string };
export type WarehouseOption = { id: number; code: string; name: string };
export type TypeOption = { value: string; label: string };

type LineForm = {
    uid: string;
    product_id: string;
    quantity: string;
};

type Props = {
    warehouses: WarehouseOption[];
    products: ProductOption[];
    types: TypeOption[];
    stocksByWarehouse: Record<string, Record<string, number>>;
    onCancel: () => void;
};

let uidCounter = 0;

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

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

function emptyLine(): LineForm {
    return {
        uid: nextUid(),
        product_id: '',
        quantity: '1',
    };
}

export function StockReturnForm({
    warehouses,
    products,
    types,
    stocksByWarehouse,
    onCancel,
}: Props) {
    const form = useForm({
        warehouse_id: '',
        type: 'client',
        returned_at: new Date().toISOString().slice(0, 10),
        motif: '',
        notes: '',
        lines: [emptyLine()],
    });

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

    const warehouseStocks = useMemo(
        () => stocksByWarehouse[form.data.warehouse_id] ?? {},
        [stocksByWarehouse, form.data.warehouse_id],
    );

    // For a supplier return, only products currently in stock can be sent
    // back. For a client return, any product can be received back.
    const selectableProducts = useMemo(
        () =>
            isSupplierReturn
                ? products.filter((product) =>
                      Object.prototype.hasOwnProperty.call(
                          warehouseStocks,
                          String(product.id),
                      ),
                  )
                : products,
        [products, warehouseStocks, isSupplierReturn],
    );

    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) {
        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 selectableProducts.filter(
            (product) => !usedIds.has(String(product.id)),
        );
    }

    const filledLines = useMemo(
        () =>
            lines.filter(
                (line) =>
                    line.product_id !== '' && Number(line.quantity) > 0,
            ),
        [lines],
    );

    const totalQuantity = filledLines.reduce(
        (sum, line) => sum + (Number(line.quantity) || 0),
        0,
    );

    const canSubmit =
        filledLines.length > 0 &&
        form.data.warehouse_id !== '' &&
        form.data.motif.trim() !== '' &&
        !form.processing;

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

        form.transform((data) => ({
            warehouse_id: Number(data.warehouse_id),
            type: data.type,
            returned_at: data.returned_at,
            motif: data.motif,
            notes: data.notes || null,
            lines: (data.lines as LineForm[])
                .filter((line) => line.product_id !== '')
                .map((line) => ({
                    product_id: Number(line.product_id),
                    quantity: Number(line.quantity),
                })),
        }));

        form.post(StockReturnController.store.url());
    }

    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>
                                Type de retour, entrepôt, date et motif.
                            </CardDescription>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            <div className="grid gap-4 sm:grid-cols-2">
                                <div className="grid gap-2">
                                    <Label>
                                        Type
                                        <span className="ml-0.5 text-destructive">
                                            *
                                        </span>
                                    </Label>
                                    <Select
                                        value={form.data.type}
                                        onValueChange={(value) => {
                                            form.setData('type', value);
                                            form.setData('lines', [
                                                emptyLine(),
                                            ]);
                                        }}
                                    >
                                        <SelectTrigger>
                                            <SelectValue />
                                        </SelectTrigger>
                                        <SelectContent>
                                            {types.map((type) => (
                                                <SelectItem
                                                    key={type.value}
                                                    value={type.value}
                                                >
                                                    {type.label}
                                                </SelectItem>
                                            ))}
                                        </SelectContent>
                                    </Select>
                                    <InputError message={form.errors.type} />
                                </div>

                                <div className="grid gap-2">
                                    <Label htmlFor="returned_at">
                                        Date de retour
                                        <span className="ml-0.5 text-destructive">
                                            *
                                        </span>
                                    </Label>
                                    <Input
                                        id="returned_at"
                                        type="date"
                                        value={form.data.returned_at}
                                        onChange={(event) =>
                                            form.setData(
                                                'returned_at',
                                                event.target.value,
                                            )
                                        }
                                        required
                                    />
                                    <InputError
                                        message={form.errors.returned_at}
                                    />
                                </div>

                                <div className="grid gap-2 sm:col-span-2">
                                    <Label>
                                        Entrepôt
                                        <span className="ml-0.5 text-destructive">
                                            *
                                        </span>
                                    </Label>
                                    <Select
                                        value={
                                            form.data.warehouse_id || undefined
                                        }
                                        onValueChange={(value) => {
                                            form.setData('warehouse_id', value);
                                            form.setData('lines', [
                                                emptyLine(),
                                            ]);
                                        }}
                                    >
                                        <SelectTrigger>
                                            <SelectValue placeholder="Sélectionner un entrepôt" />
                                        </SelectTrigger>
                                        <SelectContent>
                                            {warehouses.map((warehouse) => (
                                                <SelectItem
                                                    key={warehouse.id}
                                                    value={String(warehouse.id)}
                                                >
                                                    {warehouse.code} —{' '}
                                                    {warehouse.name}
                                                </SelectItem>
                                            ))}
                                        </SelectContent>
                                    </Select>
                                    <InputError
                                        message={form.errors.warehouse_id}
                                    />
                                </div>
                            </div>

                            <div className="grid gap-2">
                                <Label htmlFor="motif">
                                    Motif du retour
                                    <span className="ml-0.5 text-destructive">
                                        *
                                    </span>
                                </Label>
                                <Input
                                    id="motif"
                                    placeholder="Ex : produit défectueux, erreur de livraison…"
                                    value={form.data.motif}
                                    onChange={(event) =>
                                        form.setData(
                                            'motif',
                                            event.target.value,
                                        )
                                    }
                                    required
                                />
                                <InputError message={form.errors.motif} />
                            </div>

                            <div className="grid gap-2">
                                <Label htmlFor="notes">Notes</Label>
                                <Textarea
                                    id="notes"
                                    rows={3}
                                    placeholder="Remarques complémentaires… (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>Produits retournés</CardTitle>
                                <CardDescription>
                                    {isSupplierReturn
                                        ? "Seuls les produits en stock dans l'entrepôt sont proposés."
                                        : 'Tous les produits sont proposés.'}
                                </CardDescription>
                            </div>
                            <Button
                                type="button"
                                variant="outline"
                                size="sm"
                                onClick={addLine}
                                disabled={
                                    form.data.warehouse_id === '' ||
                                    selectableProducts.length === 0
                                }
                            >
                                <Plus />
                                Ajouter
                            </Button>
                        </CardHeader>
                        <CardContent className="space-y-4">
                            {form.data.warehouse_id === '' ? (
                                <p className="text-muted-foreground rounded-lg border border-dashed py-8 text-center text-sm">
                                    Sélectionnez d&apos;abord un entrepôt.
                                </p>
                            ) : selectableProducts.length === 0 ? (
                                <p className="text-muted-foreground rounded-lg border border-dashed py-8 text-center text-sm">
                                    Aucun produit en stock dans cet entrepôt.
                                </p>
                            ) : (
                                <>
                                    {lines.map((line, index) => {
                                        const product = products.find(
                                            (item) =>
                                                String(item.id) ===
                                                line.product_id,
                                        );
                                        const available =
                                            isSupplierReturn &&
                                            line.product_id !== ''
                                                ? (warehouseStocks[
                                                      line.product_id
                                                  ] ?? 0)
                                                : null;

                                        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>
                                                    </div>
                                                    <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-[minmax(0,1fr)_6.5rem]">
                                                    <div className="grid gap-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
                                                                            }
                                                                            {isSupplierReturn
                                                                                ? ` (stock: ${warehouseStocks[String(item.id)] ?? 0})`
                                                                                : ''}
                                                                        </SelectItem>
                                                                    ),
                                                                )}
                                                            </SelectContent>
                                                        </Select>
                                                        <InputError
                                                            message={
                                                                lineErrors[
                                                                    `lines.${index}.product_id`
                                                                ]
                                                            }
                                                        />
                                                    </div>

                                                    <div className="grid gap-2">
                                                        <Label className="text-xs text-muted-foreground">
                                                            Quantité
                                                            <span className="ml-0.5 text-destructive">
                                                                *
                                                            </span>
                                                        </Label>
                                                        <Input
                                                            type="number"
                                                            min={1}
                                                            max={
                                                                available ??
                                                                undefined
                                                            }
                                                            value={
                                                                line.quantity
                                                            }
                                                            onChange={(
                                                                event,
                                                            ) =>
                                                                updateLine(
                                                                    index,
                                                                    {
                                                                        quantity:
                                                                            event
                                                                                .target
                                                                                .value,
                                                                    },
                                                                )
                                                            }
                                                            required
                                                        />
                                                        {available !==
                                                            null && (
                                                            <p className="text-muted-foreground text-xs">
                                                                Dispo :{' '}
                                                                {available}
                                                            </p>
                                                        )}
                                                        <InputError
                                                            message={
                                                                lineErrors[
                                                                    `lines.${index}.quantity`
                                                                ]
                                                            }
                                                        />
                                                    </div>
                                                </div>
                                            </div>
                                        );
                                    })}

                                    <InputError message={form.errors.lines} />
                                </>
                            )}
                        </CardContent>
                    </Card>
                </div>

                <div className="lg:col-span-1">
                    <Card className="lg:sticky lg:top-6">
                        <CardHeader>
                            <CardTitle>Récapitulatif</CardTitle>
                            <CardDescription>
                                {isSupplierReturn
                                    ? 'Le retour diminuera immédiatement le stock.'
                                    : "Le retour augmentera immédiatement le stock de l'entrepôt."}
                            </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.returned_at
                                        ? formatDate(form.data.returned_at)
                                        : '—'}
                                </span>
                            </div>
                            <div className="flex items-center justify-between text-sm">
                                <span className="text-muted-foreground">
                                    Produits
                                </span>
                                <span className="flex items-center gap-1.5 font-medium tabular-nums">
                                    <Package className="size-4 text-muted-foreground" />
                                    {filledLines.length}
                                </span>
                            </div>
                            <div className="flex items-center justify-between border-t pt-4">
                                <span className="text-sm font-medium">
                                    Total unités
                                </span>
                                <span className="text-xl font-semibold tabular-nums">
                                    {totalQuantity}
                                </span>
                            </div>

                            <div className="space-y-2 border-t pt-4">
                                <Button
                                    type="submit"
                                    className="w-full"
                                    disabled={!canSubmit}
                                >
                                    <ArrowDownToLine />
                                    Enregistrer le retour
                                </Button>
                                <Button
                                    type="button"
                                    variant="outline"
                                    className="w-full"
                                    onClick={onCancel}
                                    disabled={form.processing}
                                >
                                    Annuler
                                </Button>
                            </div>
                        </CardContent>
                    </Card>
                </div>
            </div>
        </form>
    );
}
