// General Affairs — "GA Processing" detail (Phase 4, 2026-07-24).
// Built on the frozen GA detail grammar (ReviewGaDetail) + the Create add-lines editor.
// GA records per-line Fixed Price / Fixed Guarantee, attaches a MANDATORY GA document, and may
// add brand-new service lines; "GA Processing" writes status → 5 (VehicleServiceRequestController
// @gaProcessingAct). Rejected lines stay frozen + pink. Revise → 8.
import { useMemo, useRef, useState } from 'react';
import { Link, router } from '@inertiajs/react';
import { ArrowLeft, Car, ClipboardList, FileUp, ListOrdered, Plus, Trash2, Wallet, Wrench, X } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { StatusBadge } from '@/Components/Proto/UI/StatusBadge';
import { HistoryPopover } from '@/Components/MenuQuotations/QuotationDetailPage/HistoryPopover';
import { HistoryTimelinePopover } from '@/Components/MenuQuotations/QuotationDetailPage/HistoryTimelinePopover';
import { DecisionBar } from '@/Components/MenuSampleOrders/DecisionBar';
import { DecisionConfirmDialog } from '@/Components/MenuSampleOrders/DecisionConfirmDialog';
import { PrintReportButton } from '@/Components/MenuGeneralAffairs/PrintReportButton';
import { useToast } from '@/Components/Toast';

const DOC_SECTION = 'relative rounded-xl border border-border bg-card px-4 pt-3.5 pb-3 shadow-sm';
const DOC_HEADING = 'm-0 mb-3 flex items-center gap-2 text-xs font-bold uppercase tracking-wide text-foreground';
const DOC_ICON = 'inline-grid size-6 shrink-0 place-items-center rounded-full border border-primary/50 bg-transparent text-primary';
const BACK_BTN = 'inline-flex h-9 items-center justify-center gap-1.5 rounded-lg border border-input bg-card px-4 text-center text-xs font-bold text-foreground transition-colors hover:border-primary hover:text-primary';

const BAR_BTN = 'inline-flex h-9 flex-1 items-center justify-center whitespace-nowrap rounded-lg px-3.5 text-xs font-bold transition-colors sm:flex-none';
const BAR_BTN_PRIMARY = 'inline-flex h-9 flex-1 items-center justify-center whitespace-nowrap rounded-lg bg-linear-to-br from-violet-500 to-primary px-3.5 text-xs font-bold text-white shadow-sm transition-[filter] hover:brightness-105 sm:flex-none';
const CELL_INPUT = 'h-8 w-full min-w-[92px] rounded-md border border-input bg-card px-2 text-[12px] font-medium text-foreground outline-none transition-colors focus-visible:border-primary disabled:cursor-not-allowed disabled:bg-muted/40 disabled:text-muted-foreground';
const FIELD = 'h-9 w-full rounded-md border border-input bg-card px-2.5 text-[12px] font-medium text-foreground outline-none transition-colors focus-visible:border-primary';

const DETAIL_TABLE =
    'w-full border-separate border-spacing-0 ' +
    '[&_thead_th]:whitespace-nowrap [&_thead_th]:border-b [&_thead_th]:border-border [&_thead_th]:px-3 [&_thead_th]:py-3 [&_thead_th]:text-left [&_thead_th]:text-[11px] [&_thead_th]:font-semibold [&_thead_th]:uppercase [&_thead_th]:tracking-wide [&_thead_th]:text-muted-foreground/80 ' +
    '[&_th:first-child]:pl-[22px] [&_td:first-child]:pl-[22px] [&_th:last-child]:pr-5 [&_td:last-child]:pr-5 ' +
    '[&_th.number]:text-right [&_td.number]:text-right [&_th.text-center]:text-center [&_td.text-center]:text-center ' +
    '[&_tbody_td]:whitespace-nowrap [&_tbody_td]:border-b [&_tbody_td]:border-border/50 [&_tbody_td]:px-3 [&_tbody_td]:py-3 [&_tbody_td]:align-top [&_tbody_td]:text-[12px] [&_tbody_td]:font-medium [&_tbody_td]:text-foreground [&_tbody_tr:last-child_td]:border-b-0 ' +
    '[&_tbody_tr:nth-child(even)_td]:bg-secondary/25 [&_tbody_tr:hover_td]:bg-secondary/60';

const STATUS_TONE = {
    'Request': 'primary', 'Review GA': 'warning', 'Approval GA': 'success', 'Finance Down Payment': 'primary',
    'GA Processing': 'primary', 'Finance Settlement': 'primary', 'GA Completion': 'success',
    'Revise': 'warning', 'Reject': 'danger', 'Cancel': 'danger', 'Re-Review': 'warning',
};
const statusTone = (name) => STATUS_TONE[name] ?? 'neutral';
const fmtNum = (v) => (v == null || v === '' ? '—' : Number(v).toLocaleString('en-US', { minimumFractionDigits: 2 }));
const fmtMoney = (v) => `Rp ${Number(v ?? 0).toLocaleString('en-US', { minimumFractionDigits: 2 })}`;
const fmtCurrencyInput = (v) => {
    const raw = String(v ?? '').replace(/[^\d.]/g, '');
    const [int, ...rest] = raw.split('.');
    const grouped = (int || '').replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return rest.length ? `${grouped}.${rest.join('')}` : grouped;
};
const filled = (v) => v != null && String(v).trim() !== '' && v !== '—';
const MAX_GA_BYTES = 1024 * 1024; // legacy cap: 1 MB
const Prose = ({ children }) =>
    filled(children) ? <span className="block min-w-44 max-w-72 whitespace-normal break-words leading-relaxed">{children}</span> : '—';

function DocList({ fields, columns = 1 }) {
    if (!fields || Object.keys(fields).length === 0)
        return <p className="px-0 py-1 text-[0.82rem] text-muted-foreground">No data.</p>;
    if (columns === 2) {
        return (
            <dl className="grid grid-cols-2 gap-x-4 gap-y-0 [&>div:nth-last-child(-n+2)]:border-b-0 max-[520px]:grid-cols-1">
                {Object.entries(fields).map(([key, val]) => (
                    <div key={key} className="border-b border-border/40 py-1.75">
                        <dt className="m-0 text-[11px] font-medium text-muted-foreground">{key}</dt>
                        <dd className="m-0 mt-0.5 wrap-break-word text-xs font-medium text-foreground">{val || '—'}</dd>
                    </div>
                ))}
            </dl>
        );
    }
    return (
        <dl className="grid gap-0">
            {Object.entries(fields).map(([key, val]) => (
                <div key={key} className="grid grid-cols-[minmax(0,120px)_1fr] items-baseline gap-2.5 border-b border-border/40 py-1.75 last:border-b-0">
                    <dt className="m-0 text-[11px] font-medium text-muted-foreground">{key}</dt>
                    <dd className="m-0 wrap-break-word text-xs font-medium text-foreground">{val || '—'}</dd>
                </div>
            ))}
        </dl>
    );
}

export default function GaProcessingDetail({ request, lines, history, serviceTypes = [] }) {
    const vsr = request;
    const vehicle = request.vehicle;
    const { show: showToast } = useToast();

    // Per-line fixed pricing (active lines only). Seeded from any current fixed values.
    const [rows, setRows] = useState(() => lines.filter((l) => !l.isRejected).reduce((acc, l) => {
        acc[l.id] = {
            fixedPrice: l.fixedPrice ? fmtCurrencyInput(String(l.fixedPrice)) : '',
            fixedGuarantee: l.fixedGuarantee ?? '',
        };
        return acc;
    }, {}));
    const setRow = (id, key, value) => setRows((prev) => ({ ...prev, [id]: { ...prev[id], [key]: value } }));

    // GA document (mandatory).
    const [gaFile, setGaFile] = useState(null);
    const fileRef = useRef(null);
    const pickFile = (e) => {
        const f = e.target.files?.[0] ?? null;
        if (f && f.size > MAX_GA_BYTES) {
            showToast('GA document is larger than 1 MB — please choose a smaller file.', 'error');
            e.target.value = ''; setGaFile(null); return;
        }
        setGaFile(f);
    };
    const clearFile = () => { setGaFile(null); if (fileRef.current) fileRef.current.value = ''; };

    // Add New Item editor.
    const [draft, setDraft] = useState({ type: '', date: '', remark: '', brand: '', place: '', fixedPrice: '', fixedGuarantee: '' });
    const setDraftField = (k) => (e) => setDraft((s) => ({ ...s, [k]: k === 'fixedPrice' ? fmtCurrencyInput(e.target.value) : e.target.value }));
    const [newLines, setNewLines] = useState([]);
    const addLine = () => {
        const missing = [];
        if (!draft.type) missing.push('Service Type');
        if (!draft.date) missing.push('Service Date');
        if (!draft.remark.trim()) missing.push('Remark');
        if (!draft.brand.trim()) missing.push('Brand');
        if (!draft.place.trim()) missing.push('Place');
        if (!String(draft.fixedPrice).trim()) missing.push('Fix Price');
        if (!draft.fixedGuarantee.trim()) missing.push('Fix Guarantee');
        if (missing.length) { showToast(`Required: ${missing.join(', ')}.`, 'warning'); return; }
        const typeName = serviceTypes.find((t) => String(t.id) === String(draft.type))?.name ?? '';
        setNewLines((prev) => [...prev, { ...draft, typeName }]);
        setDraft({ type: '', date: '', remark: '', brand: '', place: '', fixedPrice: '', fixedGuarantee: '' });
    };
    const removeNewLine = (i) => setNewLines((prev) => prev.filter((_, n) => n !== i));

    const [decision, setDecision] = useState(null);
    const [comment, setComment] = useState('');
    const [processing, setProcessing] = useState(false);
    const pick = (dialogAction, routeAction, label) => { setComment(''); setDecision({ dialogAction, routeAction, label }); };
    const activeLines = useMemo(() => lines.filter((l) => !l.isRejected), [lines]);

    const confirm = () => {
        if (!decision) return;
        if (decision.routeAction === 'revise') { post('revise', { comment }); return; }

        // process: GA file + a fixed price/guarantee for every active line.
        if (!gaFile) { showToast('Attach the GA document before processing.', 'warning'); return; }
        const incomplete = activeLines.some((l) => !String(rows[l.id]?.fixedPrice ?? '').trim() || !String(rows[l.id]?.fixedGuarantee ?? '').trim());
        if (incomplete) { showToast('Enter a Fixed Price and Fixed Guarantee for every active line.', 'warning'); return; }

        post('process', {
            comment,
            ga_file: gaFile,
            lines: activeLines.map((l) => ({
                id: l.id,
                fixed_price: String(rows[l.id]?.fixedPrice ?? '').replace(/,/g, ''),
                fixed_guarantee: rows[l.id]?.fixedGuarantee ?? '',
            })),
            new_lines: newLines.map((n) => ({
                type: n.type, date: n.date, remark: n.remark.trim(), brand: n.brand.trim(), place: n.place.trim(),
                fixed_price: String(n.fixedPrice).replace(/,/g, ''), fixed_guarantee: n.fixedGuarantee.trim(),
            })),
        }, true);
    };

    const post = (routeAction, payload, multipart = false) => {
        setProcessing(true);
        router.post(route('general-affairs.ga-processing.act', [vsr.id, routeAction]), payload, {
            forceFormData: multipart,
            preserveScroll: true,
            onSuccess: () => setDecision(null),
            onError: () => showToast('Please check the form and try again.', 'error'),
            onFinish: () => setProcessing(false),
        });
    };

    const requestFields = {
        'No': vsr.id,
        'Created Date': vsr.tanggal || '—',
        'Status': vsr.statusName || '—',
        'Creator': vsr.creator || '—',
        'Owner': vsr.owner || '—',
        'KM': filled(vsr.km) ? `${vsr.km} KM` : '—',
        'Req Remark': vsr.remark || '—',
        'Download File': vsr.hasUpload
            ? <a href={vsr.uploadUrl} className="font-semibold text-primary hover:underline">{vsr.uploadName || 'Download'}</a>
            : 'No File',
    };
    const vehicleFields = vehicle ? {
        'Brand Name': vehicle.brandName || '—',
        'Brand Type': vehicle.brandType || '—',
        'Color': vehicle.color || '—',
        'Production Year': vehicle.productionYear || '—',
        'Lisence Plate': vehicle.plate || '—',
        'Lisence Expiry Date': vehicle.licenseExpiry || '—',
        'Insurance': vehicle.insurance || '—',
        'Insurance Expiry Date': vehicle.insuranceExpiry || '—',
        'Chassis Number': vehicle.chassisNumber || '—',
        'Engine Number': vehicle.engineNumber || '—',
        'Vehicle Desc': vehicle.description || '—',
    } : null;

    return (
        <section className="flex min-w-0 flex-col gap-4.5">
            <header className="flex flex-wrap items-start justify-between gap-3">
                <div>
                    <p className="mb-1.5 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
                        <span>General Affair</span>
                        <span aria-hidden="true">›</span>
                        <Link href={route('general-affairs.ga-processing')} className="text-foreground no-underline hover:text-primary">GA Processing</Link>
                    </p>
                </div>
                <div className="flex items-center gap-2">
                    <PrintReportButton request={request} lines={lines} history={history} />
                    <HistoryTimelinePopover entries={(history ?? []).map((h) => ({ Status: h.statusName || '—', Tanggal: h.tanggal || '—', User: h.userName || '—', Comment: h.comment || '' }))}
                        label="History"
                        triggerClassName="border-input bg-card text-foreground hover:border-primary hover:text-primary" />
                    <Link href={route('general-affairs.ga-processing')} className={BACK_BTN}>
                        <ArrowLeft className="size-3.5" /> Back to List
                    </Link>
                </div>
            </header>

            <div className="mt-1 flex items-center justify-between gap-4">
                <div className="flex min-w-0 flex-col gap-1">
                    <div className="flex flex-wrap items-center gap-3">
                        <h1 className="m-0 text-2xl font-extrabold tracking-tight text-foreground max-[560px]:text-xl">GA Processing — Vehicle Service Request #{vsr.id}</h1>
                        {vsr.statusName && <StatusBadge tone={statusTone(vsr.statusName)}>{vsr.statusName}</StatusBadge>}
                    </div>
                    {vsr.tanggal && <p className="m-0 text-[12px] font-medium text-muted-foreground">Created on {vsr.tanggal}</p>}
                </div>
            </div>

            <div className="grid grid-cols-3 gap-3.5 max-[1180px]:grid-cols-2 max-[860px]:grid-cols-1">
                <section className={DOC_SECTION} data-section-id="request">
                    <h3 className={DOC_HEADING}><span className={DOC_ICON} aria-hidden="true"><ClipboardList className="size-3.5" /></span>Request Information</h3>
                    <DocList fields={requestFields} />
                </section>
                <section className={DOC_SECTION} data-section-id="vehicle">
                    <h3 className={DOC_HEADING}><span className={DOC_ICON} aria-hidden="true"><Car className="size-3.5" /></span>Vehicle</h3>
                    <DocList fields={vehicleFields} columns={2} />
                </section>
                <section className={DOC_SECTION} data-section-id="ga">
                    <h3 className={DOC_HEADING}><span className={DOC_ICON} aria-hidden="true"><Wallet className="size-3.5" /></span>GA Processing</h3>
                    <dl className="grid gap-0">
                        <div className="grid grid-cols-[minmax(0,120px)_1fr] items-baseline gap-2.5 border-b border-border/40 py-1.75">
                            <dt className="m-0 text-[11px] font-medium text-muted-foreground">Down Payment</dt>
                            <dd className="m-0 text-xs font-semibold tabular-nums text-foreground">{fmtMoney(vsr.totalCashBon)}</dd>
                        </div>
                        <div className="py-2">
                            <dt className="m-0 mb-1.5 text-[11px] font-medium text-muted-foreground">GA Document <span className="text-destructive">*</span></dt>
                            <dd className="m-0">
                                <label className="relative flex h-10 cursor-pointer items-center gap-2 rounded-lg border border-input bg-card px-3 transition-colors hover:border-primary/50 hover:bg-accent/20">
                                    <input ref={fileRef} type="file" accept="application/pdf,image/*" onChange={pickFile} className="hidden" />
                                    <FileUp className="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
                                    {gaFile ? (
                                        <>
                                            <span className="min-w-0 truncate text-[12px] font-semibold text-foreground">{gaFile.name}</span>
                                            <button type="button" onClick={(e) => { e.preventDefault(); e.stopPropagation(); clearFile(); }} aria-label="Remove file"
                                                className="grid size-5 shrink-0 place-items-center rounded text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive"><X className="size-3.5" /></button>
                                        </>
                                    ) : (
                                        <span className="min-w-0 truncate text-[12px]">
                                            <span className="font-semibold text-primary">Choose File</span>{' '}
                                            <span className="font-medium text-muted-foreground">PDF/image · max 1 MB</span>
                                        </span>
                                    )}
                                </label>
                            </dd>
                        </div>
                    </dl>
                </section>
            </div>

            {/* Details List — active lines get editable Fixed Price / Guarantee; rejected frozen + pink */}
            <article className="rounded-2xl border border-border bg-card shadow-sm">
                <header className="flex items-center justify-between gap-3 border-b border-border p-[18px_22px]">
                    <div className="flex items-center gap-2.5">
                        <span className={DOC_ICON} aria-hidden="true"><ListOrdered className="size-3.5" /></span>
                        <div className="[&>h2]:m-0 [&>h2]:text-sm [&>h2]:font-extrabold [&>h2]:leading-[1.2] [&>h2]:text-card-foreground [&>small]:block [&>small]:text-[11px] [&>small]:font-medium [&>small]:text-muted-foreground">
                            <h2>Details List</h2>
                            <small>Enter the fixed price and guarantee for each line; rejected lines are frozen.</small>
                        </div>
                    </div>
                </header>

                {lines.length === 0 ? (
                    <p className="p-6 text-[0.85rem] text-muted-foreground">No line items.</p>
                ) : (
                    <div className="overflow-x-auto rounded-b-2xl">
                        <table className={`${DETAIL_TABLE} min-w-[1120px]`}>
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Service Type</th>
                                    <th>Service Date</th>
                                    <th>Brand</th>
                                    <th>Place</th>
                                    <th className="number">Est. Price</th>
                                    <th className="number">Fixed Price</th>
                                    <th>Fixed Guarantee</th>
                                    <th>Remark</th>
                                    <th className="!text-center">Historical</th>
                                    <th className="!text-center">History</th>
                                </tr>
                            </thead>
                            <tbody>
                                {lines.map((d) => {
                                    const r = rows[d.id];
                                    const on = !d.isRejected;
                                    return (
                                        <tr key={d.id} className={d.isRejected ? '[&>td]:!bg-destructive/5' : undefined}>
                                            <td className="tabular-nums">{d.id}</td>
                                            <td>{d.typeName || '—'}</td>
                                            <td className="tabular-nums">{d.serviceDate || '—'}</td>
                                            <td>{d.brand || '—'}</td>
                                            <td>{d.place || '—'}</td>
                                            <td className="number tabular-nums">{fmtNum(d.estimatedPrice)}</td>
                                            <td className="number">
                                                {on ? (
                                                    <input type="text" inputMode="numeric" className={`${CELL_INPUT} text-right`}
                                                        value={r?.fixedPrice ?? ''} onChange={(e) => setRow(d.id, 'fixedPrice', fmtCurrencyInput(e.target.value))} placeholder="0" aria-label={`Fixed price line ${d.id}`} />
                                                ) : <span className="tabular-nums text-muted-foreground">{fmtNum(d.fixedPrice)}</span>}
                                            </td>
                                            <td>
                                                {on ? (
                                                    <input type="text" className={CELL_INPUT} value={r?.fixedGuarantee ?? ''} onChange={(e) => setRow(d.id, 'fixedGuarantee', e.target.value)} placeholder="e.g. 6 bulan" aria-label={`Fixed guarantee line ${d.id}`} />
                                                ) : (d.fixedGuarantee || '—')}
                                            </td>
                                            <td><Prose>{d.remark}</Prose></td>
                                            <td className="text-center">
                                                <HistoryPopover count={(d.historical ?? []).length} title="Historical Service" width={320}>
                                                    {(d.historical ?? []).map((s, i) => (
                                                        <div key={i} className="text-[11px] leading-snug text-muted-foreground">
                                                            <span className="font-semibold text-foreground">{s.brand || '—'} ({s.place || '—'})</span>{' · '}
                                                            <span className="tabular-nums">{fmtNum(s.fixedPrice)}</span>
                                                        </div>
                                                    ))}
                                                </HistoryPopover>
                                            </td>
                                            <td className="text-center">
                                                <HistoryPopover count={(d.history ?? []).length} title="History" width={320}>
                                                    {(d.history ?? []).map((h, i) => (
                                                        <div key={i} className="text-[11px] leading-snug text-muted-foreground">
                                                            <span className="font-semibold text-foreground">{h.statusName || '—'}</span>
                                                            {h.tanggal ? <> · <span className="tabular-nums">{h.tanggal}</span></> : null}
                                                            {h.userName ? ` · ${h.userName}` : ''}
                                                            {h.brand ? ` · ${h.brand}` : ''}
                                                            {h.remark ? ` · ${h.remark}` : ''}
                                                        </div>
                                                    ))}
                                                </HistoryPopover>
                                            </td>
                                        </tr>
                                    );
                                })}
                            </tbody>
                        </table>
                    </div>
                )}
            </article>

            {/* Add New Item to details */}
            <article className="rounded-2xl border border-border bg-card p-5 shadow-sm">
                <header className="mb-4 flex items-center gap-2.5">
                    <span className={DOC_ICON} aria-hidden="true"><Wrench className="size-3.5" /></span>
                    <div className="[&>h2]:m-0 [&>h2]:text-sm [&>h2]:font-extrabold [&>h2]:leading-[1.2] [&>h2]:text-card-foreground [&>small]:block [&>small]:text-[11px] [&>small]:font-medium [&>small]:text-muted-foreground">
                        <h2>Add New Item</h2>
                        <small>Optional — service items found during processing (recorded at GA Processing)</small>
                    </div>
                </header>

                <div className="grid grid-cols-2 items-start gap-3 min-[900px]:grid-cols-4">
                    <select value={draft.type} onChange={setDraftField('type')} aria-label="Service type" className={FIELD}>
                        <option value="">Service Type</option>
                        {serviceTypes.map((t) => <option key={t.id} value={t.id}>{t.name}</option>)}
                    </select>
                    <input type="date" value={draft.date} onChange={setDraftField('date')} aria-label="Service date" className={FIELD} />
                    <input type="text" value={draft.remark} onChange={setDraftField('remark')} placeholder="Remark" aria-label="Remark" className={FIELD} />
                    <input type="text" value={draft.brand} onChange={setDraftField('brand')} placeholder="Brand" aria-label="Brand" className={FIELD} />
                    <input type="text" value={draft.place} onChange={setDraftField('place')} placeholder="Place" aria-label="Place" className={FIELD} />
                    <input type="text" inputMode="numeric" value={draft.fixedPrice} onChange={setDraftField('fixedPrice')} placeholder="Fix Price" aria-label="Fix price" className={`${FIELD} text-right`} />
                    <input type="text" value={draft.fixedGuarantee} onChange={setDraftField('fixedGuarantee')} placeholder="Fix Guarantee" aria-label="Fix guarantee" className={FIELD} />
                    <button type="button" onClick={addLine}
                        className="inline-flex h-9 items-center justify-center gap-1.5 rounded-lg border border-input bg-card px-4 text-xs font-bold text-foreground transition-colors hover:border-primary hover:text-primary">
                        <Plus className="size-3.5" /> Add
                    </button>
                </div>

                {newLines.length > 0 && (
                    <div className="mt-4 overflow-x-auto rounded-xl border border-border/70">
                        <table className="w-full border-collapse text-[12px]">
                            <thead>
                                <tr className="[&>th]:whitespace-nowrap [&>th]:px-3 [&>th]:py-2.5 [&>th]:text-left [&>th]:text-[11px] [&>th]:font-semibold [&>th]:uppercase [&>th]:tracking-wide [&>th]:text-muted-foreground">
                                    <th>Service Type</th><th>Date</th><th>Remark</th><th>Brand</th><th>Place</th><th className="!text-right">Fix Price</th><th>Fix Guarantee</th><th className="w-12" />
                                </tr>
                            </thead>
                            <tbody>
                                {newLines.map((n, i) => (
                                    <tr key={i} className="border-t border-border/60 [&>td]:px-3 [&>td]:py-2.5">
                                        <td className="font-semibold">{n.typeName || n.type}</td>
                                        <td className="tabular-nums">{n.date}</td>
                                        <td className="max-w-[220px] truncate" title={n.remark}>{n.remark}</td>
                                        <td>{n.brand}</td>
                                        <td>{n.place}</td>
                                        <td className="text-right tabular-nums">{n.fixedPrice}</td>
                                        <td>{n.fixedGuarantee}</td>
                                        <td className="text-center">
                                            <button type="button" title="Delete" aria-label={`Delete added line ${i + 1}`} onClick={() => removeNewLine(i)}
                                                className="inline-grid size-7 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive">
                                                <Trash2 className="size-3.5" />
                                            </button>
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                )}
            </article>

            {/* Request-level history */}

            <DecisionBar>
                <span className="hidden whitespace-nowrap text-[12.5px] font-semibold text-muted-foreground sm:inline">
                    Request <span className="font-extrabold text-foreground">#{vsr.id}</span> · {vsr.statusName}
                </span>
                <div className="flex w-full flex-wrap items-center gap-2 sm:w-auto sm:flex-nowrap">
                    <button type="button" onClick={() => pick('approve', 'process', 'GA Processing')} className={BAR_BTN_PRIMARY}>GA Processing</button>
                    <button type="button" onClick={() => pick('revise', 'revise', 'Revise')} className={`${BAR_BTN} border border-input bg-card text-warning-text hover:border-warning`}>Revise</button>
                </div>
            </DecisionBar>

            <DecisionConfirmDialog
                action={decision?.dialogAction ?? null}
                label={decision?.label}
                comment={comment}
                onCommentChange={setComment}
                processing={processing}
                onCancel={() => setDecision(null)}
                onConfirm={confirm}
            />
        </section>
    );
}

GaProcessingDetail.layout = [AppLayout];
