import { useMemo, useState } from 'react';
import { Link, useForm } from '@inertiajs/react';
import { ArrowLeft } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { Button } from '@/Components/ui/button';
import { Dialog, DialogContent, DialogFooter, DialogTitle } from '@/Components/ui/dialog';
import { DecisionBar } from '@/Components/MenuSampleOrders/DecisionBar';
import { StatusBadge } from '@/Components/Proto/UI/StatusBadge';
import { statusTone } from '@/lib/sampleOrderStatusTones';
import { NativeSelect } from '@/Components/ui/native-select';
import { useToast } from '@/Components/Toast';
import { HistoryTimelinePopover } from '@/Components/MenuQuotations/QuotationDetailPage/HistoryTimelinePopover';

// ─────────────────────────────────────────────────────────────────────────────
// Good Issue / Sample Received — per-line three-state receiving (PRD §6.12 / BR-22).
// Each still-in-transit line (detail status 4) is resolved as one of:
//   • Still In Transit (default) — line stays open; typed Qt Received is saved; no stock move.
//   • Received        — line → Sample Received; Qt Received must be > 0 and ≤ ordered (partial OK); stock kept.
//   • Not Received    — line → Sample Received; Qt Received forced 0; full line stock returned to its lot.
// Auto-flip: typing Qt Received = ordered qty flips a transit line to Received (mirrors the backend).
// The header promotes to Sample Received (8) ONLY when no line is left in transit; otherwise it
// stays at Surat Jalan (7) for a later round. Comment is required.
//
// UNWIRED until the controller + routes land (issue #79): rendered by
// SampleOrderController@goodIssueShow via Inertia::render('MenuSampleOrders/GoodIssue/Detail', [...]).
// Expected route names:
//   sample-orders.good-issue          (GET  back to the queue)
//   sample-orders.good-issue.process  (POST {id} — the receiving round)
// POST body (matches SampleOrderGoodIssueRequest):
//   { lines: { "<detailId>": { state: "transit"|"received"|"not_received", qty: <number> }, ... }, comment: <string> }
// Props:
//   sampleOrder: { id, company, division, industry, delivery, tanggal, sales, creator, project, comment, status, snk }
//   lines:       [{ id, status, principalName, barang, productName, qty (ordered, numeric),
//                  satuan, lotNumber, qtReceived (current numeric) }]  (only status-4 lines)
// ─────────────────────────────────────────────────────────────────────────────

const SECTION_CARD = 'overflow-hidden rounded-xl border border-border bg-card shadow-sm';
const SECTION_HEAD = 'border-b border-border/60 px-5 py-3';
const SECTION_TITLE = 'm-0 text-[11px] font-bold uppercase tracking-[0.05em] text-card-foreground';
const SECTION_SUB = 'mt-0.5 block text-[11px] font-medium text-muted-foreground';

const STATE_OPTIONS = [
    { value: 'transit', label: 'Still In Transit' },
    { value: 'received', label: 'Received' },
    { value: 'not_received', label: 'Not Received' },
];

export default function SampleOrderGoodIssueDetail({ sampleOrder = {}, lines = [] }) {
    const { show: showToast } = useToast();
    const q = sampleOrder;

    const orderedById = useMemo(
        () => Object.fromEntries(lines.map((l) => [l.id, Number(l.qty) || 0])),
        [lines],
    );
    const initialLines = useMemo(
        () => Object.fromEntries(lines.map((l) => [l.id, { state: 'transit', qty: String(l.qtReceived ?? 0) }])),
        [lines],
    );
    const form = useForm({ lines: initialLines, comment: '' });
    const [confirmOpen, setConfirmOpen] = useState(false);

    const lineData = (id) => form.data.lines[id] || { state: 'transit', qty: '0' };

    const updateLine = (id, patch) => {
        form.setData('lines', { ...form.data.lines, [id]: { ...lineData(id), ...patch } });
        if (form.errors.lines) form.clearErrors('lines');
    };
    // Changing the dropdown never touches Qt Received — the typed value is preserved even
    // when switching to Not Received (whose input stays locked at 0; the submit forces 0 for
    // a Not-Received line regardless of the stored value).
    const setState = (id, state) => updateLine(id, { state });
    const setQty = (id, val) => {
        // Drop a leading zero when a real digit follows ("05" → "5", "0" and "0.5" untouched),
        // so typing over a default 0 yields exactly the number typed instead of concatenating.
        const next = val.replace(/^0+(?=\d)/, '');
        const cur = lineData(id);
        const n = Number(next);
        // Auto-flip between In Transit and Received (Not Received is locked at 0 and only
        // leaves that state via the dropdown):
        //  • a FULL typed qty on a transit line is a receipt (mirrors the backend auto-flip);
        //  • clearing a received line's qty back to 0 drops it to In Transit.
        let state = cur.state;
        if (cur.state === 'transit' && n > 0 && n >= orderedById[id]) state = 'received';
        else if (cur.state === 'received' && !(n > 0)) state = 'transit';
        updateLine(id, { qty: next, ...(state !== cur.state ? { state } : {}) });
    };

    const counts = useMemo(() => {
        let received = 0, notReceived = 0, transit = 0;
        lines.forEach((l) => {
            const s = (form.data.lines[l.id] || {}).state || 'transit';
            if (s === 'received') received++;
            else if (s === 'not_received') notReceived++;
            else transit++;
        });
        return { received, notReceived, transit };
    }, [form.data.lines, lines]);
    const willPromote = counts.transit === 0;

    // Pre-flight the per-line qty rule before submitting — mirrors the service so the
    // error shows without a round-trip. Server re-validates as the backstop.
    //
    // This ALWAYS opens the dialog. Both the Comment field and both error slots live
    // INSIDE it, so returning early here would leave the button dead with an invisible
    // error — which is exactly what a `comment` pre-flight used to do: comment starts
    // blank and can only be typed in the dialog, so the dialog could never open. The
    // required-comment rule is enforced by the dialog's own submit button instead.
    const requestConfirm = () => {
        form.clearErrors('comment', 'lines');
        const bad = lines.find((l) => {
            const d = lineData(l.id);
            if (d.state !== 'received') return false;
            const qty = Number(d.qty);
            return !(qty > 0 && qty <= orderedById[l.id]);
        });
        if (bad) {
            form.setError('lines', `Received quantity for line #${bad.id} must be greater than 0 and at most the ordered quantity (${orderedById[bad.id]}).`);
        }
        setConfirmOpen(true);
    };

    const submit = (e) => {
        e.preventDefault();
        form.transform((data) => ({
            comment: data.comment,
            lines: Object.fromEntries(
                Object.entries(data.lines).map(([id, d]) => [
                    id,
                    { state: d.state, qty: d.state === 'not_received' ? 0 : Number(d.qty) || 0 },
                ]),
            ),
        }));
        form.post(route('sample-orders.good-issue.process', q.id), {
            onError: () => showToast('Please check the form and try again.', 'error'),
            preserveScroll: true,
            onSuccess: () => setConfirmOpen(false),
        });
    };

    const infoFields = {
        'Company': q.company,
        'Division': q.division,
        'Industry': q.industry,
        'Delivery': q.delivery,
        'Date': q.tanggal,
        'Sales': q.sales,
        'Creator': q.creator,
        'Project': q.project,
        'AWB': q.awb,
    };

    return (
        <section className="flex min-w-0 flex-col gap-4.5">
            <header className="flex items-center justify-between gap-4">
                <p className="m-0 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
                    <Link href={route('sample-orders.good-issue')} className="text-muted-foreground no-underline hover:text-primary">Good Issue</Link>
                    <span aria-hidden="true">›</span>
                    <span className="text-foreground">Sample Order #{q.id}</span>
                </p>
                {/* Grouped, not a bare middle child: the header is `justify-between`, so an
                    unwrapped popover is treated as a third column and parks in the middle of
                    the row. Document history belongs immediately left of the back/action
                    buttons (ui-conventions.md "History on detail pages"). */}
                <div className="flex shrink-0 items-center gap-2">
                    {q.history?.entries?.length > 0 && <HistoryTimelinePopover entries={q.history.entries} />}
                    <Link
                        href={route('sample-orders.good-issue')}
                        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"
                    >
                        <ArrowLeft className="size-3.5" />
                        Back to List
                    </Link>
                </div>
            </header>

            {/* Order summary */}
            <article className="rounded-xl border border-border bg-card px-6 py-5 shadow-sm">
                <div className="flex flex-wrap items-center gap-2.5">
                    <h1 className="m-0 text-xl font-extrabold leading-none tracking-tight text-card-foreground">
                        Sample Order <span className="text-primary">#{q.id}</span>
                    </h1>
                    {q.status && <StatusBadge tone={statusTone(q.status)}>{q.status}</StatusBadge>}
                    {q.snk && (
                        <span className="inline-flex items-center rounded-full border border-border/70 bg-muted/60 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-muted-foreground" title="Terms & Conditions">
                            {q.snk}
                        </span>
                    )}
                </div>
                <dl className="mt-4 grid grid-cols-1 gap-x-10 border-t border-border/60 pt-1 sm:grid-cols-2 min-[980px]:grid-cols-3">
                    {Object.entries(infoFields).map(([label, value]) => (
                        <div key={label} className="grid grid-cols-[minmax(0,104px)_1fr] items-baseline gap-2 border-b border-dashed border-border/70 py-[7px]">
                            <dt className="m-0 text-[11px] font-medium text-muted-foreground">{label}</dt>
                            <dd className="m-0 min-w-0 truncate text-xs font-semibold text-foreground" title={value || undefined}>{value || '—'}</dd>
                        </div>
                    ))}
                </dl>
            </article>

            {/* In-transit lines + per-line receiving controls */}
            <article className={SECTION_CARD}>
                <header className={SECTION_HEAD}>
                    <h2 className={SECTION_TITLE}>Sample Request Detail List</h2>
                    <small className={SECTION_SUB}>
                        Per line: keep it in transit (stays open), mark it received (enter the quantity), or not received (stock returned). The order is marked Sample Received only once no line is left in transit.
                    </small>
                </header>
                {lines.length === 0 ? (
                    <p className="px-5 py-6 text-xs text-muted-foreground">No in-transit lines to receive.</p>
                ) : (
                    <div className="overflow-x-auto">
                        <table className="w-full min-w-[1100px] border-collapse [&_tbody_td]:border-b [&_tbody_td]:border-border/50 [&_tbody_td]:p-[14px_12px] [&_tbody_td]:text-[11px] [&_tbody_td]:text-card-foreground [&_tbody_tr:last-child_td]:border-b-0 [&_tbody_tr:hover_td]:bg-secondary/60 [&_thead_th]:border-b [&_thead_th]:border-border [&_thead_th]:whitespace-nowrap [&_thead_th]:p-[10px_12px] [&_thead_th]:text-left [&_thead_th]:text-[11px] [&_thead_th]:font-semibold [&_thead_th]:uppercase [&_thead_th]:tracking-wide [&_thead_th]:text-muted-foreground">
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Principal</th>
                                    <th>Original Product</th>
                                    <th>Product Name</th>
                                    <th className="!text-right">Ordered</th>
                                    <th>Unit</th>
                                    <th>Lot</th>
                                    <th className="min-w-[180px]">Receiving State</th>
                                    <th className="min-w-[140px] !text-right">Qt Received</th>
                                </tr>
                            </thead>
                            <tbody>
                                {lines.map((l) => {
                                    const d = lineData(l.id);
                                    const notReceived = d.state === 'not_received';
                                    return (
                                        <tr key={l.id}>
                                            <td className="font-bold tabular-nums text-primary">#{l.id}</td>
                                            <td>{l.principalName || '—'}</td>
                                            <td>{l.barang || '—'}</td>
                                            <td className="font-semibold text-foreground">{l.productName || '—'}</td>
                                            <td className="text-right tabular-nums">{l.qty ?? '—'}</td>
                                            <td>{l.satuan || '—'}</td>
                                            <td>{l.lotNumber || '—'}</td>
                                            <td>
                                                <NativeSelect
                                                    value={d.state}
                                                    onChange={(e) => setState(l.id, e.target.value)}
                                                    aria-label={`Receiving state for line ${l.id}`}
                                                    className="h-9 w-full rounded-md border border-input bg-card px-2 text-xs text-foreground outline-none focus-visible:border-primary focus-visible:ring-1 focus-visible:ring-ring"
                                                >
                                                    {STATE_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
                                                </NativeSelect>
                                            </td>
                                            <td className="text-right">
                                                <input
                                                    type="number"
                                                    min="0"
                                                    step="0.01"
                                                    value={notReceived ? '0' : d.qty}
                                                    disabled={notReceived}
                                                    onFocus={(e) => { if (!Number(d.qty)) e.target.select(); }}
                                                    onChange={(e) => setQty(l.id, e.target.value)}
                                                    aria-label={`Quantity received for line ${l.id}`}
                                                    className="h-9 w-full rounded-md border border-input bg-card px-2 text-right text-xs tabular-nums text-foreground outline-none focus-visible:border-primary focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
                                                />
                                            </td>
                                        </tr>
                                    );
                                })}
                            </tbody>
                        </table>
                    </div>
                )}
            </article>

            {/* Decision dock — comment + confirm pinned to the viewport bottom */}
            <DecisionBar>
                <span className="text-[12px] font-medium text-muted-foreground">
                    {counts.received} received · {counts.notReceived} not received · {counts.transit} still in transit
                    {' · '}
                    <span className={willPromote ? 'font-semibold text-success' : 'font-semibold text-warning-text'}>
                        {willPromote ? 'will be marked Sample Received' : 'stays in queue'}
                    </span>
                </span>
                <span className="h-6 w-px bg-border" />
                <Button type="button" disabled={lines.length === 0} onClick={requestConfirm}
                    className="h-9 rounded-lg bg-linear-to-br from-violet-500 to-primary px-4 text-xs font-bold text-white shadow-sm transition-[filter] hover:brightness-105">
                    Confirm Receipt
                </Button>
            </DecisionBar>

            {/* Confirm dialog */}
            <Dialog open={confirmOpen} onOpenChange={(open) => { if (!open) setConfirmOpen(false); }}>
                <DialogContent className="max-w-md">
                    <DialogTitle>Good Issue — Sample Order #{q.id}</DialogTitle>
                    <p className="m-0 text-xs leading-relaxed text-muted-foreground">
                        {counts.received} line(s) received, {counts.notReceived} not received (full stock returned), {counts.transit} still in transit.
                        {' '}
                        {willPromote
                            ? 'The order will be marked Sample Received (status 8).'
                            : `The order stays in the Good Issue queue (status 7) — ${counts.transit} line(s) still in transit for a later round.`}
                    </p>
                    <form onSubmit={submit}>
                        {/* Comment moved out of the floating pill — it is read back here before sending. */}
                        <label className="mt-3 block">
                            <span className="mb-1.5 block text-[12px] font-semibold text-muted-foreground">
                                Good Issue Comment <span className="text-danger-text">*</span>
                            </span>
                            <textarea
                                value={form.data.comment}
                                onChange={(e) => { form.setData('comment', e.target.value); if (form.errors.comment) form.clearErrors('comment'); }}
                                rows={3}
                                autoFocus
                                placeholder="Note for this decision…"
                                className="w-full resize-y rounded-lg border border-input bg-card px-3 py-2.5 text-[13px] text-foreground outline-none transition-colors focus:border-primary"
                            />
                        </label>
                        {form.errors.comment && <p className="m-0 mt-1 text-[12px] font-semibold text-danger-text">{form.errors.comment}</p>}
                        {form.errors.lines && <p className="m-0 mt-1 text-[12px] font-semibold text-danger-text">{form.errors.lines}</p>}
                        <DialogFooter>
                            <Button type="submit" disabled={form.processing || !form.data.comment.trim() || !!form.errors.lines}>Confirm Receipt</Button>
                            <Button type="button" variant="outline" onClick={() => setConfirmOpen(false)}>Close</Button>
                        </DialogFooter>
                    </form>
                </DialogContent>
            </Dialog>
        </section>
    );
}

SampleOrderGoodIssueDetail.layout = [AppLayout];
