import { Button, Card, Input, Label, Modal, Pill, Select } from '@/Components/ui';
import {
    AlertCircle,
    CheckCircle2,
    Loader2,
    Pencil,
    Plus,
    Trash2,
    X,
} from 'lucide-react';
import {
    useCallback,
    useEffect,
    useMemo,
    useState,
    type SubmitEvent as ReactSubmitEvent,
    type ReactNode,
} from 'react';
import { csrfHeaders } from './types';

type CurrencyPosition =
    | 'left'
    | 'right'
    | 'left_with_space'
    | 'right_with_space';

const POSITION_OPTIONS: ReadonlyArray<{
    value: CurrencyPosition;
    label: string;
}> = [
    { value: 'left', label: 'Left ($1,234.56)' },
    { value: 'right', label: 'Right (1,234.56$)' },
    { value: 'left_with_space', label: 'Left + space ($ 1,234.56)' },
    { value: 'right_with_space', label: 'Right + space (1,234.56 $)' },
];

type Currency = {
    id: number;
    name: string;
    code: string;
    symbol: string | null;
    is_default: boolean;
    position: CurrencyPosition;
    no_of_decimal: number;
    thousand_separator: string | null;
    decimal_separator: string | null;
};

type IndexResponse = {
    currencies: Currency[];
};

type Toast =
    | { kind: 'success'; message: string }
    | { kind: 'error'; message: string };

type FormState = {
    name: string;
    code: string;
    symbol: string;
    position: CurrencyPosition;
    no_of_decimal: string;
    thousand_separator: string;
    decimal_separator: string;
};

const EMPTY_FORM: FormState = {
    name: '',
    code: '',
    symbol: '',
    position: 'left',
    no_of_decimal: '2',
    thousand_separator: ',',
    decimal_separator: '.',
};

function currencyToForm(c: Currency): FormState {
    return {
        name: c.name ?? '',
        code: c.code ?? '',
        symbol: c.symbol ?? '',
        position: c.position,
        no_of_decimal: String(c.no_of_decimal ?? 2),
        thousand_separator: c.thousand_separator ?? '',
        decimal_separator: c.decimal_separator ?? '',
    };
}

/**
 * Mirror of `App\Models\Currency::format()` so the Add/Edit modal can
 * preview formatting without a server round-trip. The reference value is
 * always 1234567.89 — it stresses both separators + the decimal slot.
 */
export function formatPreview(
    amount: number,
    opts: {
        symbol: string;
        position: CurrencyPosition;
        decimals: number;
        thousandSep: string | null;
        decimalSep: string | null;
    },
): string {
    const decimals = Math.max(0, Math.min(6, Math.floor(opts.decimals)));
    const decimalSep =
        opts.decimalSep !== null && opts.decimalSep !== '' ? opts.decimalSep : '.';
    const thousandSep = opts.thousandSep !== null ? opts.thousandSep : ',';

    const fixed = amount.toFixed(decimals);
    const [intPart, fracPart] = fixed.split('.');
    const grouped = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
    const intWithSep = grouped.split(' ').join(thousandSep);
    const number =
        decimals > 0 && fracPart !== undefined
            ? `${intWithSep}${decimalSep}${fracPart}`
            : intWithSep;
    const symbol = opts.symbol ?? '';

    switch (opts.position) {
        case 'right':
            return `${number}${symbol}`;
        case 'left_with_space':
            return `${symbol} ${number}`;
        case 'right_with_space':
            return `${number} ${symbol}`;
        case 'left':
        default:
            return `${symbol}${number}`;
    }
}

function formatCurrency(c: Currency, amount: number): string {
    return formatPreview(amount, {
        symbol: c.symbol ?? '',
        position: c.position,
        decimals: c.no_of_decimal,
        thousandSep: c.thousand_separator,
        decimalSep: c.decimal_separator,
    });
}

const PREVIEW_AMOUNT = 1234567.89;

export default function CurrenciesTab() {
    const [list, setList] = useState<Currency[]>([]);
    const [loading, setLoading] = useState(true);
    const [loadError, setLoadError] = useState<string | null>(null);
    const [toast, setToast] = useState<Toast | null>(null);
    const [showAddModal, setShowAddModal] = useState(false);
    const [editTarget, setEditTarget] = useState<Currency | null>(null);
    const [deleteTarget, setDeleteTarget] = useState<Currency | null>(null);
    const [pendingDefaultId, setPendingDefaultId] = useState<number | null>(
        null,
    );

    const refetch = useCallback(async () => {
        try {
            const res = await fetch('/admin/settings/currencies', {
                credentials: 'same-origin',
                headers: {
                    Accept: 'application/json',
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });
            if (!res.ok) {
                setLoadError(`Failed to load currencies (${res.status}).`);
                return;
            }
            const body = (await res.json()) as IndexResponse;
            setList(body.currencies ?? []);
            setLoadError(null);
        } catch {
            setLoadError('Network error loading currencies.');
        } finally {
            setLoading(false);
        }
    }, []);

    useEffect(() => {
        void refetch();
    }, [refetch]);

    useEffect(() => {
        if (toast === null) return;
        const t = window.setTimeout(() => setToast(null), 3200);
        return () => window.clearTimeout(t);
    }, [toast]);

    const setDefault = async (currency: Currency) => {
        if (currency.is_default || pendingDefaultId !== null) return;
        setPendingDefaultId(currency.id);
        try {
            const res = await fetch(
                `/admin/settings/currencies/${currency.id}/default`,
                {
                    method: 'POST',
                    credentials: 'same-origin',
                    headers: csrfHeaders(),
                },
            );
            if (!res.ok) {
                const body = await res.json().catch(() => null);
                setToast({
                    kind: 'error',
                    message:
                        body?.message ?? `Could not set default (${res.status}).`,
                });
                return;
            }
            await refetch();
            setToast({
                kind: 'success',
                message: `${currency.code} is now the default currency.`,
            });
        } catch {
            setToast({ kind: 'error', message: 'Network error.' });
        } finally {
            setPendingDefaultId(null);
        }
    };

    return (
        <Card padding="lg" data-testid="admin-settings-currencies">
            <header className="mb-5 flex flex-wrap items-start justify-between gap-3">
                <div>
                    <h2 className="text-base font-semibold tracking-tight text-foreground">
                        Currencies
                    </h2>
                    <p className="mt-1 max-w-2xl text-[12px] text-muted-foreground">
                        Manage the currency list used by the Pricing page and
                        invoice display. Each currency carries its own
                        symbol, position, and separator configuration.
                        Per-(plan, currency) prices are configured under
                        Plans &amp; providers — currencies here drive
                        display only.
                    </p>
                </div>
                <div className="flex shrink-0 items-center gap-2">
                    <Button
                        type="button"
                        variant="primary"
                        size="sm"
                        onClick={() => setShowAddModal(true)}
                        data-testid="admin-currencies-add"
                    >
                        <Plus className="h-3.5 w-3.5" strokeWidth={2.5} />
                        Add currency
                    </Button>
                </div>
            </header>

            {toast && (
                <p
                    className={
                        toast.kind === 'success'
                            ? 'mb-4 flex items-start gap-2 rounded-lg border border-success/30 bg-success/5 px-3 py-2 text-[12px] font-medium text-success'
                            : 'mb-4 flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-[12px] font-medium text-destructive'
                    }
                    role={toast.kind === 'success' ? 'status' : 'alert'}
                    data-testid={`admin-currencies-toast-${toast.kind}`}
                >
                    {toast.kind === 'success' ? (
                        <CheckCircle2
                            className="mt-0.5 h-3.5 w-3.5 shrink-0"
                            strokeWidth={2.5}
                        />
                    ) : (
                        <AlertCircle
                            className="mt-0.5 h-3.5 w-3.5 shrink-0"
                            strokeWidth={2.5}
                        />
                    )}
                    <span className="break-words">{toast.message}</span>
                </p>
            )}

            {loading ? (
                <div
                    className="flex items-center justify-center rounded-lg border border-dashed border-border bg-muted/20 px-4 py-10 text-[12px] text-muted-foreground"
                    data-testid="admin-currencies-loading"
                >
                    <Loader2
                        className="mr-2 h-4 w-4 animate-spin"
                        strokeWidth={2}
                    />
                    Loading currencies…
                </div>
            ) : loadError ? (
                <div
                    className="flex items-center gap-2 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-3 text-[12px] font-medium text-destructive"
                    role="alert"
                    data-testid="admin-currencies-load-error"
                >
                    <AlertCircle className="h-4 w-4" strokeWidth={2.5} />
                    {loadError}
                </div>
            ) : list.length === 0 ? (
                <div
                    className="rounded-lg border border-dashed border-border bg-muted/30 px-4 py-8 text-center text-[12px] text-muted-foreground"
                    data-testid="admin-currencies-empty"
                >
                    No currencies yet — Add your first.
                </div>
            ) : (
                <div className="overflow-x-auto rounded-lg border border-border">
                    <table
                        className="w-full text-left text-[12px]"
                        data-testid="admin-currencies-table"
                    >
                        <thead className="border-b border-border bg-muted/30 text-[11px] font-medium text-muted-foreground">
                            <tr>
                                <th className="px-3 py-2.5">Code</th>
                                <th className="px-3 py-2.5">Name</th>
                                <th className="px-3 py-2.5">Symbol</th>
                                <th className="px-3 py-2.5">Format</th>
                                <th className="px-3 py-2.5">Default</th>
                                <th className="px-3 py-2.5 text-right">
                                    Actions
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            {list.map((c) => (
                                <tr
                                    key={c.id}
                                    className="border-b border-border/40 last:border-b-0 hover:bg-muted/20"
                                    data-testid={`admin-currencies-row-${c.code}`}
                                >
                                    <td className="px-3 py-2.5 font-mono text-[11px] font-medium text-foreground">
                                        {c.code}
                                    </td>
                                    <td className="px-3 py-2.5 text-foreground">
                                        {c.name}
                                    </td>
                                    <td className="px-3 py-2.5 font-mono text-foreground">
                                        {c.symbol ?? (
                                            <span className="text-muted-foreground">
                                                —
                                            </span>
                                        )}
                                    </td>
                                    <td className="px-3 py-2.5 font-mono text-[11px] text-foreground">
                                        {formatCurrency(c, PREVIEW_AMOUNT)}
                                    </td>
                                    <td className="px-3 py-2.5">
                                        {c.is_default ? (
                                            <Pill
                                                tone="accent"
                                                size="sm"
                                                data-testid={`admin-currencies-row-${c.code}-default-pill`}
                                            >
                                                Default
                                            </Pill>
                                        ) : (
                                            <button
                                                type="button"
                                                onClick={() => setDefault(c)}
                                                disabled={
                                                    pendingDefaultId !== null
                                                }
                                                className="text-[11px] font-medium text-accent hover:underline disabled:pointer-events-none disabled:opacity-50"
                                                data-testid={`admin-currencies-row-${c.code}-make-default`}
                                            >
                                                {pendingDefaultId === c.id
                                                    ? 'Setting…'
                                                    : 'Make default'}
                                            </button>
                                        )}
                                    </td>
                                    <td className="px-3 py-2.5">
                                        <div className="flex items-center justify-end gap-1">
                                            <button
                                                type="button"
                                                onClick={() => setEditTarget(c)}
                                                className="inline-flex items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium text-muted-foreground hover:bg-muted hover:text-foreground"
                                                data-testid={`admin-currencies-row-${c.code}-edit`}
                                            >
                                                <Pencil
                                                    className="h-3 w-3"
                                                    strokeWidth={2}
                                                />
                                                Edit
                                            </button>
                                            {!c.is_default && (
                                                <button
                                                    type="button"
                                                    onClick={() =>
                                                        setDeleteTarget(c)
                                                    }
                                                    className="inline-flex items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium text-destructive hover:bg-destructive/10"
                                                    data-testid={`admin-currencies-row-${c.code}-delete`}
                                                >
                                                    <Trash2
                                                        className="h-3 w-3"
                                                        strokeWidth={2}
                                                    />
                                                    Delete
                                                </button>
                                            )}
                                        </div>
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            )}

            {showAddModal && (
                <CurrencyModal
                    title="Add currency"
                    submitLabel="Add currency"
                    initial={EMPTY_FORM}
                    onClose={() => setShowAddModal(false)}
                    onSaved={async (msg) => {
                        await refetch();
                        setShowAddModal(false);
                        setToast({ kind: 'success', message: msg });
                    }}
                    submit={async (payload) => {
                        const res = await fetch(
                            '/admin/settings/currencies',
                            {
                                method: 'POST',
                                credentials: 'same-origin',
                                headers: csrfHeaders(),
                                body: JSON.stringify(payload),
                            },
                        );
                        return res;
                    }}
                    successMessage={(payload) =>
                        `Added ${payload.code.toUpperCase()}.`
                    }
                />
            )}

            {editTarget && (
                <CurrencyModal
                    title={`Edit ${editTarget.code}`}
                    submitLabel="Save changes"
                    initial={currencyToForm(editTarget)}
                    codeLocked={false}
                    onClose={() => setEditTarget(null)}
                    onSaved={async (msg) => {
                        await refetch();
                        setEditTarget(null);
                        setToast({ kind: 'success', message: msg });
                    }}
                    submit={async (payload) => {
                        const res = await fetch(
                            `/admin/settings/currencies/${editTarget.id}`,
                            {
                                method: 'PATCH',
                                credentials: 'same-origin',
                                headers: csrfHeaders(),
                                body: JSON.stringify(payload),
                            },
                        );
                        return res;
                    }}
                    successMessage={() => `Updated ${editTarget.code}.`}
                />
            )}

            {deleteTarget && (
                <DeleteCurrencyConfirm
                    currency={deleteTarget}
                    onCancel={() => setDeleteTarget(null)}
                    onDeleted={async () => {
                        const code = deleteTarget.code;
                        await refetch();
                        setDeleteTarget(null);
                        setToast({
                            kind: 'success',
                            message: `Deleted ${code}.`,
                        });
                    }}
                    onError={(message) => {
                        setDeleteTarget(null);
                        setToast({ kind: 'error', message });
                    }}
                />
            )}
        </Card>
    );
}

type ModalPayload = {
    name: string;
    code: string;
    symbol: string | null;
    position: CurrencyPosition;
    no_of_decimal: number;
    thousand_separator: string | null;
    decimal_separator: string | null;
};

function CurrencyModal({
    title,
    submitLabel,
    initial,
    onClose,
    onSaved,
    submit,
    successMessage,
    codeLocked = false,
}: {
    title: string;
    submitLabel: string;
    initial: FormState;
    onClose: () => void;
    onSaved: (message: string) => void | Promise<void>;
    submit: (payload: ModalPayload) => Promise<Response>;
    successMessage: (payload: ModalPayload) => string;
    codeLocked?: boolean;
}) {
    const [form, setForm] = useState<FormState>(initial);
    const [errors, setErrors] = useState<Record<string, string>>({});
    const [globalError, setGlobalError] = useState<string | null>(null);
    const [saving, setSaving] = useState(false);

    const set = useCallback(
        <K extends keyof FormState>(key: K, value: FormState[K]) => {
            setForm((prev) => ({ ...prev, [key]: value }));
            setErrors((prev) => {
                if (!(key in prev)) return prev;
                const next = { ...prev };
                delete next[key as string];
                return next;
            });
        },
        [],
    );

    const previewDecimals = useMemo(() => {
        const n = parseInt(form.no_of_decimal, 10);
        return Number.isFinite(n) ? n : 0;
    }, [form.no_of_decimal]);

    const preview = useMemo(
        () =>
            formatPreview(PREVIEW_AMOUNT, {
                symbol: form.symbol,
                position: form.position,
                decimals: previewDecimals,
                thousandSep: form.thousand_separator,
                decimalSep: form.decimal_separator,
            }),
        [
            form.symbol,
            form.position,
            previewDecimals,
            form.thousand_separator,
            form.decimal_separator,
        ],
    );

    const onSubmit = async (e?: ReactSubmitEvent<HTMLFormElement>) => {
        e?.preventDefault();
        setSaving(true);
        setErrors({});
        setGlobalError(null);

        const code = form.code.trim().toUpperCase();
        const localErrors: Record<string, string> = {};
        if (form.name.trim() === '') {
            localErrors.name = 'Name is required.';
        }
        if (!/^[A-Z]{3}$/.test(code)) {
            localErrors.code = 'Code must be exactly 3 letters (e.g. USD).';
        }
        const decimalsNum = parseInt(form.no_of_decimal, 10);
        if (
            !Number.isFinite(decimalsNum) ||
            decimalsNum < 0 ||
            decimalsNum > 6
        ) {
            localErrors.no_of_decimal =
                'Decimals must be a whole number 0–6.';
        }
        if (Object.keys(localErrors).length > 0) {
            setErrors(localErrors);
            setSaving(false);
            return;
        }

        const payload: ModalPayload = {
            name: form.name.trim(),
            code,
            symbol: form.symbol === '' ? null : form.symbol,
            position: form.position,
            no_of_decimal: decimalsNum,
            thousand_separator:
                form.thousand_separator === '' ? null : form.thousand_separator,
            decimal_separator:
                form.decimal_separator === '' ? null : form.decimal_separator,
        };

        try {
            const res = await submit(payload);
            if (!res.ok) {
                const body = await res.json().catch(() => null);
                if (
                    res.status === 422 &&
                    body?.errors &&
                    typeof body.errors === 'object'
                ) {
                    const fieldErrors: Record<string, string> = {};
                    for (const [field, msgs] of Object.entries(body.errors)) {
                        const arr = Array.isArray(msgs) ? msgs : [msgs];
                        if (arr.length > 0 && typeof arr[0] === 'string') {
                            fieldErrors[field] = arr[0];
                        }
                    }
                    setErrors(fieldErrors);
                }
                setGlobalError(
                    typeof body?.message === 'string'
                        ? body.message
                        : `Save failed (${res.status}).`,
                );
                return;
            }
            await onSaved(successMessage(payload));
        } catch {
            setGlobalError('Network error. Try again.');
        } finally {
            setSaving(false);
        }
    };

    return (
        <Modal
            open
            onClose={onClose}
            size="md"
            closeOnBackdrop={false}
            closeOnEsc={!saving}
            data-testid="admin-currencies-modal"
        >
                {/*
                  Intentionally NOT a <form> (no `onSubmit`): the Settings page
                  wraps every active tab in a top-level <form>, and nested forms
                  collapse in HTML5 — an inner submit would submit the OUTER form
                  and redirect to /admin/settings without saving the modal. Save
                  is wired through the button's onClick instead.
                */}
                <Modal.Header
                    title={title}
                    actions={
                        <button
                            type="button"
                            onClick={onClose}
                            disabled={saving}
                            className="rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
                            aria-label="Close"
                            data-testid="admin-currencies-modal-close"
                        >
                            <X className="h-4 w-4" strokeWidth={2} />
                        </button>
                    }
                />

                <Modal.Body
                    fade={false}
                    className="space-y-4"
                    data-testid="admin-currencies-modal-form"
                >
                        {globalError && (
                            <div
                                className="flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2 text-[11px] font-medium text-destructive"
                                role="alert"
                                data-testid="admin-currencies-modal-error"
                            >
                                <AlertCircle
                                    className="mt-0.5 h-3.5 w-3.5"
                                    strokeWidth={2.5}
                                />
                                <span>{globalError}</span>
                            </div>
                        )}

                        <div className="grid gap-4 sm:grid-cols-2">
                            <ModalField
                                label="Name"
                                error={errors.name}
                                htmlFor="cur_name"
                            >
                                <Input
                                    id="cur_name"
                                    value={form.name}
                                    onChange={(e) =>
                                        set('name', e.target.value)
                                    }
                                    invalid={Boolean(errors.name)}
                                    placeholder="US Dollar"
                                    data-testid="admin-currencies-modal-name"
                                />
                            </ModalField>

                            <ModalField
                                label="Code"
                                error={errors.code}
                                htmlFor="cur_code"
                                hint="ISO 4217 — three uppercase letters."
                            >
                                <Input
                                    id="cur_code"
                                    value={form.code}
                                    onChange={(e) =>
                                        set(
                                            'code',
                                            e.target.value
                                                .replace(/[^a-zA-Z]/g, '')
                                                .slice(0, 3)
                                                .toUpperCase(),
                                        )
                                    }
                                    invalid={Boolean(errors.code)}
                                    disabled={codeLocked}
                                    placeholder="USD"
                                    autoCapitalize="characters"
                                    data-testid="admin-currencies-modal-code"
                                />
                            </ModalField>
                        </div>

                        <div className="grid gap-4 sm:grid-cols-2">
                            <ModalField
                                label="Symbol"
                                error={errors.symbol}
                                htmlFor="cur_symbol"
                                hint="Optional — leave blank to show only the code."
                            >
                                <Input
                                    id="cur_symbol"
                                    value={form.symbol}
                                    maxLength={8}
                                    onChange={(e) =>
                                        set('symbol', e.target.value)
                                    }
                                    invalid={Boolean(errors.symbol)}
                                    placeholder="$"
                                    data-testid="admin-currencies-modal-symbol"
                                />
                            </ModalField>

                            <div className="space-y-1.5">
                                <Label htmlFor="cur_position">Position</Label>
                                <Select
                                    id="cur_position"
                                    value={form.position}
                                    onChange={(e) =>
                                        set(
                                            'position',
                                            e.target.value as CurrencyPosition,
                                        )
                                    }
                                    data-testid="admin-currencies-modal-position"
                                >
                                    {POSITION_OPTIONS.map((opt) => (
                                        <option key={opt.value} value={opt.value}>
                                            {opt.label}
                                        </option>
                                    ))}
                                </Select>
                                {errors.position && (
                                    <p className="text-[11px] font-medium text-destructive">
                                        {errors.position}
                                    </p>
                                )}
                            </div>
                        </div>

                        <div className="grid gap-4 sm:grid-cols-3">
                            <ModalField
                                label="Decimals"
                                error={errors.no_of_decimal}
                                htmlFor="cur_decimals"
                            >
                                <Input
                                    id="cur_decimals"
                                    type="number"
                                    min={0}
                                    max={6}
                                    value={form.no_of_decimal}
                                    onChange={(e) =>
                                        set('no_of_decimal', e.target.value)
                                    }
                                    invalid={Boolean(errors.no_of_decimal)}
                                    data-testid="admin-currencies-modal-decimals"
                                />
                            </ModalField>

                            <ModalField
                                label="Thousand separator"
                                error={errors.thousand_separator}
                                htmlFor="cur_thousand"
                            >
                                <Input
                                    id="cur_thousand"
                                    value={form.thousand_separator}
                                    maxLength={4}
                                    onChange={(e) =>
                                        set(
                                            'thousand_separator',
                                            e.target.value,
                                        )
                                    }
                                    invalid={Boolean(errors.thousand_separator)}
                                    placeholder=","
                                    data-testid="admin-currencies-modal-thousand"
                                />
                            </ModalField>

                            <ModalField
                                label="Decimal separator"
                                error={errors.decimal_separator}
                                htmlFor="cur_decimal"
                            >
                                <Input
                                    id="cur_decimal"
                                    value={form.decimal_separator}
                                    maxLength={4}
                                    onChange={(e) =>
                                        set(
                                            'decimal_separator',
                                            e.target.value,
                                        )
                                    }
                                    invalid={Boolean(errors.decimal_separator)}
                                    placeholder="."
                                    data-testid="admin-currencies-modal-decimal"
                                />
                            </ModalField>
                        </div>

                        <div className="rounded-lg border border-border/60 bg-muted/30 px-3 py-3">
                            <div className="text-[11px] font-medium text-muted-foreground">
                                Format preview
                            </div>
                            <div
                                className="mt-1 font-mono text-base text-foreground"
                                data-testid="admin-currencies-modal-preview"
                            >
                                {preview}
                            </div>
                            <div className="mt-1 text-[11px] text-muted-foreground">
                                Reference value: 1234567.89
                            </div>
                        </div>
                </Modal.Body>

                <Modal.Footer>
                        <Button
                            type="button"
                            variant="ghost"
                            size="sm"
                            onClick={onClose}
                            disabled={saving}
                            data-testid="admin-currencies-modal-cancel"
                        >
                            Cancel
                        </Button>
                        <Button
                            type="button"
                            variant="primary"
                            size="sm"
                            onClick={() => void onSubmit()}
                            disabled={saving}
                            data-testid="admin-currencies-modal-save"
                        >
                            {saving ? (
                                <Loader2
                                    className="h-3.5 w-3.5 animate-spin"
                                    strokeWidth={2}
                                />
                            ) : null}
                            {submitLabel}
                        </Button>
                </Modal.Footer>
        </Modal>
    );
}

function ModalField({
    label,
    error,
    htmlFor,
    hint,
    children,
}: {
    label: string;
    error?: string;
    htmlFor: string;
    hint?: ReactNode;
    children: ReactNode;
}) {
    return (
        <div className="space-y-1.5">
            <Label htmlFor={htmlFor}>{label}</Label>
            {children}
            {error ? (
                <p className="text-[11px] font-medium text-destructive">
                    {error}
                </p>
            ) : hint ? (
                <p className="text-[11px] text-muted-foreground">{hint}</p>
            ) : null}
        </div>
    );
}

function DeleteCurrencyConfirm({
    currency,
    onCancel,
    onDeleted,
    onError,
}: {
    currency: Currency;
    onCancel: () => void;
    onDeleted: () => void | Promise<void>;
    onError: (message: string) => void;
}) {
    const [busy, setBusy] = useState(false);
    const [error, setError] = useState<string | null>(null);

    const onConfirm = async () => {
        setBusy(true);
        setError(null);
        try {
            const res = await fetch(
                `/admin/settings/currencies/${currency.id}`,
                {
                    method: 'DELETE',
                    credentials: 'same-origin',
                    headers: csrfHeaders(),
                },
            );
            if (!res.ok) {
                const body = await res.json().catch(() => null);
                const message =
                    typeof body?.message === 'string'
                        ? body.message
                        : `Delete failed (${res.status}).`;
                if (res.status === 422) {
                    setError(message);
                } else {
                    onError(message);
                }
                return;
            }
            await onDeleted();
        } catch {
            setError('Network error. Try again.');
        } finally {
            setBusy(false);
        }
    };

    return (
        <Modal
            open
            onClose={onCancel}
            size="md"
            closeOnBackdrop={false}
            closeOnEsc={!busy}
            data-testid="admin-currencies-delete-modal"
        >
            <Modal.Header
                eyebrow="Delete currency"
                eyebrowClassName="text-destructive"
                title={
                    <>
                        {currency.name}{' '}
                        <span className="font-mono text-base text-muted-foreground">
                            ({currency.code})
                        </span>
                    </>
                }
            />
            <Modal.Body fade={false}>
                <p className="text-sm text-muted-foreground">
                    Removes this currency from the list. Plan-price
                    rows referencing it will block the delete with a
                    clean error. Cannot be undone.
                </p>
                {error && (
                    <p
                        className="text-[12px] font-medium text-destructive"
                        data-testid="admin-currencies-delete-error"
                    >
                        {error}
                    </p>
                )}
            </Modal.Body>
            <Modal.Footer>
                <Button
                    type="button"
                    variant="ghost"
                    size="sm"
                    onClick={onCancel}
                    disabled={busy}
                    data-testid="admin-currencies-delete-cancel"
                >
                    Cancel
                </Button>
                <Button
                    type="button"
                    variant="danger"
                    size="sm"
                    onClick={onConfirm}
                    disabled={busy}
                    data-testid="admin-currencies-delete-confirm"
                >
                    {busy ? (
                        <Loader2
                            className="h-3.5 w-3.5 animate-spin"
                            strokeWidth={2}
                        />
                    ) : null}
                    Delete
                </Button>
            </Modal.Footer>
        </Modal>
    );
}
