import { useForm } from '@inertiajs/react';
import { ArrowUpFromLine, Package, Plus, Trash2 } from 'lucide-react';
import { useMemo, type FormEvent } from 'react';
import StockExitController from '@/actions/App/Http/Controllers/Admin/StockExitController';
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 `exit-line-${uidCounter}`;
}

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

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

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

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

    const productsInStock = useMemo(
        () =>
            products.filter((product) =>
                Object.prototype.hasOwnProperty.call(
                    warehouseStocks,
                    String(product.id),
                ),
            ),
        [products, warehouseStocks],
    );

    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 productsInStock.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 !== '' &&
        (!isTransfer || form.data.destination_warehouse_id !== '') &&
        !form.processing;

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

        form.transform((data) => ({
            warehouse_id: Number(data.warehouse_id),
            destination_warehouse_id:
                data.type === 'transfer' && data.destination_warehouse_id
                    ? Number(data.destination_warehouse_id)
                    : null,
            type: data.type,
            exited_at: data.exited_at,
            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(StockExitController.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 sortie, entrepôt et date.
                            </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);
                                            if (value !== 'transfer') {
                                                form.setData(
                                                    'destination_warehouse_id',
                                                    '',
                                                );
                                            }
                                        }}
                                    >
                                        <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="exited_at">
                                        Date de sortie
                                        <span className="ml-0.5 text-destructive">
                                            *
                                        </span>
                                    </Label>
                                    <Input
                                        id="exited_at"
                                        type="date"
                                        value={form.data.exited_at}
                                        onChange={(event) =>
                                            form.setData(
                                                'exited_at',
                                                event.target.value,
                                            )
                                        }
                                        required
                                    />
                                    <InputError
                                        message={form.errors.exited_at}
                                    />
                                </div>

                                <div className="grid gap-2">
                                    <Label>
                                        Entrepôt source
                                        <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()]);
                                            if (
                                                form.data
                                                    .destination_warehouse_id ===
                                                value
                                            ) {
                                                form.setData(
                                                    'destination_warehouse_id',
                                                    '',
                                                );
                                            }
                                        }}
                                    >
                                        <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>

                                {isTransfer && (
                                    <div className="grid gap-2">
                                        <Label>
                                            Entrepôt destination
                                            <span className="ml-0.5 text-destructive">
                                                *
                                            </span>
                                        </Label>
                                        <Select
                                            value={
                                                form.data
                                                    .destination_warehouse_id ||
                                                undefined
                                            }
                                            onValueChange={(value) =>
                                                form.setData(
                                                    'destination_warehouse_id',
                                                    value,
                                                )
                                            }
                                        >
                                            <SelectTrigger>
                                                <SelectValue placeholder="Sélectionner la destination" />
                                            </SelectTrigger>
                                            <SelectContent>
                                                {warehouses
                                                    .filter(
                                                        (warehouse) =>
                                                            String(
                                                                warehouse.id,
                                                            ) !==
                                                            form.data
                                                                .warehouse_id,
                                                    )
                                                    .map((warehouse) => (
                                                        <SelectItem
                                                            key={warehouse.id}
                                                            value={String(
                                                                warehouse.id,
                                                            )}
                                                        >
                                                            {warehouse.code} —{' '}
                                                            {warehouse.name}
                                                        </SelectItem>
                                                    ))}
                                            </SelectContent>
                                        </Select>
                                        <InputError
                                            message={
                                                form.errors
                                                    .destination_warehouse_id
                                            }
                                        />
                                    </div>
                                )}
                            </div>

                            <div className="grid gap-2">
                                <Label htmlFor="notes">Notes</Label>
                                <Textarea
                                    id="notes"
                                    rows={3}
                                    placeholder="Motif, référence client, 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>Produits sortis</CardTitle>
                                <CardDescription>
                                    Seuls les produits en stock dans
                                    l&apos;entrepôt source sont proposés.
                                </CardDescription>
                            </div>
                            <Button
                                type="button"
                                variant="outline"
                                size="sm"
                                onClick={addLine}
                                disabled={
                                    form.data.warehouse_id === '' ||
                                    productsInStock.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
                                    source.
                                </p>
                            ) : productsInStock.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 =
                                            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
                                                                            }{' '}
                                                                            (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>
                                La sortie diminuera immédiatement le stock
                                source.
                            </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.exited_at
                                        ? formatDate(form.data.exited_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}
                                >
                                    <ArrowUpFromLine />
                                    Enregistrer la sortie
                                </Button>
                                <Button
                                    type="button"
                                    variant="outline"
                                    className="w-full"
                                    onClick={onCancel}
                                    disabled={form.processing}
                                >
                                    Annuler
                                </Button>
                            </div>
                        </CardContent>
                    </Card>
                </div>
            </div>
        </form>
    );
}
