import { Fragment, useMemo, useRef, 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 { Switch } from '@/Components/ui/switch';
import { StatusBadge } from '@/Components/Proto/UI/StatusBadge';
import { CheckBox } from '@/Components/Proto/UI/CheckBox';
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 { firstMessagePerKey } from '@/lib/formErrors';
import { useToast } from '@/Components/Toast';
import { complaintStatusTone, complaintTypeTone } from '@/Proto/complaintsData';

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 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 RING_ICON = 'inline-grid size-6 shrink-0 place-items-center rounded-full border border-primary/50 bg-transparent text-primary';
const ASSIGN_REMARK = 'min-h-[52px] w-full rounded-lg border border-input bg-card px-3 py-2 text-[13px] text-card-foreground outline-none focus:border-primary disabled:cursor-not-allowed disabled:bg-muted/40 disabled:text-muted-foreground';

// NO blanket [&_tbody_td]:font-normal here. An arbitrary variant compiles to a
// DESCENDANT selector (.[&_tbody_td]:font-normal tbody td, specificity 0-2-1), which
// outranks every plain .font-bold / .font-semibold a <td> sets on itself (0-1-0). With
// it, all 25-odd per-cell weights in this file were dead code and the table rendered
// one flat weight — reported 2026-08-24. A <td> is font-normal by default anyway, so
// dropping it changes nothing except letting the cells speak. Same trap applies to
// colour: never add [&_tbody_td]:text-* back unless no cell sets its own.
// Table type matches the app majority — header 11px/600, body 12px — the sizes Quotation
// and Company Rebate detail tables use. This file ran 12px/700 headers over 13px body,
// one step up on BOTH, which is what made the page read larger than every screen beside
// it (measured 2026-08-24). Keep the four Complaint Handling detail files identical:
// their TABLE constants are copies, so changing one alone splits four twin screens.
const TABLE = 'w-full border-collapse '
    + '[&_thead_tr]:bg-card [&_thead_th]:whitespace-nowrap [&_thead_th]:border-b [&_thead_th]:border-border [&_thead_th]:px-4 [&_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 [&_th.text-right]:text-right '
    + '[&_tbody_td]:whitespace-nowrap [&_tbody_td]:border-b [&_tbody_td]:border-border/40 [&_tbody_td]:px-4 [&_tbody_td]:py-3 [&_tbody_td]:align-top [&_tbody_td]:text-[12px] [&_tbody_td]:text-foreground '
    + '[&_tbody_tr:last-child_td]:border-b-0 [&_tbody_tr:hover_td]:bg-muted/20';

const LOT_BASE = [{ key: 'lotNumber', label: 'Lot No' }];
const LOT_EXTRA = [
    { key: 'poNumber', label: 'PO No' }, { key: 'poQuantity', label: 'PO Qty', align: true },
    { key: 'poDate', label: 'PO Date' }, { key: 'eta', label: 'ETA' },
    { key: 'grNumber', label: 'GR No' }, { key: 'grDate', label: 'GR Date' },
    { key: 'isPayment', label: 'Is Payment' }, { key: 'paymentDate', label: 'Payment Date' },
    { key: 'stdLotNumber', label: 'Std Lot No' },
];
const LOT_TAIL = [
    { key: 'lotQty', label: 'Lot Qty', align: true }, { key: 'lotQtyProblem', label: 'Lot Problem', align: true },
    { key: 'packaging', label: 'Packaging' }, { key: 'expiredDate', label: 'Expiry' },
    { key: 'complainDetails', label: 'Details' }, { key: 'complainExpectation', label: 'Expectation' },
];

const cv = (v) => (v === '' || v === null || v === undefined) ? <span className="text-muted-foreground/40">—</span> : v;
const lotCell = (l, key) => (key === 'isPayment' ? (l.isPayment ? 'Yes' : 'No') : cv(l[key]));

function Ring({ d }) {
    return (
        <span className={RING_ICON} aria-hidden="true">
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">{d}</svg>
        </span>
    );
}

function DocList({ fields }) {
    return (
        <dl className="grid gap-0">
            {Object.entries(fields).map(([key, val]) => (
                <div key={key} className="grid grid-cols-[minmax(0,140px)_1fr] items-baseline gap-2.5 border-b border-border/40 py-2.5 last:border-b-0">
                    <dt className="m-0 text-xs font-medium text-muted-foreground">{key}</dt>
                    <dd className="m-0 wrap-break-word text-[13px] font-semibold text-foreground">{(val ?? '') === '' ? '—' : val}</dd>
                </div>
            ))}
        </dl>
    );
}

export default function ApprovalCeoDetail({ report }) {
    const { show: showToast } = useToast();
    const [showLots, setShowLots] = useState(false);
    const [confirm, setConfirm] = useState(null); // 'approve' | 'reject' | null

    // Per-department assign state: all unchecked by default.
    const form = useForm({
        assignments: report.departments.map((d) => ({ departmentId: d.departmentId, checked: false, remark: '' })),
    });
    const [assignErrors, setAssignErrors] = useState({}); // departmentId -> message
    // An error about the assignments ARRAY rather than one row (required / min:1). It has no
    // department to sit next to, so it gets its own line above the table.
    const [assignFormError, setAssignFormError] = useState('');

    /*
     * The departments actually POSTed, in payload order.
     *
     * The server answers with `assignments.0.remark`, and index 0 is the first CHECKED department
     * — not the first row on screen. Without this the errors could only be matched by position in
     * the rendered table, which marks the wrong department the moment anything is left unticked.
     * A pasted CJK character in a remark is the reachable case: it passes the client check and
     * fails the latin1 column guard, and until now it produced a generic toast and nothing else.
     */
    const submittedDepts = useRef([]);

    const setAssign = (departmentId, patch) => {
        form.setData('assignments', form.data.assignments.map((a) => (a.departmentId === departmentId ? { ...a, ...patch } : a)));
    };
    const assignFor = (departmentId) => form.data.assignments.find((a) => a.departmentId === departmentId);

    const lotCols = showLots ? [...LOT_BASE, ...LOT_EXTRA, ...LOT_TAIL] : [...LOT_BASE, ...LOT_TAIL];

    const timeline = report.history.map((e) => ({ Status: e.status, Tanggal: e.tanggal, User: e.user, Comment: e.remark }));
    const infoLeft = {
        'ID': <span className="font-bold tabular-nums text-primary">{report.id}</span>,
        'Principal Name': <span className="font-semibold text-foreground">{report.principal}</span>,
        'Created By': <span className="font-semibold text-foreground">{report.createdBy}</span>,
        'Creator Role': <span className="font-semibold text-foreground">{report.creatorRole}</span>,
    };
    const infoRight = {
        'Created Date': <span className="tabular-nums font-medium">{report.createdDate}</span>,
        'File': report.fileUrl
            ? <a href={report.fileUrl} className="font-semibold text-primary hover:underline">{report.file}</a>
            : <span className="font-semibold text-foreground">{report.file || 'No File'}</span>,
    };

    // Validate before opening the Approve confirm: >=1 checked dept, each with a non-empty remark.
    const openApprove = () => {
        const picked = form.data.assignments.filter((a) => a.checked);
        const errs = {};
        picked.forEach((a) => { if (!a.remark.trim()) errs[a.departmentId] = 'Remark wajib diisi'; });
        if (picked.length === 0) {
            showToast('Pilih minimal satu department untuk di-assign', 'error');
            return;
        }
        if (Object.keys(errs).length > 0) {
            setAssignErrors(errs);
            showToast('Isi remark untuk setiap department yang dicentang', 'error');
            return;
        }
        setAssignErrors({});
        setConfirm('approve');
    };

    const submitApprove = () => {
        const picked = form.data.assignments.filter((a) => a.checked).map((a) => ({ departmentId: a.departmentId, remark: a.remark.trim() }));
        submittedDepts.current = picked.map((a) => a.departmentId);
        form.transform(() => ({ assignments: picked }));
        form.post(route('complaint-handling.approval-ceo.approve', report.id), {
            preserveScroll: true,
            onSuccess: () => { setConfirm(null); setAssignErrors({}); setAssignFormError(''); },
            onError: (errors) => {
                // Close the confirm dialog — the remark boxes are on the page behind it, and now
                // the offending one is actually marked.
                setConfirm(null);
                setAssignErrors(firstMessagePerKey(errors, 'assignments', submittedDepts.current, ['remark', 'departmentId']));
                setAssignFormError(errors.assignments ?? '');
                // Locked 422 wording (.claude/rules/notifications.md): the toast says WHAT
                // happened, the inline label says WHICH field.
                showToast('Please check the form and try again.', 'error');
            },
        });
    };

    const submitReject = () => {
        form.transform(() => ({}));
        form.post(route('complaint-handling.approval-ceo.reject', report.id), {
            preserveScroll: true,
            onSuccess: () => setConfirm(null),
            onError: () => { setConfirm(null); showToast('Reject failed.', 'error'); },
        });
    };

    const dept = (departmentId) => report.departments.find((d) => d.departmentId === departmentId);
    const approveSummary = (
        <ul className="m-0 list-disc space-y-1 pl-5 text-[12px] text-muted-foreground">
            {form.data.assignments.filter((a) => a.checked).map((a) => (
                <li key={a.departmentId}><span className="font-semibold text-foreground">{dept(a.departmentId)?.dept}</span>: {a.remark.trim()}</li>
            ))}
        </ul>
    );

    return (
        <section className="flex min-w-0 flex-col gap-4.5">
            <header>
                <p className="m-0 mb-1.5 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
                    <Link href={route('complaint-handling.approval-ceo')} className="no-underline hover:text-primary">Approval CEO</Link>
                    <span aria-hidden="true">›</span>
                    <span className="text-foreground">Complaint Handling Report</span>
                </p>
                <div className="flex flex-col items-start gap-3 sm:flex-row sm:items-center sm:justify-between sm: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">Complaint Handling Report #{report.id}</h1>
                            <StatusBadge tone={complaintStatusTone(report.status)}>{report.status}</StatusBadge>
                            <StatusBadge tone={complaintTypeTone(report.complainType)}>{report.complainType}</StatusBadge>
                        </div>
                    </div>
                    <div className="flex shrink-0 items-center gap-2">
                        <HistoryTimelinePopover entries={timeline} />
                        <Link href={route('complaint-handling.approval-ceo')} className={BACK_BTN}><ArrowLeft className="size-3.5" />Back to List</Link>
                    </div>
                </div>
            </header>

            <section className={DOC_SECTION}>
                <h3 className={DOC_HEADING}>
                    <Ring d={<><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" /></>} />
                    Report Information
                </h3>
                <div className="grid grid-cols-2 gap-x-10 max-[760px]:grid-cols-1 max-[760px]:gap-x-0">
                    <DocList fields={infoLeft} />
                    <DocList fields={infoRight} />
                </div>
            </section>

            <section className={DOC_SECTION}>
                <div className="mb-3 flex flex-wrap items-center justify-between gap-3">
                    <h3 className={DOC_HEADING}><Ring d={<><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" /><polyline points="3.27 6.96 12 12.01 20.73 6.96" /><line x1="12" y1="22.08" x2="12" y2="12" /></>} /> Details</h3>
                    <label className="flex cursor-pointer items-center gap-2 text-[12px] font-semibold text-muted-foreground select-none">
                        <Switch checked={showLots} onCheckedChange={setShowLots} /> Show Details Lot
                    </label>
                </div>
                <div className="overflow-x-auto rounded-xl border border-border/60 shadow-2xs">
                    <table className={TABLE}>
                        <thead>
                            <tr>
                                <th>Product</th>
                                <th className="text-right">Total</th>
                                <th className="text-right">Problem</th>
                                {lotCols.map((c) => <th key={c.key} className={c.align ? 'text-right' : ''}>{c.label}</th>)}
                            </tr>
                        </thead>
                        <tbody>
                            {report.products.map((p, pi) => p.lots.map((l, li) => (
                                <tr key={`${pi}-${li}`} className={li === 0 && pi > 0 ? 'border-t border-border' : ''}>
                                    {li === 0 && (
                                        <Fragment>
                                            <td rowSpan={p.lots.length} className="font-bold text-foreground align-top bg-card border-r border-border/40 text-[12px]">{p.product}</td>
                                            <td rowSpan={p.lots.length} className="text-right tabular-nums font-semibold text-foreground align-top bg-card border-r border-border/40 text-[12px]">{p.totalQty}</td>
                                            <td rowSpan={p.lots.length} className="text-right tabular-nums font-semibold text-foreground align-top bg-card border-r border-border/40 text-[12px]">{p.totalQtyProblem}</td>
                                        </Fragment>
                                    )}
                                    {lotCols.map((c) => (
                                        <td key={c.key} className={c.align ? 'text-right tabular-nums font-semibold text-foreground text-[12px]' : (c.key === 'lotNumber' ? 'font-semibold text-foreground text-[12px]' : 'text-foreground font-normal text-[12px]')}>
                                            {lotCell(l, c.key)}
                                        </td>
                                    ))}
                                </tr>
                            )))}
                        </tbody>
                    </table>
                </div>
            </section>

            {/* Assign form — one row per department: checkbox (default checked) + read-only
                ReviewRemark + REQUIRED assign-remark (greyed when unchecked) + per-dept history. */}
            <section className={DOC_SECTION}>
                <h3 className={DOC_HEADING}><Ring d={<><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><path d="M23 21v-2a4 4 0 0 0-3-3.87" /><path d="M16 3.13a4 4 0 0 1 0 7.75" /></>} /> Details List Complain Handling</h3>
                {/* An error about the assignments array as a whole — no department to sit beside. */}
                {assignFormError && (
                    <p role="alert" className="mx-5 mb-3 rounded-lg border border-destructive/40 bg-destructive/5 p-2.5 text-[12px] font-semibold text-destructive">
                        {assignFormError}
                    </p>
                )}
                <div className="overflow-x-auto rounded-xl border border-border/60 shadow-2xs">
                    <table className={TABLE}>
                        <thead>
                            <tr>
                                <th className="w-[180px]">Assign To</th>
                                <th className="w-[220px]">Review Remark</th>
                                <th>Assign Remark</th>
                                <th className="w-[100px] text-center">History</th>
                            </tr>
                        </thead>
                        <tbody>
                            {report.departments.map((d) => {
                                const a = assignFor(d.departmentId);
                                const checked = !!a?.checked;
                                return (
                                    <tr key={d.departmentId}>
                                        <td className="whitespace-nowrap">
                                            <label className="inline-flex cursor-pointer items-center gap-2.5 select-none">
                                                <CheckBox
                                                    checked={checked}
                                                    onChange={(e) => setAssign(d.departmentId, { checked: e.target.checked })}
                                                    ariaLabel={`Assign to ${d.dept}`}
                                                />
                                                <span className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-[11px] font-bold transition-colors ${checked ? 'bg-primary/10 text-primary border border-primary/20' : 'bg-muted text-muted-foreground border border-border/40'}`}>
                                                    {d.dept}
                                                </span>
                                            </label>
                                        </td>
                                        <td className="text-muted-foreground">{cv(d.reviewRemark)}</td>
                                        <td>
                                            <textarea rows={2} disabled={!checked} value={a?.remark ?? ''} placeholder="Insert Remark"
                                                aria-invalid={assignErrors[d.departmentId] && checked ? true : undefined}
                                                onChange={(e) => setAssign(d.departmentId, { remark: e.target.value })}
                                                className={`${ASSIGN_REMARK}${assignErrors[d.departmentId] && checked ? ' border-destructive focus:border-destructive' : ''}`} />
                                            {assignErrors[d.departmentId] && checked && (
                                                <p className="mt-1 text-[11px] font-semibold text-destructive">{assignErrors[d.departmentId]}</p>
                                            )}
                                        </td>
                                        <td className="text-center">
                                            <HistoryPopover count={d.history.length} title={`History — ${d.dept}`} width={360}>
                                                {d.history.map((e, i) => (
                                                    <div key={i} className="flex flex-col gap-0.5 border-b border-border/50 py-1.5 last:border-b-0">
                                                        <div className="flex items-center justify-between gap-2">
                                                            <StatusBadge tone={complaintStatusTone(e.status)}>{e.status}</StatusBadge>
                                                            <span className="shrink-0 text-[10px] font-medium tabular-nums text-muted-foreground">{e.tanggal}</span>
                                                        </div>
                                                        <span className="text-[11px] leading-snug text-muted-foreground">
                                                            <span className="font-semibold text-foreground">{e.user}</span>{e.remark ? ` · ${e.remark}` : ''}
                                                        </span>
                                                    </div>
                                                ))}
                                            </HistoryPopover>
                                        </td>
                                    </tr>
                                );
                            })}
                        </tbody>
                    </table>
                </div>
            </section>

            <DecisionBar>
                <span className="hidden whitespace-nowrap text-[12.5px] font-semibold text-muted-foreground sm:inline">
                    Approval CEO · Report <span className="font-extrabold text-foreground">#{report.id}</span>
                </span>
                <span className="hidden h-6 w-px bg-border sm:block" aria-hidden="true" />
                <div className="flex flex-wrap items-center gap-2.5">
                    <Button type="button" variant="outline" disabled={form.processing} onClick={() => setConfirm('reject')}
                        className="h-9 rounded-lg border border-danger/40 bg-card px-4.5 text-xs font-bold text-danger hover:bg-danger/10">Reject</Button>
                    <Button type="button" disabled={form.processing} onClick={openApprove}
                        className="h-9 rounded-lg bg-primary px-4.5 text-xs font-bold text-primary-foreground shadow-sm transition-colors hover:bg-primary/90">Approve</Button>
                </div>
            </DecisionBar>

            <DecisionConfirmDialog
                action={confirm === 'approve' ? 'approve' : (confirm === 'reject' ? 'reject' : null)}
                showComment={false}
                summary={confirm === 'approve' ? approveSummary : null}
                label={confirm === 'approve' ? 'Assign to departments' : undefined}
                onCancel={() => setConfirm(null)}
                onConfirm={confirm === 'approve' ? submitApprove : submitReject}
                processing={form.processing}
            />
        </section>
    );
}

ApprovalCeoDetail.layout = [AppLayout];
