import { useForm } from '@inertiajs/react';
import { ArrowLeftRight, Calculator, Landmark, Save } from 'lucide-react';
import { useMemo, useState } from 'react';
import { toast } from 'sonner';
import { ConfirmActionDialog } from '@/components/confirm-action-dialog';
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 { Spinner } from '@/components/ui/spinner';
import { calculateCurrencyExchangeTotals } from '@/lib/currency-exchange';
import { formatMoneyAmountOrDash, formatMoneyInputDisplay } from '@/lib/dates';
import { parseMoneyInput, roundToDecimals, sanitizeDecimalInput } from '@/lib/money';
import { cn } from '@/lib/utils';
import { zodErrorToFieldMap } from '@/lib/zod-errors';
import { z } from 'zod';

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

function CurrencyAmountInput({
    id,
    label,
    currency,
    value,
    onChange,
    placeholder,
    error,
    maxDecimals = 2,
    allowNegative = false,
}) {
    return (
        <div className="space-y-2">
            <Label htmlFor={id}>{label}</Label>
            <div className="relative">
                <Input
                    id={id}
                    type="text"
                    inputMode="decimal"
                    value={value}
                    onChange={(e) =>
                        onChange(
                            sanitizeDecimalInput(e.target.value, {
                                maxDecimals,
                                allowNegative,
                            }),
                        )
                    }
                    onWheel={(e) => e.currentTarget.blur()}
                    placeholder={placeholder}
                    aria-invalid={Boolean(error)}
                    className={cn('pe-16 tabular-nums', error && 'border-destructive')}
                />
                <span className="text-muted-foreground pointer-events-none absolute inset-y-0 end-3 flex items-center text-xs font-medium uppercase tracking-wide">
                    {currency}
                </span>
            </div>
            {error ? <p className="text-destructive text-sm">{error}</p> : null}
        </div>
    );
}

function FormSection({ icon: Icon, title, hint, children, className }) {
    return (
        <section
            className={cn(
                'space-y-4 rounded-xl border border-border/80 bg-muted/15 p-4 sm:p-5',
                className,
            )}
        >
            <div className="flex items-start gap-3">
                {Icon ? (
                    <div className="bg-primary/10 text-primary mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg">
                        <Icon className="size-4" />
                    </div>
                ) : null}
                <div className="min-w-0 space-y-1">
                    <h3 className="text-sm font-semibold">{title}</h3>
                    {hint ? <p className="text-muted-foreground text-sm">{hint}</p> : null}
                </div>
            </div>
            {children}
        </section>
    );
}

function SummaryRow({ label, value, currency, highlight = false, warning = false }) {
    return (
        <div
            className={cn(
                'flex items-center justify-between gap-3 rounded-lg px-3 py-2.5',
                highlight && 'bg-primary/10',
                warning && 'bg-amber-500/10',
                !highlight && !warning && 'bg-background/70',
            )}
        >
            <span className="text-muted-foreground text-sm">{label}</span>
            <span
                className={cn(
                    'text-end text-sm font-semibold tabular-nums',
                    highlight && 'text-primary',
                    warning && 'text-amber-700 dark:text-amber-400',
                )}
            >
                {value}
                {currency ? ` ${currency}` : ''}
            </span>
        </div>
    );
}

export function CurrencyExchangeForm({
    sarafs,
    labels,
    validation,
    submitUrl,
    locale,
    cancelHref,
    exchange = null,
    method = 'post',
    minReceiveDollar = null,
}) {
    const [confirmOpen, setConfirmOpen] = useState(false);
    const isEdit = method === 'put';

    const schema = useMemo(
        () =>
            z.object({
                saraf_id: z.string().min(1, validation.required),
                exchange_date: z.string().min(1, validation.required),
                total_afn: z.coerce.number().gt(0),
                dollar_difference_price: z.coerce.number(),
                dollar_price: z.coerce.number().gt(0),
                receive_dollar: z.preprocess(
                    (value) => (value === '' || value === null || value === undefined ? 0 : value),
                    z.coerce.number().min(0),
                ),
            }),
        [validation.required],
    );

    const form = useForm({
        saraf_id: exchange ? String(exchange.saraf_id) : '',
        exchange_date: exchange?.exchange_date ?? todayYmd(),
        total_afn: exchange?.total_afn ?? '',
        dollar_difference_price: exchange?.dollar_difference_price ?? '0',
        dollar_price: exchange?.dollar_price ?? '',
        receive_dollar: exchange?.receive_dollar ?? '',
    });

    const selectedSaraf = useMemo(
        () => sarafs.find((saraf) => String(saraf.id) === String(form.data.saraf_id)),
        [sarafs, form.data.saraf_id],
    );

    const { totalDollar, remainDollarOnSaraf } = useMemo(
        () =>
            calculateCurrencyExchangeTotals(
                form.data.total_afn,
                form.data.dollar_price,
                form.data.dollar_difference_price,
                form.data.receive_dollar,
            ),
        [
            form.data.total_afn,
            form.data.dollar_price,
            form.data.dollar_difference_price,
            form.data.receive_dollar,
        ],
    );

    const effectiveRate = useMemo(() => {
        const price = parseMoneyInput(form.data.dollar_price, 4);
        const difference = parseMoneyInput(form.data.dollar_difference_price, 4);

        if (price == null || difference == null) {
            return null;
        }

        const rate = roundToDecimals(price + difference, 4);

        return rate > 0 ? rate : null;
    }, [form.data.dollar_price, form.data.dollar_difference_price]);

    const canSubmit =
        sarafs.length > 0 && totalDollar != null && !form.processing;

    function handleSubmit(e) {
        e.preventDefault();
        form.clearErrors();
        const parsed = schema.safeParse(form.data);

        if (!parsed.success) {
            form.setError(zodErrorToFieldMap(parsed.error));
            return;
        }

        setConfirmOpen(true);
    }

    function commitSave() {
        form.clearErrors();
        const parsed = schema.safeParse(form.data);

        if (!parsed.success) {
            form.setError(zodErrorToFieldMap(parsed.error));
            setConfirmOpen(false);
            return;
        }

        form[method](submitUrl, {
            preserveScroll: true,
            onSuccess: () => setConfirmOpen(false),
            onError: () => toast.error(labels.requestFailed),
        });
    }

    return (
        <>
            <ConfirmActionDialog
                open={confirmOpen}
                onOpenChange={setConfirmOpen}
                title={isEdit ? labels.confirmUpdateTitle : labels.confirmSaveTitle}
                description={isEdit ? labels.confirmUpdateBody : labels.confirmSaveBody}
                confirmLabel={isEdit ? labels.update : labels.save}
                cancelLabel={labels.cancel}
                processing={form.processing}
                onConfirm={commitSave}
            />

            <form
                noValidate
                onSubmit={handleSubmit}
                className="mx-auto flex w-full max-w-5xl flex-col gap-6"
            >
                <Card className="overflow-hidden">
                    <CardHeader className="border-b bg-muted/20">
                        <CardTitle>{labels.pageTitle ?? labels.createTitle}</CardTitle>
                        <CardDescription>{labels.pageDescription ?? labels.createDescription}</CardDescription>
                    </CardHeader>

                    <CardContent className="grid gap-6 p-4 sm:p-6 lg:grid-cols-[minmax(0,1fr)_minmax(280px,320px)] lg:gap-8">
                        <div className="space-y-5">
                            <FormSection
                                icon={Landmark}
                                title={labels.sectionDetailsTitle}
                                hint={labels.sectionDetailsHint}
                            >
                                <div className="grid gap-4 sm:grid-cols-2">
                                    <div className="space-y-2 sm:col-span-2">
                                        <Label htmlFor="currency-exchange-saraf">{labels.sarafLabel}</Label>
                                        {sarafs.length === 0 ? (
                                            <p className="text-muted-foreground rounded-lg border border-dashed px-3 py-4 text-sm">
                                                {labels.noSarafsHint}
                                            </p>
                                        ) : (
                                            <Select
                                                value={form.data.saraf_id}
                                                onValueChange={(value) => form.setData('saraf_id', value)}
                                            >
                                                <SelectTrigger
                                                    id="currency-exchange-saraf"
                                                    className={cn(form.errors.saraf_id && 'border-destructive')}
                                                >
                                                    <SelectValue placeholder={labels.sarafPlaceholder} />
                                                </SelectTrigger>
                                                <SelectContent>
                                                    {sarafs.map((saraf) => (
                                                        <SelectItem key={saraf.id} value={String(saraf.id)}>
                                                            {saraf.name}
                                                        </SelectItem>
                                                    ))}
                                                </SelectContent>
                                            </Select>
                                        )}
                                        {form.errors.saraf_id ? (
                                            <p className="text-destructive text-sm">{form.errors.saraf_id}</p>
                                        ) : null}
                                    </div>

                                    <div className="space-y-2">
                                        <Label htmlFor="currency-exchange-date">{labels.dateLabel}</Label>
                                        <AppDateInput
                                            id="currency-exchange-date"
                                            value={form.data.exchange_date}
                                            onChange={(value) => form.setData('exchange_date', value)}
                                            invalid={Boolean(form.errors.exchange_date)}
                                        />
                                        {form.errors.exchange_date ? (
                                            <p className="text-destructive text-sm">{form.errors.exchange_date}</p>
                                        ) : null}
                                    </div>
                                </div>
                            </FormSection>

                            <FormSection
                                icon={ArrowLeftRight}
                                title={labels.sectionAfnTitle}
                                hint={labels.sectionAfnHint}
                            >
                                <CurrencyAmountInput
                                    id="currency-exchange-total-afn"
                                    label={labels.totalAfnLabel}
                                    currency={labels.afnCurrencyLabel}
                                    value={form.data.total_afn}
                                    onChange={(value) => form.setData('total_afn', value)}
                                    placeholder={labels.totalAfnPlaceholder}
                                    error={form.errors.total_afn}
                                    maxDecimals={2}
                                />
                            </FormSection>

                            <FormSection
                                icon={Calculator}
                                title={labels.sectionRateTitle}
                                hint={labels.sectionRateHint}
                            >
                                <div className="grid gap-4 sm:grid-cols-2">
                                    <CurrencyAmountInput
                                        id="currency-exchange-dollar-price"
                                        label={labels.dollarPriceLabel}
                                        currency={labels.afnCurrencyLabel}
                                        value={form.data.dollar_price}
                                        onChange={(value) => form.setData('dollar_price', value)}
                                        placeholder={labels.dollarPricePlaceholder}
                                        error={form.errors.dollar_price}
                                        maxDecimals={4}
                                    />
                                    <CurrencyAmountInput
                                        id="currency-exchange-difference"
                                        label={labels.dollarDifferencePriceLabel}
                                        currency={labels.afnCurrencyLabel}
                                        value={form.data.dollar_difference_price}
                                        onChange={(value) =>
                                            form.setData('dollar_difference_price', value)
                                        }
                                        placeholder={labels.dollarDifferencePricePlaceholder}
                                        error={form.errors.dollar_difference_price}
                                        maxDecimals={4}
                                        allowNegative
                                    />
                                </div>

                                <div className="rounded-lg border border-dashed bg-background/80 px-3 py-2.5 text-sm">
                                    <p className="text-muted-foreground">{labels.calculationHint}</p>
                                    {effectiveRate != null ? (
                                        <p className="mt-1 font-medium tabular-nums">
                                            {labels.effectiveRateLabel}:{' '}
                                            {formatMoneyAmountOrDash(effectiveRate, locale, 4)}{' '}
                                            {labels.afnCurrencyLabel}
                                        </p>
                                    ) : null}
                                </div>
                            </FormSection>

                            <FormSection title={labels.sectionSettlementTitle} hint={labels.sectionSettlementHint}>
                                <CurrencyAmountInput
                                    id="currency-exchange-receive-dollar"
                                    label={`${labels.receiveDollarLabel} (${labels.optionalLabel})`}
                                    currency={labels.usdCurrencyLabel}
                                    value={form.data.receive_dollar}
                                    onChange={(value) => form.setData('receive_dollar', value)}
                                    placeholder={labels.receiveDollarPlaceholder}
                                    error={form.errors.receive_dollar}
                                    maxDecimals={2}
                                />
                                {isEdit && minReceiveDollar != null && Number(minReceiveDollar) > 0 ? (
                                    <p className="text-muted-foreground text-xs">
                                        {labels.minReceiveHint.replace(
                                            '{amount}',
                                            formatMoneyAmountOrDash(minReceiveDollar, locale),
                                        )}
                                    </p>
                                ) : null}
                            </FormSection>

                            <div className="flex flex-col-reverse gap-3 sm:flex-row sm:justify-end">
                                {cancelHref ? (
                                    <Button type="button" variant="outline" asChild>
                                        <a href={cancelHref}>{labels.backToList}</a>
                                    </Button>
                                ) : null}
                                <Button type="submit" disabled={!canSubmit} className="sm:min-w-40">
                                    {form.processing ? (
                                        <Spinner className="size-4" />
                                    ) : (
                                        <Save className="size-4" />
                                    )}
                                    {form.processing
                                        ? isEdit
                                            ? labels.updating
                                            : labels.saving
                                        : isEdit
                                          ? labels.update
                                          : labels.save}
                                </Button>
                            </div>
                        </div>

                        <aside className="lg:sticky lg:top-4 lg:self-start">
                            <div className="space-y-4 rounded-xl border border-primary/20 bg-primary/5 p-4 sm:p-5">
                                <div className="space-y-1">
                                    <h3 className="text-sm font-semibold">{labels.summaryTitle}</h3>
                                    <p className="text-muted-foreground text-sm">{labels.summaryHint}</p>
                                </div>

                                {selectedSaraf ? (
                                    <div className="rounded-lg border bg-background/80 px-3 py-2 text-sm">
                                        <span className="text-muted-foreground">{labels.sarafLabel}: </span>
                                        <span className="font-medium">{selectedSaraf.name}</span>
                                    </div>
                                ) : null}

                                <div className="space-y-2">
                                    <SummaryRow
                                        label={labels.totalAfnLabel}
                                        value={formatMoneyInputDisplay(form.data.total_afn, locale, 2)}
                                        currency={labels.afnCurrencyLabel}
                                    />
                                    <SummaryRow
                                        label={labels.dollarPriceLabel}
                                        value={formatMoneyInputDisplay(form.data.dollar_price, locale, 4)}
                                        currency={labels.afnCurrencyLabel}
                                    />
                                    <SummaryRow
                                        label={labels.dollarDifferencePriceLabel}
                                        value={formatMoneyInputDisplay(
                                            form.data.dollar_difference_price,
                                            locale,
                                            4,
                                        )}
                                        currency={labels.afnCurrencyLabel}
                                    />
                                    <SummaryRow
                                        label={labels.effectiveRateLabel}
                                        value={formatMoneyAmountOrDash(effectiveRate, locale, 4)}
                                        currency={labels.afnCurrencyLabel}
                                    />
                                    <SummaryRow
                                        label={labels.totalDollarLabel}
                                        value={formatMoneyAmountOrDash(totalDollar, locale)}
                                        currency={labels.usdCurrencyLabel}
                                        highlight
                                    />
                                    <SummaryRow
                                        label={labels.receiveDollarLabel}
                                        value={formatMoneyInputDisplay(
                                            form.data.receive_dollar,
                                            locale,
                                            2,
                                        )}
                                        currency={labels.usdCurrencyLabel}
                                    />
                                    <SummaryRow
                                        label={labels.remainDollarOnSarafLabel}
                                        value={formatMoneyAmountOrDash(remainDollarOnSaraf, locale)}
                                        currency={labels.usdCurrencyLabel}
                                        warning={
                                            remainDollarOnSaraf != null && remainDollarOnSaraf > 0.001
                                        }
                                    />
                                </div>

                                {totalDollar != null &&
                                form.data.total_afn !== '' &&
                                effectiveRate != null ? (
                                    <div className="rounded-lg border border-dashed bg-background/70 px-3 py-3 text-center text-sm tabular-nums">
                                        <span className="font-medium">
                                            {formatMoneyInputDisplay(form.data.total_afn, locale, 2)}
                                        </span>
                                        <span className="text-muted-foreground mx-2">÷</span>
                                        <span className="font-medium">
                                            {formatMoneyAmountOrDash(effectiveRate, locale, 4)}
                                        </span>
                                        <span className="text-muted-foreground mx-2">=</span>
                                        <span className="text-primary font-semibold">
                                            {formatMoneyAmountOrDash(totalDollar, locale)} {labels.usdCurrencyLabel}
                                        </span>
                                    </div>
                                ) : (
                                    <p className="text-muted-foreground text-center text-sm">
                                        {labels.summaryEmpty}
                                    </p>
                                )}
                            </div>
                        </aside>
                    </CardContent>
                </Card>
            </form>
        </>
    );
}
