import { Link, router } from '@inertiajs/react';
import { Save } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { toast } from 'sonner';
import { returnPacks as returnSale } from '@/actions/App/Http/Controllers/SaleController';
import { ConfirmActionDialog } from '@/components/confirm-action-dialog';
import { SaleReturnProductCard } from '@/components/sales/sale-return-product-card';
import { SaleReturnSummary } from '@/components/sales/sale-return-summary';
import { Button } from '@/components/ui/button';
import {
    Card,
    CardContent,
    CardDescription,
    CardFooter,
    CardHeader,
    CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { firstInertiaErrorMessage } from '@/lib/inertia-errors';
import {
    paginateSaleReturnLines,
    SALE_RETURN_COMPACT_THRESHOLD,
    SALE_RETURN_PAGE_SIZE,
    saleReturnLineMatchesSearch,
} from '@/lib/sale-return-list';
import {
    createEmptySaleReturnBreakdown,
    initialSaleReturnBreakdowns,
    SALE_RETURN_CONDITIONS,
    saleReturnBreakdownTotalQuantity,
    saleReturnConditionAmountIsEditable,
    saleReturnDefaultEntryAmount,
    saleReturnLineKey,
    saleReturnLinesPayloadFromBreakdowns,
    saleReturnTotalsFromBreakdowns,
    saleReturnWeightForCondition,
    validateSaleReturnBreakdowns,
} from '@/lib/sale-return-quantities';
import { cn } from '@/lib/utils';
import { formatDecimalTrimmed } from '@/lib/money';
import { zodErrorToNestedFieldMap } from '@/lib/zod-errors';
import { buildReturnSalePacksSchema } from '@/validation/schemas';

/**
 * @param {object} props
 * @param {Record<string, string>} props.labels
 * @param {Record<string, string>} props.validation
 * @param {Record<string, string>} props.appActions
 * @param {{ id: number, sale_number?: string, customer_name?: string, order_number?: string|null }} props.sale
 * @param {Array<{
 *   sale_item_id?: number|null,
 *   product_name?: string,
 *   unit_name?: string|null,
 *   quantity: number,
 *   total_weight: string,
 *   weight_price?: string|null,
 *   pack_ids: number[],
 *   pack_weights?: string[]
 * }>} props.lines
 * @param {number[]} [props.preselectedPackIds]
 * @param {string} [props.cancelHref]
 * @param {string} props.locale
 */
export function SaleReturnForm({
    labels,
    validation,
    appActions,
    sale,
    lines = [],
    preselectedPackIds = [],
    cancelHref,
    locale,
}) {
    const usePagedProducts = lines.length >= SALE_RETURN_COMPACT_THRESHOLD;

    const [breakdowns, setBreakdowns] = useState(() =>
        initialSaleReturnBreakdowns(lines, preselectedPackIds),
    );
    const [notes, setNotes] = useState('');
    const [errors, setErrors] = useState({});
    const [processing, setProcessing] = useState(false);
    const [search, setSearch] = useState('');
    const [page, setPage] = useState(1);
    const [confirmOpen, setConfirmOpen] = useState(false);

    useEffect(() => {
        setBreakdowns(initialSaleReturnBreakdowns(lines, preselectedPackIds));
    }, [lines, preselectedPackIds]);

    const schema = useMemo(
        () => buildReturnSalePacksSchema(validation),
        [validation],
    );

    const returnTotals = useMemo(
        () => saleReturnTotalsFromBreakdowns(lines, breakdowns),
        [lines, breakdowns],
    );

    const filteredLines = useMemo(
        () =>
            lines.filter((line) =>
                saleReturnLineMatchesSearch(line.product_name, search),
            ),
        [lines, search],
    );

    const pagination = useMemo(
        () =>
            usePagedProducts
                ? paginateSaleReturnLines(
                      filteredLines,
                      page,
                      SALE_RETURN_PAGE_SIZE,
                  )
                : {
                      items: filteredLines,
                      currentPage: 1,
                      totalPages: 1,
                      totalItems: filteredLines.length,
                      from: filteredLines.length > 0 ? 1 : 0,
                      to: filteredLines.length,
                  },
        [usePagedProducts, filteredLines, page],
    );

    useEffect(() => {
        setPage(1);
    }, [search]);

    useEffect(() => {
        if (page > pagination.totalPages) {
            setPage(pagination.totalPages);
        }
    }, [page, pagination.totalPages]);

    const allReturned = lines.every((line) => {
        const key = saleReturnLineKey(line);
        const breakdown = breakdowns[key] ?? createEmptySaleReturnBreakdown();

        return saleReturnBreakdownTotalQuantity(breakdown) === line.quantity;
    });

    function updateConditionQuantity(line, condition, rawValue) {
        const key = saleReturnLineKey(line);
        const parsed = Number.parseInt(String(rawValue), 10);
        const nextQuantity = Number.isNaN(parsed) ? 0 : Math.max(parsed, 0);

        setBreakdowns((current) => {
            const breakdown = {
                ...(current[key] ?? createEmptySaleReturnBreakdown()),
            };
            const otherTotal = SALE_RETURN_CONDITIONS.filter(
                (entry) => entry !== condition,
            ).reduce(
                (sum, entry) => sum + (breakdown[entry]?.quantity ?? 0),
                0,
            );
            const cappedQuantity = Math.min(
                nextQuantity,
                Math.max(0, line.quantity - otherTotal),
            );
            const nextBreakdown = {
                ...breakdown,
                [condition]: {
                    quantity: cappedQuantity,
                    weight: '',
                    amount: '',
                },
            };
            const weightValue =
                cappedQuantity > 0
                    ? saleReturnWeightForCondition(
                          line,
                          nextBreakdown,
                          condition,
                      )
                    : 0;

            breakdown[condition] = {
                quantity: cappedQuantity,
                weight: cappedQuantity > 0 ? formatDecimalTrimmed(weightValue, 3) : '',
                amount:
                    cappedQuantity > 0 &&
                    saleReturnConditionAmountIsEditable(condition)
                        ? saleReturnDefaultEntryAmount(line, weightValue, cappedQuantity)
                        : '',
            };

            return { ...current, [key]: breakdown };
        });
    }

    function updateConditionWeight(line, condition, rawValue) {
        const key = saleReturnLineKey(line);

        setBreakdowns((current) => {
            const breakdown = {
                ...(current[key] ?? createEmptySaleReturnBreakdown()),
            };
            const weightValue = Number(rawValue);

            breakdown[condition] = {
                ...breakdown[condition],
                weight: rawValue,
                amount:
                    saleReturnConditionAmountIsEditable(condition) &&
                    Number.isFinite(weightValue) &&
                    weightValue > 0
                        ? saleReturnDefaultEntryAmount(
                              line,
                              weightValue,
                              breakdown[condition]?.quantity ?? 0,
                          )
                        : (breakdown[condition]?.amount ?? ''),
            };

            return { ...current, [key]: breakdown };
        });
    }

    function updateConditionAmount(line, condition, rawValue) {
        const key = saleReturnLineKey(line);

        setBreakdowns((current) => {
            const breakdown = {
                ...(current[key] ?? createEmptySaleReturnBreakdown()),
            };

            breakdown[condition] = {
                ...breakdown[condition],
                amount: rawValue,
            };

            return { ...current, [key]: breakdown };
        });
    }

    function returnAllLines() {
        setBreakdowns(
            Object.fromEntries(
                lines.map((line) => {
                    const key = saleReturnLineKey(line);

                    return [
                        key,
                        {
                            good: {
                                quantity: line.quantity,
                                weight: formatDecimalTrimmed(
                                    saleReturnWeightForCondition(
                                        line,
                                        {
                                            good: {
                                                quantity: line.quantity,
                                                weight: '',
                                                amount: '',
                                            },
                                            defective: {
                                                quantity: 0,
                                                weight: '',
                                                amount: '',
                                            },
                                            expired: {
                                                quantity: 0,
                                                weight: '',
                                                amount: '',
                                            },
                                        },
                                        'good',
                                    ),
                                    3,
                                ),
                                amount: '',
                            },
                            defective: {
                                quantity: 0,
                                weight: '',
                                amount: '',
                            },
                            expired: {
                                quantity: 0,
                                weight: '',
                                amount: '',
                            },
                        },
                    ];
                }),
            ),
        );
    }

    function clearAllReturns() {
        setBreakdowns(
            Object.fromEntries(
                lines.map((line) => [
                    saleReturnLineKey(line),
                    createEmptySaleReturnBreakdown(),
                ]),
            ),
        );
    }

    function buildValidatedPayload() {
        setErrors({});

        const validationError = validateSaleReturnBreakdowns(lines, breakdowns);

        if (validationError) {
            const message =
                typeof validationError === 'object' &&
                validationError?.key === 'returnWeightExceedsSoldMax'
                    ? (labels.returnWeightExceedsSoldMax ?? labels.returnWeightExceedsSold)
                          .replace('{max}', validationError.max)
                    : labels[validationError] ??
                      validation.required ??
                      appActions.requestFailed;
            setErrors({ return_lines: message });
            toast.error(message);
            return null;
        }

        const returnLines = saleReturnLinesPayloadFromBreakdowns(
            lines,
            breakdowns,
        );

        const parsed = schema.safeParse({
            return_lines: returnLines,
            notes,
        });

        if (!parsed.success) {
            setErrors(zodErrorToNestedFieldMap(parsed.error));
            toast.error(
                parsed.error.flatten().fieldErrors.return_lines?.[0] ??
                    labels.selectPacksToReturn ??
                    validation.required ??
                    appActions.requestFailed,
            );
            return null;
        }

        return parsed.data;
    }

    function handleSubmit(e) {
        e.preventDefault();
        if (!buildValidatedPayload()) {
            return;
        }
        setConfirmOpen(true);
    }

    function commitSave() {
        const data = buildValidatedPayload();
        if (!data) {
            setConfirmOpen(false);
            return;
        }

        setProcessing(true);
        router.post(
            returnSale.url(sale.id),
            {
                return_lines: data.return_lines,
                notes: data.notes || undefined,
            },
            {
                onError: (pageErrors) =>
                    toast.error(
                        firstInertiaErrorMessage(
                            pageErrors,
                            appActions.requestFailed,
                        ),
                    ),
                onFinish: () => setProcessing(false),
            },
        );
    }

    return (
        <>
        <ConfirmActionDialog
            open={confirmOpen}
            onOpenChange={setConfirmOpen}
            title={labels.confirmReturnTitle}
            description={labels.confirmReturnBody}
            confirmLabel={labels.confirmReturn}
            cancelLabel={appActions.cancel}
            processing={processing}
            onConfirm={commitSave}
        />
        <form onSubmit={handleSubmit} className="mx-auto w-full max-w-7xl">
            <Card>
                <CardHeader>
                    <CardTitle>{labels.returnHeadTitle}</CardTitle>
                    <CardDescription>
                        {labels.returnDescription}
                    </CardDescription>
                </CardHeader>

                <CardContent className="space-y-8">
                    <section className="space-y-4">
                        <h3 className="text-sm font-semibold">
                            {labels.billDetailsSection}
                        </h3>

                        <div className="grid gap-4 sm:grid-cols-2">
                            <div className="space-y-2">
                                <Label>{labels.billNoLabel}</Label>
                                <Input
                                    value={sale.sale_number ?? '—'}
                                    disabled
                                    className="bg-muted/40 font-mono text-sm"
                                />
                            </div>
                            <div className="space-y-2">
                                <Label>{labels.customerLabel}</Label>
                                <Input
                                    value={sale.customer_name ?? '—'}
                                    disabled
                                />
                            </div>
                        </div>
                    </section>

                    <section className="space-y-4">
                        <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
                            <div>
                                <h3 className="text-sm font-semibold">
                                    {labels.productsSection}
                                </h3>
                                <p className="mt-1 text-sm text-muted-foreground">
                                    {usePagedProducts
                                        ? labels.returnProductsCompactHint
                                        : labels.returnProductsSectionHint}
                                </p>
                            </div>
                            <div className="flex flex-wrap gap-2">
                                <Button
                                    type="button"
                                    variant="outline"
                                    size="sm"
                                    onClick={returnAllLines}
                                    disabled={allReturned}
                                >
                                    {labels.returnAllProducts}
                                </Button>
                                <Button
                                    type="button"
                                    variant="outline"
                                    size="sm"
                                    onClick={clearAllReturns}
                                    disabled={returnTotals.quantity === 0}
                                >
                                    {labels.clearReturnQuantities}
                                </Button>
                            </div>
                        </div>

                        {returnTotals.quantity > 0 ? (
                            <SaleReturnSummary
                                variant="compact"
                                labels={labels}
                                locale={locale}
                                totals={returnTotals}
                                lines={lines}
                                breakdowns={breakdowns}
                            />
                        ) : null}

                        {usePagedProducts ? (
                            <div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
                                <div className="max-w-md flex-1 space-y-2">
                                    <Label htmlFor="return_product_search">
                                        {labels.returnProductSearchLabel}
                                    </Label>
                                    <Input
                                        id="return_product_search"
                                        type="search"
                                        value={search}
                                        onChange={(e) =>
                                            setSearch(e.target.value)
                                        }
                                        placeholder={
                                            labels.returnProductSearchPlaceholder
                                        }
                                        className="h-9"
                                    />
                                </div>
                                <p className="text-sm text-muted-foreground tabular-nums">
                                    {labels.returnProductCountLabel
                                        .replace(
                                            '{shown}',
                                            String(pagination.totalItems),
                                        )
                                        .replace(
                                            '{total}',
                                            String(lines.length),
                                        )}
                                </p>
                            </div>
                        ) : null}

                        <div className="grid gap-2.5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
                            {pagination.items.length === 0 ? (
                                <div className="col-span-full rounded-xl border border-dashed border-border px-4 py-10 text-center text-sm text-muted-foreground">
                                    {labels.returnProductSearchEmpty}
                                </div>
                            ) : (
                                pagination.items.map((line) => {
                                    const key = saleReturnLineKey(line);
                                    const breakdown =
                                        breakdowns[key] ??
                                        createEmptySaleReturnBreakdown();

                                    return (
                                        <SaleReturnProductCard
                                            key={key}
                                            line={line}
                                            breakdown={breakdown}
                                            labels={labels}
                                            locale={locale}
                                            onUpdateQuantity={
                                                updateConditionQuantity
                                            }
                                            onUpdateWeight={
                                                updateConditionWeight
                                            }
                                            onUpdateAmount={
                                                updateConditionAmount
                                            }
                                        />
                                    );
                                })
                            )}
                        </div>

                        {usePagedProducts &&
                        pagination.totalItems > SALE_RETURN_PAGE_SIZE ? (
                            <div className="flex flex-col gap-3 border-t border-border pt-4 sm:flex-row sm:items-center sm:justify-between">
                                <p className="text-sm text-muted-foreground tabular-nums">
                                    {labels.returnPaginationSummary
                                        .replace(
                                            '{from}',
                                            String(pagination.from),
                                        )
                                        .replace('{to}', String(pagination.to))
                                        .replace(
                                            '{total}',
                                            String(pagination.totalItems),
                                        )}
                                </p>
                                <div className="flex items-center gap-2">
                                    <Button
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        onClick={() =>
                                            setPage((current) =>
                                                Math.max(1, current - 1),
                                            )
                                        }
                                        disabled={pagination.currentPage <= 1}
                                    >
                                        {labels.returnPaginationPrevious}
                                    </Button>
                                    <span className="min-w-[7rem] text-center text-sm text-muted-foreground tabular-nums">
                                        {labels.returnPaginationPages
                                            .replace(
                                                '{page}',
                                                String(pagination.currentPage),
                                            )
                                            .replace(
                                                '{pages}',
                                                String(pagination.totalPages),
                                            )}
                                    </span>
                                    <Button
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        onClick={() =>
                                            setPage((current) =>
                                                Math.min(
                                                    pagination.totalPages,
                                                    current + 1,
                                                ),
                                            )
                                        }
                                        disabled={
                                            pagination.currentPage >=
                                            pagination.totalPages
                                        }
                                    >
                                        {labels.returnPaginationNext}
                                    </Button>
                                </div>
                            </div>
                        ) : null}

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

                    <SaleReturnSummary
                        labels={labels}
                        locale={locale}
                        totals={returnTotals}
                        lines={lines}
                        breakdowns={breakdowns}
                    />

                    <section className="space-y-2">
                        <Label htmlFor="return_notes">
                            {labels.notesLabel}
                        </Label>
                        <Textarea
                            id="return_notes"
                            value={notes}
                            onChange={(e) => setNotes(e.target.value)}
                            placeholder={labels.returnNotesPlaceholder}
                            rows={3}
                            className={cn(errors.notes && 'border-destructive')}
                        />
                        {errors.notes ? (
                            <p className="text-sm text-destructive">
                                {errors.notes}
                            </p>
                        ) : null}
                    </section>
                </CardContent>

                <CardFooter className="flex flex-col-reverse gap-3 border-t border-border pt-6 sm:flex-row sm:justify-end">
                    {cancelHref ? (
                        <Button
                            type="button"
                            variant="outline"
                            asChild
                            disabled={processing}
                        >
                            <Link href={cancelHref}>{appActions.cancel}</Link>
                        </Button>
                    ) : null}
                    <Button
                        type="submit"
                        disabled={processing || returnTotals.quantity === 0}
                    >
                        <Save className="size-4" />
                        {processing
                            ? labels.returningPacks
                            : labels.confirmReturn}
                    </Button>
                </CardFooter>
            </Card>
        </form>
        </>
    );
}
