import { useState } from 'react';
import { Link, router, useForm } from '@inertiajs/react';
import { ArrowLeft, Ban, ChevronDown, Info, Mail, Pencil, RefreshCw } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { Button } from '@/Components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogTitle } from '@/Components/ui/dialog';
import { Switch } from '@/Components/ui/switch';
import { FloatingField } from '@/Components/Proto/UI/FloatingField';
import { StatusBadge } from '@/Components/Proto/UI/StatusBadge';
import { HistoryPopover } from '@/Components/MenuQuotations/QuotationDetailPage/HistoryPopover';
import { sampleOrderViewMeta } from '@/lib/sampleOrderViews';
import { statusTone } from '@/lib/sampleOrderStatusTones';
import { HistoryTimelinePopover } from '@/Components/MenuQuotations/QuotationDetailPage/HistoryTimelinePopover';
import { useStickyColShadow } from '@/lib/useStickyColShadow';
import { cn } from '@/lib/utils';
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';

// ---- Line-items table (data-driven) -------------------------------------
// `always` columns render regardless; the rest auto-hide when EVERY row is
// empty for them — the legacy layout showed all 15 columns full of "—", which
// forced a ~1600px table for data that mostly wasn't there.
const filled = (v) => v != null && String(v).trim() !== '' && v !== '—';
// Prose fields (remarks etc.) wrap inside a bounded block instead of inheriting
// the table's nowrap — one long remark used to stretch its column indefinitely.
const Prose = ({ children }) =>
    filled(children) ? <span className="block min-w-44 max-w-72 whitespace-normal break-words leading-relaxed">{children}</span> : '—';

const LINE_COLS = [
    // Product Name leads and freezes (house col-name pattern): it's the row's
    // identity once the table scrolls sideways; the legacy order buried it 5th.
    { id: 'product', label: 'Product Name', always: true, sticky: true, get: (i) => i.productName, render: (i) => <strong className="font-semibold text-foreground" title={i.productName || undefined}>{i.productName || '—'}</strong> },
    { id: 'id', label: 'ID', always: true, cls: 'tabular-nums', get: (i) => i.id },
    { id: 'status', label: 'Status', always: true, get: (i) => i.statusLabel, render: (i) => (i.statusLabel ? <StatusBadge tone={statusTone(i.status)}>{i.statusLabel}</StatusBadge> : '—') },
    { id: 'principal', label: 'Principal', always: true, get: (i) => i.principalName },
    { id: 'barang', label: 'Barang', always: true, get: (i) => i.barang },
    { id: 'qty', label: 'Qty', always: true, numeric: true, get: (i) => i.qty },
    { id: 'qtReceived', label: 'Qt Received', numeric: true, get: (i) => i.qtReceived },
    { id: 'satuan', label: 'Satuan', always: true, get: (i) => i.satuan },
    { id: 'application', label: 'Application', get: (i) => i.application, prose: true },
    { id: 'requestLot', label: 'Request Lot Number', get: (i) => i.requestLot, prose: true },
    { id: 'listBarang', label: 'List Barang', get: (i) => i.listBarang, prose: true },
    { id: 'remarks', label: 'Remarks', get: (i) => i.remarks, prose: true },
    { id: 'remarkCoverLetter', label: 'Remark Cover Letter', get: (i) => i.remarkCoverLetter, prose: true },
    { id: 'remarkInternal', label: 'Remark Internal', get: (i) => i.remarkInternal, prose: true },
];

// border-separate (not collapse) — sticky cells drop collapsed borders while
// scrolling. Zebra/hover on the frozen column use color-mix for a SOLID paint;
// a translucent bg would let scrolled columns show through it.
const LINE_TABLE =
    'w-full border-separate border-spacing-0 ' +
    // WHITE header (border-b only) — the gray color-mix band belongs to LIST pages;
    // detail tables (QuotationDetailPage reference) stay clean white.
    '[&_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 ' +
    '[&_th.col-name]:sticky [&_th.col-name]:left-0 [&_th.col-name]:z-3 [&_th.col-name]:bg-card ' +
    '[&_tbody_td.col-name]:sticky [&_tbody_td.col-name]:left-0 [&_tbody_td.col-name]:z-1 [&_tbody_td.col-name]:max-w-64 [&_tbody_td.col-name]:overflow-hidden [&_tbody_td.col-name]:text-ellipsis [&_tbody_td.col-name]:bg-card ' +
    '[&_tbody_tr:nth-child(even)_td.col-name]:bg-[color-mix(in_srgb,var(--color-secondary)_25%,var(--color-card))] [&_tbody_tr:hover_td.col-name]:bg-[color-mix(in_srgb,var(--color-secondary)_60%,var(--color-card))]';

function DocList({ fields }) {
    if (!fields || Object.keys(fields).length === 0)
        return <p className="px-0 py-1 text-[0.82rem] text-muted-foreground">Tidak ada data.</p>;
    return (
        <dl className="grid gap-0">
            {Object.entries(fields).map(([key, val]) => (
                <div key={key} className="grid grid-cols-[minmax(0,110px)_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>
    );
}

function getCreatedOnString(q) {
    let dateStr = '';
    if (q.history?.entries && q.history.entries.length > 0) {
        const oldest = q.history.entries[q.history.entries.length - 1];
        if (oldest?.Tanggal && oldest.Tanggal !== '—') {
            dateStr = oldest.Tanggal;
        }
    }
    if (!dateStr) {
        dateStr = q.general?.['Quotation Date'] || q.general?.['Sample Order Date'] || q.tanggal || '';
    }
    if (!dateStr || dateStr === '—') return '';
    try {
        const parts = dateStr.trim().split(/\s+/);
        const datePart = parts[0];
        const timePart = parts[1] || '';
        
        let formattedDate = datePart;
        if (datePart.includes('-')) {
            const [y, m, d] = datePart.split('-');
            const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
            const monthName = months[parseInt(m, 10) - 1] || m;
            formattedDate = `${parseInt(d, 10)} ${monthName} ${y}`;
        }
        
        let formattedTime = '';
        if (timePart) {
            const tParts = timePart.split(':');
            if (tParts.length >= 2) {
                formattedTime = `${tParts[0]}:${tParts[1]}`;
            }
        }
        
        if (formattedDate && formattedTime) {
            return `Created on ${formattedDate} · ${formattedTime}`;
        } else if (formattedDate) {
            return `Created on ${formattedDate}`;
        }
    } catch (e) {
        // Ignore
    }
    return `Created on ${dateStr}`;
}

export default function SampleOrderDetail({ sampleOrder = {}, view = 'all', caps = null, statusOptions = null }) {
    const { show: showToast } = useToast();
    const q = sampleOrder;
    const meta = sampleOrderViewMeta(view);
    // Hero action buttons only render in views with action capabilities (the
    // remaining #31 PM stage / #32 revise pass consume the same caps object).
    const showActions = caps ? Boolean(caps.changeStatus || caps.reviseRecreate || caps.cancel) : true;

    // ---- Actions card: cancel / send-email / change-status (2026-06-12) ----
    // Every POST carries `view`; the server re-verifies grant + caps + row scope.
    const hasActionsCard = Boolean(caps && (caps.cancel || caps.sendEmail || caps.changeStatus));
    // Legacy gate: Cancel only renders for statuses 1–4 (re-checked server-side).
    const canCancel = Boolean(caps?.cancel) && [1, 2, 3, 4].includes(q.statusId);
    // Revise button: visible when caps.reviseRecreate is true AND status is 4 (Revise).
    const canRevise = Boolean(caps?.reviseRecreate) && q.statusId === 4;

    const [cancelOpen, setCancelOpen] = useState(false);
    const cancelForm = useForm({ view });
    const submitCancel = (e) => {
        e.preventDefault();
        cancelForm.post(route('sample-orders.cancel', q.id), {
            onError: () => showToast('Please check the form and try again.', 'error'),
            preserveScroll: true,
            onSuccess: () => setCancelOpen(false),
        });
    };

    const [emailBusy, setEmailBusy] = useState(false);
    const toggleSendEmail = (next) => {
        router.post(route('sample-orders.send-email', q.id), { view, send: next }, {
            onError: () => showToast('Please check the form and try again.', 'error'),
            preserveScroll: true,
            onStart: () => setEmailBusy(true),
            onFinish: () => setEmailBusy(false),
        });
    };

    const [csOpen, setCsOpen] = useState(false);
    const csForm = useForm({ view, status: '', comment: '' });
    const csOptions = statusOptions ?? [];
    const csBlockReasons = [...new Set(csOptions.filter((o) => o.disabled).map((o) => o.reason))];
    const openChangeStatus = () => {
        csForm.reset();
        csForm.clearErrors();
        setCsOpen(true);
    };
    const submitChangeStatus = (e) => {
        e.preventDefault();
        csForm.post(route('sample-orders.change-status', q.id), {
            onError: () => showToast('Please check the form and try again.', 'error'),
            preserveScroll: true,
            onSuccess: () => setCsOpen(false),
        });
    };

    // Build section fields — fallback ke top-level fields kalau detail belum ada
    const generalFields = q.general || {
        'No': q.id,
        'SO Status': q.statusLabel || '—',
        'Feedback Status': q.feedback || '—',
        'Sample Order Date': q.tanggal || '—',
        'Creator': q.creator || '—',
        'Sales': q.sales || '—',
    };

    const companyFields = q.companyContact || {
        'Company Name': q.company || '—',
        'Division': q.division || '—',
        'Industry': q.industry || '—',
        'Priority': q.priority || '—',
    };

    const orderFields = q.order || {
        'Sample Order By': q.sampleOrderBy || '—',
        'Date SO By': q.tanggalSOBy || '—',
        'Delivery': q.delivery || '—',
        'Project': q.project || '—',
    };

    const additionalFields = q.additional || { 'Creator': q.creator || '—', 'Sales': q.sales || '—', 'Comment': q.comment || '—' };
    // No top-level fallback like the groups above: nothing outside `shipping` carries these
    // four, so an older payload renders the card exactly as it did before.
    const shippingFields  = q.shipping || null;
    const lineItems       = q.lineItems  || [];
    const totals          = q.totals     || { items: lineItems.length, qty: '0' };

    // Sticky product column divider (only while horizontally scrolled) + the
    // subset of columns that actually hold data for THIS order.
    const { scrollRef, shadowClass } = useStickyColShadow();
    const visibleLineCols = LINE_COLS.filter((c) => c.always || lineItems.some((i) => filled(c.get(i))));

    return (
        <section className="flex min-w-0 flex-col gap-4.5">
            <header className="flex items-center justify-between gap-4">
                <div>
                    <p className="mb-1.5 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
                        <Link href={route(meta.indexRoute)} className="text-muted-foreground no-underline hover:text-primary">{meta.label}</Link>
                        <span aria-hidden="true">›</span>
                        <span className="text-foreground">View Sample Order</span>
                    </p>
                </div>
                <Link href={route(meta.indexRoute)} className={BACK_BTN}>
                    <ArrowLeft className="size-3.5" />
                    Back to List
                </Link>
            </header>

            {/* Hero */}
            <div className="flex items-center justify-between gap-4 mt-1">
                <div className="flex flex-col gap-1 min-w-0">
                    <div className="flex items-center gap-3">
                        <h1 className="m-0 text-2xl font-extrabold tracking-tight text-foreground">Sample Order #{q.id}</h1>
                        {q.statusLabel && (
                            <StatusBadge tone={statusTone(q.status)}>{q.statusLabel}</StatusBadge>
                        )}
                    </div>
                    {getCreatedOnString(q) && (
                        <p className="m-0 text-[12px] font-medium text-muted-foreground">{getCreatedOnString(q)}</p>
                    )}
                </div>
                {hasActionsCard && (
                    <div className="flex shrink-0 items-center gap-5 whitespace-nowrap">
                        {caps.sendEmail && (
                            <div className="flex items-center gap-2">
                                <span className="flex items-center gap-1.5 text-xs font-bold text-foreground">
                                    <Mail aria-hidden="true" className="size-4 text-muted-foreground" />
                                    Send Email
                                </span>
                                <Switch checked={Boolean(q.isSendEmail)} disabled={emailBusy} onCheckedChange={toggleSendEmail} aria-label="Toggle send email" />
                            </div>
                        )}
                        {caps.changeStatus && (
                            <button type="button" onClick={openChangeStatus} className="flex items-center gap-1.5 text-xs font-bold text-primary transition-colors hover:text-primary/80">
                                <RefreshCw aria-hidden="true" className="size-4" />
                                Change Status
                            </button>
                        )}
                        {canRevise && (
                            <Link href={route('sample-orders.revise', q.id)} className="flex items-center gap-1.5 text-xs font-bold text-primary transition-colors hover:text-primary/80">
                                <Pencil aria-hidden="true" className="size-4" />
                                Revise
                            </Link>
                        )}
                        {caps.cancel && (canCancel ? (
                            <button
                                type="button"
                                onClick={() => { cancelForm.clearErrors(); setCancelOpen(true); }}
                                className="flex items-center gap-1.5 text-xs font-bold text-danger transition-colors hover:text-danger/80"
                            >
                                <Ban aria-hidden="true" className="size-4" />
                                Cancel Order
                            </button>
                        ) : (
                            <div className="group relative flex items-center gap-1">
                                <span className="flex cursor-not-allowed items-center gap-1.5 text-xs font-bold text-danger/55">
                                    <Ban aria-hidden="true" className="size-4" />
                                    Cancel Order
                                </span>
                                <button type="button" aria-label="Why is cancel unavailable?" className="grid size-4 place-items-center rounded-full text-muted-foreground/70 transition-colors hover:text-muted-foreground focus:text-muted-foreground focus:outline-none">
                                    <Info aria-hidden="true" className="size-3.5" />
                                </button>
                                <div role="tooltip" className="pointer-events-none absolute right-0 top-[calc(100%+8px)] z-50 w-60 rounded-lg border border-border bg-card p-3 text-left opacity-0 shadow-[0_8px_24px_rgba(0,0,0,0.12)] transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100">
                                    <p className="m-0 text-[11px] font-bold text-foreground">Cancel hanya tersedia di status:</p>
                                    <p className="m-0 mt-1 text-[11px] font-medium text-muted-foreground">Request, Approval SM, Approval PM, Revise.</p>
                                </div>
                            </div>
                        ))}
                    </div>
                )}
            </div>

            {/* Stats Strip */}
            <article className="flex items-center gap-2 rounded-2xl border border-border bg-card shadow-sm p-[14px_18px]">
                <div className="grid min-w-0 flex-1 grid-cols-5 max-[860px]:grid-cols-2 gap-0">
                <div className="flex min-w-0 items-center gap-2.5 p-[0_14px]">
                    <div><small className="mb-px block text-[10px] font-medium text-muted-foreground">Total Items</small><strong className="block whitespace-nowrap text-base font-extrabold leading-[1.1] text-card-foreground">{totals.items}</strong></div>
                </div>
                <div className="flex min-w-0 items-center gap-2.5 border-l border-border p-[0_14px]">
                    <div><small className="mb-px block text-[10px] font-medium text-muted-foreground">Total Qty</small><strong className="block whitespace-nowrap text-base font-extrabold leading-[1.1] text-card-foreground">{totals.qty}</strong></div>
                </div>
                <div className="flex min-w-0 items-center gap-2.5 border-l border-border p-[0_14px]">
                    <div><small className="mb-px block text-[10px] font-medium text-muted-foreground">Sample Order By</small><strong className="block whitespace-nowrap text-base font-extrabold leading-[1.1] text-card-foreground">{q.sampleOrderBy || '—'}</strong></div>
                </div>
                <div className="flex min-w-0 items-center gap-2.5 border-l border-border p-[0_14px]">
                    <div><small className="mb-px block text-[10px] font-medium text-muted-foreground">Delivery</small><strong className="block whitespace-nowrap text-base font-extrabold leading-[1.1] text-card-foreground">{q.delivery || '—'}</strong></div>
                </div>
                <div className="flex min-w-0 items-center gap-2.5 border-l border-border p-[0_14px]">
                    <div><small className="mb-px block text-[10px] font-medium text-muted-foreground">Priority</small><strong className="block whitespace-nowrap text-base font-extrabold leading-[1.1] text-card-foreground">{q.priority || '—'}</strong></div>
                </div>
                </div>
                {q.history?.entries?.length > 0 && (
                    <div className="shrink-0 self-center border-l border-border pl-3">
                        <HistoryTimelinePopover entries={q.history.entries} />
                    </div>
                )}
            </article>

            {/* Doc Sections */}
            <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="general">
                    <h3 className={DOC_HEADING}>
                        <span className={DOC_ICON} aria-hidden="true">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                <circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/>
                            </svg>
                        </span>
                        General Information
                    </h3>
                    <DocList fields={generalFields} />
                </section>

                <section className={DOC_SECTION} data-section-id="company">
                    <h3 className={DOC_HEADING}>
                        <span className={DOC_ICON} aria-hidden="true">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
                            </svg>
                        </span>
                        Company &amp; Contact
                    </h3>
                    <DocList fields={companyFields} />
                </section>

                <section className={DOC_SECTION} data-section-id="order">
                    <h3 className={DOC_HEADING}>
                        <span className={DOC_ICON} aria-hidden="true">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                <rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/>
                            </svg>
                        </span>
                        Order Information
                    </h3>
                    {/* The whole body scrolls, capped at 220px (user decision 2026-08-24).
                        The three sections share one grid row, so grid stretch makes every card
                        as tall as the tallest — and this card holds three field lists where
                        General and Company hold one each, measuring 515px against their 284px
                        and padding both of them with 231px of dead air.
                        220px is not a guess: card = 1 border + 14 padding-top + 24 heading
                        + 12 heading margin + BODY + 12 padding-bottom + 1 border, so a 220px
                        body lands the card on 284px — exactly General's natural height.
                        Capping only the Additional block was tried first and cannot work: even
                        with that block deleted outright the card still measures 374px. */}
                    <div className="max-h-[220px] overflow-y-auto">
                        <DocList fields={orderFields} />
                        {/* Shipping rides in THIS card rather than a fourth one: Delivery
                            already lives here, and the grid is 3-up, so a fourth card would sit
                            alone on a second row above 1180px. It sits ABOVE Additional — the
                            shipping header is order data, Comment is the free-text tail. */}
                        {shippingFields && (
                            <>
                                <h4 className="mt-4 mb-2 border-t border-dashed border-border pt-3 text-[11px] font-extrabold uppercase tracking-wide text-muted-foreground">Shipping Information</h4>
                                <DocList fields={shippingFields} />
                            </>
                        )}
                        <h4 className="mt-4 mb-2 border-t border-dashed border-border pt-3 text-[11px] font-extrabold uppercase tracking-wide text-muted-foreground">Additional Information</h4>
                        <DocList fields={additionalFields} />
                    </div>
                </section>
            </div>

            {/* Line Items */}
            <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">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                <line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/>
                                <circle cx="4" cy="6" r="1"/><circle cx="4" cy="12" r="1"/><circle cx="4" cy="18" r="1"/>
                            </svg>
                        </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>Sample Order Details</h2>
                            <small>Line items breakdown</small>
                        </div>
                    </div>
                </header>

                {lineItems.length === 0 ? (
                    <p className="p-6 text-[0.85rem] text-muted-foreground">Tidak ada line item.</p>
                ) : (
                    <div ref={scrollRef} className="overflow-x-auto rounded-b-2xl">
                        <table className={cn(LINE_TABLE, shadowClass)}>
                            <thead>
                                <tr>
                                    {visibleLineCols.map((col) => (
                                        <th key={col.id} className={cn(col.sticky && 'col-name', col.numeric && 'number')}>{col.label}</th>
                                    ))}
                                    <th className="!text-center">History</th>
                                </tr>
                            </thead>
                            <tbody>
                                {lineItems.map(item => (
                                    <tr key={item.id}>
                                        {visibleLineCols.map((col) => (
                                            <td key={col.id} className={cn(col.sticky && 'col-name', col.numeric && 'number tabular-nums', col.cls)}>
                                                {col.render
                                                    ? col.render(item)
                                                    : col.prose
                                                        ? <Prose>{col.get(item)}</Prose>
                                                        : (filled(col.get(item)) ? col.get(item) : '—')}
                                            </td>
                                        ))}
                                        <td className="text-center">
                                            <HistoryPopover count={(item.history ?? []).length} title="History" width={320}>
                                                {(item.history ?? []).map((h, i) => (
                                                    <div key={i} className="text-[11px] leading-snug text-muted-foreground">
                                                        <span className="font-semibold text-foreground">{h.status || '—'}</span>
                                                        {h.date ? <> · <span className="tabular-nums">{h.date}</span></> : null}
                                                        {h.user ? ` · ${h.user}` : ''}
                                                        {h.remark ? ` · ${h.remark}` : ''}
                                                    </div>
                                                ))}
                                            </HistoryPopover>
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                )}
            </article>

            {/* Cancel confirm — service guard errors land on `cancel` */}
            <Dialog open={cancelOpen} onOpenChange={(open) => { if (!open) setCancelOpen(false); }}>
                <DialogContent className="max-w-md">
                    <DialogTitle>Cancel Sample Order #{q.id}?</DialogTitle>
                    <p className="m-0 text-xs leading-relaxed text-muted-foreground">
                        Status order menjadi <strong>Cancel</strong> dan semua line item ikut dibatalkan.
                        Histori mencatat “Cancelled by User.”
                    </p>
                    {cancelForm.errors.cancel && (
                        <p className="m-0 text-[11px] font-semibold text-danger">{cancelForm.errors.cancel}</p>
                    )}
                    <form onSubmit={submitCancel}>
                        <DialogFooter>
                            <Button type="button" variant="outline" className="rounded-lg font-bold" onClick={() => setCancelOpen(false)}>Keep Order</Button>
                            <Button type="submit" variant="destructive" disabled={cancelForm.processing} className="rounded-lg font-bold">
                                Cancel Sample Order
                            </Button>
                        </DialogFooter>
                    </form>
                </DialogContent>
            </Dialog>

            {/* Change Status — options pre-disabled with the server's own reasons */}
            <Dialog open={csOpen} onOpenChange={(open) => { if (!open) setCsOpen(false); }}>
                <DialogContent className="max-w-md">
                    <DialogTitle>Change Status — Sample Order #{q.id}</DialogTitle>
                    <form onSubmit={submitChangeStatus} className="mt-2 flex flex-col gap-3">
                        <FloatingField
                            as="select"
                            label="Status *"
                            value={csForm.data.status}
                            onChange={(e) => {
                                csForm.setData('status', e.target.value);
                                if (csForm.errors.status) csForm.clearErrors('status');
                            }}
                        >
                            <option value="">Select Status</option>
                            {csOptions.map((o) => (
                                <option key={o.id} value={o.id} disabled={o.disabled}>{o.name}</option>
                            ))}
                        </FloatingField>
                        {csBlockReasons.map((r) => (
                            <p key={r} className="m-0 text-[11px] font-medium italic text-muted-foreground">{r}</p>
                        ))}
                        {csForm.errors.status && (
                            <p className="m-0 text-[11px] font-semibold text-danger">{csForm.errors.status}</p>
                        )}
                        <FloatingField
                            as="textarea"
                            label="Comment *"
                            className="[&_textarea]:min-h-20"
                            value={csForm.data.comment}
                            onChange={(e) => {
                                csForm.setData('comment', e.target.value);
                                if (csForm.errors.comment) csForm.clearErrors('comment');
                            }}
                        />
                        {csForm.errors.comment && (
                            <p className="m-0 text-[11px] font-semibold text-danger">{csForm.errors.comment}</p>
                        )}
                        <DialogFooter>
                            <Button type="submit" disabled={csForm.processing || !csForm.data.status} className="rounded-lg bg-linear-to-br from-violet-500 to-primary text-white font-bold shadow-sm transition-[filter] hover:brightness-105">Change Status</Button>
                            <Button type="button" variant="outline" className="rounded-lg font-bold" onClick={() => setCsOpen(false)}>Close</Button>
                        </DialogFooter>
                    </form>
                </DialogContent>
            </Dialog>
        </section>
    );
}

SampleOrderDetail.layout = [AppLayout]
