import { Link, useForm } from '@inertiajs/react';
import { Plus, Save, Trash2 } from 'lucide-react';
import { useMemo, useState } from 'react';
import { toast } from 'sonner';
import { ConfirmActionDialog } from '@/components/confirm-action-dialog';
import { CustomerSearchSelect } from '@/components/customers/customer-search-select';
import { AppDateInput } from '@/components/ui/app-date-input';
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 {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { formatMoneyAmountOrDash } from '@/lib/dates';
import { cn } from '@/lib/utils';
import { zodErrorToNestedFieldMap } from '@/lib/zod-errors';
import {
    buildStoreCustomerOrderSchema,
    buildUpdateCustomerOrderSchema,
} from '@/validation/schemas';

function todayYmd() {
    const now = new Date();
    return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
}

const emptyItem = () => ({ factory_product_id: '', quantity: '' });

/**
 * @param {object} props
 * @param {{ factory_product_id: string, quantity: string }} props.item
 * @param {number} props.index
 * @param {Record<string, string>} props.labels
 * @param {Array<{id: number, name: string, unit_name?: string|null, stock_on_hand?: string}>} props.products
 * @param {Record<string, string>} props.errors
 * @param {boolean} props.canRemove
 * @param {'table'|'cards'} props.variant
 * @param {(index: number, field: 'factory_product_id'|'quantity', value: string) => void} props.onUpdate
 * @param {(index: number) => void} props.onRemove
 * @param {string} props.locale
 */
function CustomerOrderItemLine({
    item,
    index,
    labels,
    products,
    errors,
    canRemove,
    variant,
    onUpdate,
    onRemove,
    locale,
}) {
    const productError = errors[`items.${index}.factory_product_id`];
    const quantityError = errors[`items.${index}.quantity`];
    const selectedProduct = products.find(
        (product) => String(product.id) === String(item.factory_product_id),
    );

    const productSelect = (
        <div className="space-y-1">
            <Select
                value={item.factory_product_id || undefined}
                onValueChange={(value) => onUpdate(index, 'factory_product_id', value)}
            >
                <SelectTrigger
                    id={`customer-order-item-product-${index}`}
                    className={cn(productError && 'border-destructive', variant === 'table' && 'h-9')}
                >
                    <SelectValue placeholder={labels.productPlaceholder} />
                </SelectTrigger>
                <SelectContent>
                    {products.map((product) => (
                        <SelectItem key={product.id} value={String(product.id)}>
                            {product.name}
                            {product.unit_name ? ` (${product.unit_name})` : ''}
                        </SelectItem>
                    ))}
                </SelectContent>
            </Select>
            {productError ? <p className="text-destructive text-xs">{productError}</p> : null}
        </div>
    );

    const quantityInput = (
        <div className="space-y-1">
            <Input
                id={`customer-order-item-qty-${index}`}
                type="number"
                min="0"
                step="0.001"
                placeholder={labels.quantityPlaceholder}
                value={item.quantity}
                aria-invalid={Boolean(quantityError)}
                className={cn(quantityError && 'border-destructive', variant === 'table' && 'h-9')}
                onChange={(e) => onUpdate(index, 'quantity', e.target.value)}
            />
            {quantityError ? <p className="text-destructive text-xs">{quantityError}</p> : null}
        </div>
    );

    const stockCell = (
        <div className="border-input bg-background flex h-9 items-center rounded-md border px-3 text-sm tabular-nums">
            {selectedProduct?.stock_on_hand != null ? (
                formatMoneyAmountOrDash(selectedProduct.stock_on_hand, locale)
            ) : (
                <span className="text-muted-foreground">—</span>
            )}
        </div>
    );

    const readyToSaleCell = (
        <div className="border-input bg-background flex h-9 items-center rounded-md border px-3 text-sm tabular-nums">
            {selectedProduct?.ready_to_sale_quantity != null ? (
                formatMoneyAmountOrDash(selectedProduct.ready_to_sale_quantity, locale)
            ) : (
                <span className="text-muted-foreground">—</span>
            )}
        </div>
    );

    const removeButton = (
        <Button
            type="button"
            variant="outline"
            size="icon"
            className="size-9 shrink-0"
            disabled={!canRemove}
            onClick={() => onRemove(index)}
            aria-label={labels.removeLine}
        >
            <Trash2 className="size-4" />
        </Button>
    );

    if (variant === 'table') {
        return (
            <TableRow>
                <TableCell className="text-muted-foreground w-12 tabular-nums align-top">
                    {index + 1}
                </TableCell>
                <TableCell className="min-w-[14rem] align-top">{productSelect}</TableCell>
                <TableCell className="w-32 align-top">{quantityInput}</TableCell>
                <TableCell className="w-28 align-top">{stockCell}</TableCell>
                <TableCell className="w-28 align-top">{readyToSaleCell}</TableCell>
                <TableCell className="w-14 align-top">{removeButton}</TableCell>
            </TableRow>
        );
    }

    return (
        <div className="grid gap-4 rounded-lg border border-border/80 bg-muted/20 p-4 sm:grid-cols-12">
            <div className="space-y-2 sm:col-span-4">
                <Label htmlFor={`customer-order-item-product-${index}`}>{labels.colProduct}</Label>
                {productSelect}
            </div>
            <div className="space-y-2 sm:col-span-2">
                <Label htmlFor={`customer-order-item-qty-${index}`}>{labels.quantityLabel}</Label>
                {quantityInput}
            </div>
            <div className="space-y-2 sm:col-span-2">
                <Label>{labels.colStock}</Label>
                {stockCell}
            </div>
            <div className="space-y-2 sm:col-span-3">
                <Label>{labels.colReadyToSale ?? 'Ready to Sale'}</Label>
                {readyToSaleCell}
            </div>
            <div className="flex items-end sm:col-span-1">{removeButton}</div>
        </div>
    );
}

/**
 * @param {object} props
 * @param {'create'|'edit'} props.mode
 * @param {Record<string, string>} props.labels
 * @param {Record<string, string>} props.validation
 * @param {Record<string, string>} props.appActions
 * @param {Array<{id: number, full_name: string}>} props.customers
 * @param {Array<{id: number, name: string, unit_name?: string|null, stock_on_hand?: string}>} props.products
 * @param {object} [props.initialOrder]
 * @param {string} props.submitUrl
 * @param {'post'|'put'} props.submitMethod
 * @param {string} props.cancelHref
 * @param {string} props.locale
 */
export function CustomerOrderForm({
    mode,
    labels,
    validation,
    appActions,
    customers,
    products,
    initialOrder,
    submitUrl,
    submitMethod,
    cancelHref,
    locale,
}) {
    const isCreate = mode === 'create';
    const initialItems =
        initialOrder?.items?.length > 0
            ? initialOrder.items.map((item) => ({
                  factory_product_id: item.factory_product_id
                      ? String(item.factory_product_id)
                      : '',
                  quantity: item.quantity ?? '',
              }))
            : [emptyItem()];

    const form = useForm({
        customer_id: initialOrder?.customer_id
            ? String(initialOrder.customer_id)
            : '',
        ordered_at: initialOrder?.ordered_at ?? todayYmd(),
        notes: initialOrder?.notes ?? '',
        items: initialItems,
    });
    const [confirmOpen, setConfirmOpen] = useState(false);

    const schema = useMemo(
        () =>
            isCreate
                ? buildStoreCustomerOrderSchema(validation)
                : buildUpdateCustomerOrderSchema(validation),
        [isCreate, validation],
    );

    const hasProducts = products.length > 0;

    function addItem() {
        form.setData('items', [...form.data.items, emptyItem()]);
    }

    function removeItem(index) {
        form.setData(
            'items',
            form.data.items.filter((_, rowIndex) => rowIndex !== index),
        );
    }

    function updateItem(index, field, value) {
        form.setData(
            'items',
            form.data.items.map((row, rowIndex) =>
                rowIndex === index ? { ...row, [field]: value } : row,
            ),
        );
    }

    function handleSubmit(e) {
        e.preventDefault();
        form.clearErrors();
        const parsed = schema.safeParse(form.data);
        if (!parsed.success) {
            form.setError(zodErrorToNestedFieldMap(parsed.error));
            toast.error(validation.required ?? appActions.requestFailed);
            return;
        }
        setConfirmOpen(true);
    }

    function commitSave() {
        form.clearErrors();
        const parsed = schema.safeParse(form.data);
        if (!parsed.success) {
            form.setError(zodErrorToNestedFieldMap(parsed.error));
            setConfirmOpen(false);
            toast.error(validation.required ?? appActions.requestFailed);
            return;
        }

        form.transform(() => ({
            customer_id: parsed.data.customer_id,
            ordered_at: parsed.data.ordered_at,
            notes: parsed.data.notes ?? '',
            items: parsed.data.items.map((item) => ({
                factory_product_id: item.factory_product_id,
                quantity: item.quantity,
            })),
        }));

        const options = {
            onError: () => toast.error(appActions.requestFailed),
        };

        if (submitMethod === 'put') {
            form.put(submitUrl, options);
            return;
        }

        form.post(submitUrl, options);
    }

    return (
        <>
            <ConfirmActionDialog
                open={confirmOpen}
                onOpenChange={setConfirmOpen}
                title={isCreate ? labels.confirmSaveTitle : labels.confirmUpdateTitle}
                description={isCreate ? labels.confirmSaveBody : labels.confirmUpdateBody}
                confirmLabel={isCreate ? labels.saveOrder : labels.updateOrder}
                cancelLabel={appActions.cancel}
                processing={form.processing}
                onConfirm={commitSave}
            />
            <form onSubmit={handleSubmit} className="mx-auto flex w-full max-w-5xl flex-col gap-6">
                <Card>
                    <CardHeader>
                        <CardTitle>
                            {isCreate ? labels.createHeadTitle : labels.editHeadTitle}
                        </CardTitle>
                        <CardDescription>
                            {isCreate ? labels.createDescription : labels.editDescription}
                        </CardDescription>
                    </CardHeader>
                    <CardContent className="space-y-6">
                        <div className="grid gap-6 sm:grid-cols-2">
                            <div className="space-y-2">
                                <Label htmlFor="customer_id">{labels.customerLabel}</Label>
                                <CustomerSearchSelect
                                    id="customer_id"
                                    value={form.data.customer_id}
                                    onValueChange={(v) => form.setData('customer_id', v)}
                                    customers={customers}
                                    placeholder={labels.customerPlaceholder}
                                    searchPlaceholder={labels.customerSearchPlaceholder}
                                    emptyLabel={labels.customerSearchEmpty}
                                    noCustomersHint={labels.noCustomersHint}
                                    addCustomerLink={labels.addCustomerLink}
                                    error={form.errors.customer_id}
                                />
                                {form.errors.customer_id ? (
                                    <p className="text-destructive text-sm">
                                        {form.errors.customer_id}
                                    </p>
                                ) : null}
                            </div>
                            <div className="space-y-2">
                                <Label>{labels.orderedAtLabel}</Label>
                                <AppDateInput
                                    value={form.data.ordered_at}
                                    onChange={(v) => form.setData('ordered_at', v)}
                                    invalid={Boolean(form.errors.ordered_at)}
                                />
                                {form.errors.ordered_at ? (
                                    <p className="text-destructive text-sm">
                                        {form.errors.ordered_at}
                                    </p>
                                ) : null}
                            </div>
                        </div>

                        <div className="space-y-4 rounded-xl border border-border p-4">
                            <div className="flex flex-wrap items-center justify-between gap-3">
                                <div>
                                    <h3 className="text-sm font-semibold">{labels.itemsSection}</h3>
                                    <p className="text-muted-foreground text-sm">
                                        {labels.itemsSectionHint}
                                    </p>
                                </div>
                                {hasProducts ? (
                                    <Button
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        onClick={addItem}
                                    >
                                        <Plus className="size-4" />
                                        {labels.addItem}
                                    </Button>
                                ) : null}
                            </div>

                            {!hasProducts ? (
                                <p className="text-muted-foreground text-sm">{labels.noProductsHint}</p>
                            ) : (
                                <>
                                    <div className="hidden overflow-x-auto rounded-lg border border-border md:block">
                                        <Table>
                                            <TableHeader>
                                                <TableRow>
                                                    <TableHead className="w-12">
                                                        {labels.colSerial}
                                                    </TableHead>
                                                    <TableHead className="min-w-[14rem]">
                                                        {labels.colProduct}
                                                    </TableHead>
                                                    <TableHead className="w-32">
                                                        {labels.quantityLabel}
                                                    </TableHead>
                                                    <TableHead className="w-28">
                                                        {labels.colStock}
                                                    </TableHead>
                                                    <TableHead className="w-28">
                                                        {labels.colReadyToSale ?? 'Ready to Sale'}
                                                    </TableHead>
                                                    <TableHead className="w-14">
                                                        <span className="sr-only">
                                                            {labels.removeLine}
                                                        </span>
                                                    </TableHead>
                                                </TableRow>
                                            </TableHeader>
                                            <TableBody>
                                                {form.data.items.map((item, index) => (
                                                    <CustomerOrderItemLine
                                                        key={index}
                                                        item={item}
                                                        index={index}
                                                        labels={labels}
                                                        products={products}
                                                        errors={form.errors}
                                                        canRemove={form.data.items.length > 1}
                                                        variant="table"
                                                        onUpdate={updateItem}
                                                        onRemove={removeItem}
                                                        locale={locale}
                                                    />
                                                ))}
                                            </TableBody>
                                        </Table>
                                    </div>
                                    <div className="space-y-4 md:hidden">
                                        {form.data.items.map((item, index) => (
                                            <CustomerOrderItemLine
                                                key={index}
                                                item={item}
                                                index={index}
                                                labels={labels}
                                                products={products}
                                                errors={form.errors}
                                                canRemove={form.data.items.length > 1}
                                                variant="cards"
                                                onUpdate={updateItem}
                                                onRemove={removeItem}
                                                locale={locale}
                                            />
                                        ))}
                                    </div>
                                </>
                            )}

                            {form.errors.items ? (
                                <p className="text-destructive text-sm">{form.errors.items}</p>
                            ) : null}
                        </div>

                        <div className="space-y-2">
                            <Label>{labels.notesLabel}</Label>
                            <textarea
                                value={form.data.notes}
                                onChange={(e) => form.setData('notes', e.target.value)}
                                rows={3}
                                className="border-input flex min-h-[4rem] w-full rounded-md border bg-transparent px-3 py-2 text-sm shadow-xs outline-none"
                            />
                        </div>

                        <div className="flex flex-wrap items-center gap-3">
                            <Button
                                type="submit"
                                disabled={
                                    form.processing
                                    || products.length === 0
                                    || customers.length === 0
                                }
                            >
                                <Save className="size-4" />
                                {form.processing
                                    ? isCreate
                                        ? labels.savingOrder
                                        : labels.updatingOrder
                                    : isCreate
                                      ? labels.saveOrder
                                      : labels.updateOrder}
                            </Button>
                            <Button type="button" variant="outline" asChild>
                                <Link href={cancelHref} prefetch>
                                    {isCreate ? labels.backToOrders : labels.backToOrder}
                                </Link>
                            </Button>
                        </div>
                    </CardContent>
                </Card>
            </form>
        </>
    );
}
