import { useEffect, useMemo, useRef, useState } from 'react';
import { router, usePage } from '@inertiajs/react';
import { ChevronRight as Caret, Search, Settings } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { OptionPill, SelectPill } from '@/Components/MenuQuotations/QuotationListPage/QuotationListPills';
import { HistoryPopover } from '@/Components/MenuQuotations/QuotationDetailPage/HistoryPopover';
import { ListFooter } from '@/Components/Table/ListFooter';
import { TOOLBAR_GEAR, TOOLBAR_FILTERS } from '@/Components/Table';
import { StatusBadge } from '@/Components/Proto/UI/StatusBadge';
import { DateText } from '@/Components/Proto/UI/DateText';
import { complaintStatusTone, complaintTypeTone } from '@/Proto/complaintsData';
import { useResizableColumns, ColumnResizeGrip } from '@/lib/useResizableColumns';
import { useColumnPrefs } from '@/lib/useColumnPrefs';
import { CustomizeColumnsModal } from '@/Components/Proto/Modals/CustomizeColumnsModal';
import { useServerSort, SortButton } from '@/lib/ServerSort';
import { stripDefaults } from '@/lib/listParams';

const TABLE_CLASS = 'w-full table-fixed border-separate border-spacing-0 '
    + '[&_thead_th]:whitespace-nowrap [&_thead_th]:bg-[color-mix(in_srgb,var(--color-secondary)_50%,var(--color-card))] [&_thead_th]:px-3.5 [&_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-center]:text-center '
    + '[&_tbody_td]:overflow-hidden [&_tbody_td]:border-b [&_tbody_td]:border-border/60 [&_tbody_td]:px-3.5 [&_tbody_td]:py-[13px] [&_tbody_td]:align-middle [&_tbody_td]:text-[12px] [&_tbody_td]:text-card-foreground '
    + '[&_tbody_tr:last-child_td]:border-b-0 [&_tbody_tr:hover_td]:bg-secondary/60 [&_tbody_tr:nth-child(even)_td]:bg-secondary/25 [&_td.text-center]:text-center '
    + '[&_thead_th:first-child]:rounded-l-full [&_thead_th:first-child]:pl-7 [&_thead_th:last-child]:rounded-r-full [&_thead_th:last-child]:pr-5 [&_tbody_td:first-child]:pl-7 [&_tbody_td:last-child]:pr-5';

// Sortable header ids — MUST mirror the controller's SORT_COLUMNS allowlist. A key that
// is not in it falls back to the default sort silently: the arrow moves, the rows do not.
const SORTABLE = new Set(['reportNo', 'creator', 'principal', 'type', 'inputDate']);

const COLUMN_GROUPS = [{ id: 'queue', label: 'Queue' }];
const COLUMN_DEFS = [
    { id: 'reportNo', label: 'Report No', groupId: 'queue', required: true },
    { id: 'details', label: 'Details', groupId: 'queue' },
    { id: 'creator', label: 'Creator', groupId: 'queue' },
    { id: 'principal', label: 'Principal', groupId: 'queue' },
    { id: 'type', label: 'Type', groupId: 'queue' },
    { id: 'product', label: 'Product', groupId: 'queue' },
    { id: 'inputDate', label: 'Input Date', groupId: 'queue' },
    { id: 'history', label: 'History', groupId: 'queue' },
];

const COL_W = { reportNo: 110, details: 90, creator: 150, principal: 160, type: 150, product: 240, inputDate: 150, history: 110 };
const COL_W_FALLBACK = 150;
const RELOAD = { only: ['reports', 'filters'], preserveState: true, preserveScroll: true, replace: true };

function ProductsCell({ items }) {
    const [open, setOpen] = useState(false);
    if (!items?.length) return <span className="text-muted-foreground">—</span>;
    const shown = open ? items : items.slice(0, 2);
    const extra = items.length - shown.length;
    return (
        <div className="flex max-w-[240px] flex-wrap items-center gap-1">
            {shown.map((p, i) => <span key={i} className="inline-flex items-center rounded-md bg-secondary px-1.5 py-0.5 text-[11px] font-medium text-foreground">{p}</span>)}
            {extra > 0 && (
                <button type="button" onClick={(e) => { e.stopPropagation(); setOpen(true); }}
                    className="inline-flex items-center rounded-md border border-primary/30 bg-accent/40 px-1.5 py-0.5 text-[11px] font-bold text-primary hover:border-primary">+{extra}</button>
            )}
            {open && items.length > 2 && (
                <button type="button" onClick={(e) => { e.stopPropagation(); setOpen(false); }}
                    className="text-[11px] font-semibold text-muted-foreground hover:text-primary">less</button>
            )}
        </div>
    );
}

export default function ViewList({ variant, reports, filters = {}, filterOptions = {} }) {
    // This list's server-side defaults, so go() can leave them out of the URL (lib/listParams.js).
    const { listDefaults } = usePage().props;
    const rows = reports.data ?? [];
    const [searchDraft, setSearchDraft] = useState(filters.search || '');
    const [openPill, setOpenPill] = useState(null);
    const [customizeOpen, setCustomizeOpen] = useState(false);
    const filterBarRef = useRef(null);

    const prefs = useColumnPrefs(`complaint_handling_view_${variant.slug}_v1`, COLUMN_DEFS);

    const { widthOf, startResize, resizingId } = useResizableColumns(COL_W, COL_W_FALLBACK);
    const tableWidth = useMemo(() => prefs.visibleCols.reduce((s, col) => s + widthOf(col.id), 0), [prefs.visibleCols, widthOf]);

    const typeOptions = filterOptions.types ?? [];
    const principalOptions = (filterOptions.principals ?? []).map((p) => ({ id: p, name: p }));

    useEffect(() => {
        if (!openPill) return undefined;
        const onDoc = (e) => { if (filterBarRef.current && !filterBarRef.current.contains(e.target)) setOpenPill(null); };
        document.addEventListener('mousedown', onDoc);
        return () => document.removeEventListener('mousedown', onDoc);
    }, [openPill]);

    const go = (overrides = {}) => {
        const params = {
            // The COMMITTED search, not the live box. Reading `searchDraft` here made
            // paginating / sorting / picking a pill carry whatever was half-typed —
            // and, when the box had been cleared without pressing Enter, silently drop
            // a search that was still filtering the rows. Enter and the Search button
            // are what commit a term (they pass it as an override).
            search: filters.search ?? '',
            type: filters.type ?? '',
            principal: filters.principal ?? '',
            sort: filters.sort,
            dir: filters.dir,
            per_page: reports.per_page,
            ...overrides,
        };
        Object.keys(params).forEach((k) => {
            if (params[k] === '' || params[k] === null || params[k] === undefined) delete params[k];
        });
        router.get(route(`complaint-handling.${variant.slug}`), stripDefaults(params, listDefaults), RELOAD);
    };

    // Sort travels to the SERVER (rule #26): sortKey/sortDir are read from `filters`,
    // never from local state — `preserveState` would freeze a local copy at its first
    // render while the rows underneath it changed. go() sends no `page`, so a sort
    // lands back on page 1.
    const { sortKey, sortDir, toggleSort } = useServerSort(filters, go);

    const hasFilter = filters.search || filters.type || filters.principal || searchDraft;
    const resetFilters = () => {
        setSearchDraft('');
        router.get(route(`complaint-handling.${variant.slug}`), {}, RELOAD);
    };

    const renderCell = (r, colId) => {
        switch (colId) {
            case 'reportNo':
                return <span className="whitespace-nowrap text-[13px] font-bold tabular-nums text-primary">{r.reportNo}</span>;
            case 'details':
                return (
                    <button type="button" onClick={() => router.visit(route('complaint-handling.view.show', { variant: variant.slug, id: r.reportNo }))}
                        className="group/link inline-flex items-center gap-0.5 text-[11px] font-bold text-primary hover:underline">
                        Details <Caret className="size-3.5 transition-transform duration-200 group-hover/link:translate-x-0.5" aria-hidden="true" />
                    </button>
                );
            case 'creator':
                return r.creator || '—';
            case 'principal':
                return r.principal || '—';
            case 'type':
                return <StatusBadge tone={complaintTypeTone(r.type)}>{r.type}</StatusBadge>;
            case 'product':
                return <ProductsCell items={r.products} />;
            case 'inputDate':
                return <DateText value={r.inputDate} />;
            case 'history':
                return r.history?.length ? (
                    <HistoryPopover count={r.history.length} title="History">
                        {r.history.map((e, n) => (
                            <div key={n} className="flex flex-col gap-0.5 border-b border-border/50 pb-1.5 last:border-b-0">
                                <div className="flex items-center justify-between gap-2">
                                    <StatusBadge tone={complaintStatusTone(e.status)}>{e.dept ? `${e.status} ${e.dept}` : e.status}</StatusBadge>
                                    <span className="shrink-0 text-[10px] font-medium tabular-nums text-muted-foreground">{e.tanggal}</span>
                                </div>
                                <span className="text-[11px] font-semibold text-foreground">{e.user}</span>
                            </div>
                        ))}
                    </HistoryPopover>
                ) : <span className="text-muted-foreground">—</span>;
            default:
                return '—';
        }
    };

    return (
        <section className="flex min-w-0 flex-col gap-[18px]">
            <header>
                <p className="m-0 mb-1.5 flex items-center gap-2 text-xs font-semibold text-muted-foreground">
                    <span>Complaint Handling</span>
                    <span aria-hidden="true">›</span>
                    <span className="text-foreground">{variant.name}</span>
                </p>
                <h1 className="m-0 text-xl font-bold leading-[1.2] text-card-foreground">Search Complaint Handling Report - {variant.name}</h1>
            </header>

            <article className="overflow-hidden rounded-2xl border border-border bg-card shadow-sm">
                <div ref={filterBarRef} className="flex flex-wrap items-center gap-2.5 border-b border-border/50 px-5 py-4">
                    <label className="relative inline-flex h-8 w-[200px] max-w-full items-center gap-2 rounded-full border border-transparent bg-muted/60 px-3.5 text-muted-foreground transition-colors hover:bg-muted focus-within:border-primary/40 focus-within:bg-card" aria-label="Search report no">
                        <Search aria-hidden="true" className="size-3.5 shrink-0" />
                        <input type="search" inputMode="numeric" placeholder="C. Report No…" autoComplete="off" value={searchDraft}
                            onChange={(e) => setSearchDraft(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') go({ search: searchDraft.trim(), page: 1 }); }}
                            className="min-w-0 flex-1 bg-transparent text-[12.5px] font-medium text-foreground outline-none placeholder:text-muted-foreground/70" />
                    </label>
                    {/* ⚙ on line ONE: DOM position, not `order` — a flex line is filled
                        in order sequence and TOOLBAR_FILTERS is w-full, so anything after
                        it is on line 2 regardless. See TOOLBAR_ROW in Components/Table. */}
                    <button type="button" onClick={() => setCustomizeOpen(true)} title="Customize columns" aria-label="Customize columns"
                        className={TOOLBAR_GEAR}>
                        <Settings className="size-3.5" strokeWidth={2.5} />
                    </button>
                    <div className={TOOLBAR_FILTERS}>
                    <SelectPill label="Type" value={filters.type ?? ''} options={typeOptions}
                        open={openPill === 'type'} onToggle={() => setOpenPill(openPill === 'type' ? null : 'type')}
                        onPick={(v) => { setOpenPill(null); go({ type: v, page: 1 }); }} />
                    <OptionPill label="Principal" value={filters.principal ?? ''} options={principalOptions} searchable
                        open={openPill === 'principal'} onToggle={() => setOpenPill(openPill === 'principal' ? null : 'principal')}
                        onPick={(v) => { setOpenPill(null); go({ principal: v, page: 1 }); }} />
                    <button type="button" onClick={() => go({ search: searchDraft.trim(), page: 1 })}
                        className="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-full bg-linear-to-br from-violet-500 to-primary px-4 text-xs font-bold text-white shadow-sm transition-[filter] hover:brightness-105">
                        <Search aria-hidden="true" className="size-3.5" /> Search
                    </button>
                    {hasFilter && (
                        <button type="button" onClick={resetFilters} className="inline-flex h-8 items-center gap-1.5 px-2.5 text-[12px] font-bold text-muted-foreground transition-colors hover:text-danger-text">Reset filters</button>
                    )}
                    </div>
                </div>

                <div className="overflow-x-auto">
                    <table style={{ minWidth: tableWidth }} className={TABLE_CLASS}>
                        <colgroup>
                            {prefs.visibleCols.map((col) => <col key={col.id} style={{ width: widthOf(col.id) }} />)}
                        </colgroup>
                        <thead>
                            <tr>
                                {prefs.visibleCols.map((col) => (
                                    <th key={col.id} {...prefs.dragProps(col.id)} className={`group/col relative ${col.id === 'history' ? 'text-center' : ''} ${prefs.dragClass(col.id)}`}>
                                        {SORTABLE.has(col.id)
                                            ? <SortButton id={col.id} label={col.label} sortKey={sortKey} sortDir={sortDir} onToggle={toggleSort} />
                                            : col.label}
                                        <ColumnResizeGrip onMouseDown={(e) => startResize(e, col.id)} active={resizingId === col.id} />
                                    </th>
                                ))}
                            </tr>
                        </thead>
                        <tbody>
                            {rows.length === 0 ? (
                                <tr><td colSpan={prefs.visibleCols.length} className="px-4 py-10 text-center italic text-muted-foreground">No reports found.</td></tr>
                            ) : rows.map((r) => (
                                <tr key={r.reportNo}>
                                    {prefs.visibleCols.map((col) => (
                                        <td key={col.id} className={`whitespace-nowrap ${col.id === 'history' ? 'text-center' : ''}`}>
                                            {renderCell(r, col.id)}
                                        </td>
                                    ))}
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>

                <ListFooter
                    page={reports.current_page} totalPages={reports.last_page} onPage={(p) => go({ page: p })}
                    pageSize={reports.per_page} onPageSize={(n) => go({ per_page: n, page: 1 })} pageSizeOptions={[10, 20, 50, 100]}
                    total={reports.total} itemLabel="results" />
            </article>

            <CustomizeColumnsModal
                open={customizeOpen}
                onClose={() => setCustomizeOpen(false)}
                groups={COLUMN_GROUPS}
                definitions={COLUMN_DEFS}
                state={prefs.columnState}
                onApply={prefs.applyColumns}
                onReset={prefs.resetColumns}
            />
        </section>
    );
}

ViewList.layout = [AppLayout];
