// Phase 2 wiring (2026-07-03) of the files-only copy of Pages/Proto/VisitReport/Index.jsx.
// Design is FROZEN — only the data layer changed: mock PLANS + client filtering → the
// server paginator (VisitPlanController@index, scoped to UserIDInput) driven by Inertia's
// router. See ../"VisitPlan PRD.md" for the module contract.
import { useEffect, useMemo, useRef, useState } from 'react';
import { Link, router } from '@inertiajs/react';
import { Search, CalendarDays, RotateCcw, SlidersHorizontal, BarChart3 } from 'lucide-react';
import { ExportButton } from '@/lib/excel/ExportButton';
import { CreateActionButton } from '@/Components/Table/CreateActionButton';
import AppLayout from '@/Layouts/AppLayout';
import { StatusBadge } from '@/Components/Proto/UI/StatusBadge';
import { CheckBox } from '@/Components/Proto/UI/CheckBox';
import { SelectPill } from '@/Components/MenuQuotations/QuotationListPage/QuotationListPills';
import { ListFooter } from '@/Components/Table/ListFooter';
import { useResizableColumns, ColumnResizeGrip } from '@/lib/useResizableColumns';
import { SortButton } from '@/lib/ClientSort';
import { useServerSortNav } from '@/lib/ServerSort';

// Sortable columns — id → row value (alphabetical A→Z on first click).
// Columns the SERVER can order by — must mirror the controller's SORT_COLUMNS.
// A column not listed here renders a plain label instead of a dead sort button.
const SORTABLE = new Set(['id', 'division', 'company', 'schedule', 'meet', 'purpose', 'sales', 'status']);

const CARD = 'rounded-2xl border border-border bg-card shadow-sm';
const TH = 'whitespace-nowrap bg-secondary/50 px-3.5 py-3 text-left text-[11px] font-semibold uppercase tracking-wide text-muted-foreground';
// Resizable columns (left→right) + default widths for the table-fixed layout.
const COLS = ['id', 'division', 'company', 'schedule', 'meet', 'purpose', 'sales', 'status'];
const COL_W = {
    id: 90, division: 130, company: 220, schedule: 150, meet: 200, purpose: 220, sales: 160, status: 140,
};
const COL_W_FALLBACK = 150;
const COL_LABELS = { id: 'ID', division: 'Division', company: 'Company', schedule: 'Schedule', meet: 'Meet With', purpose: 'Purpose', sales: 'Sales', status: 'Status' };
// ID + Company always shown (row anchor); the rest toggle via the ⚙ columns panel, per view.
const REQUIRED_COLS = new Set(['id', 'company']);
// v2 payload = { order: [colId], visible: [colId] } — order (header drag) + visibility
// (⚙ panel). The old v1 key stored a bare visible-id array; it is read once as a
// visibility fallback so nobody loses their prefs on the shape change. Load-guard:
// drop ids no longer in COLS, insert new columns at their default position, and force
// REQUIRED_COLS visible — a stale payload must never hide the row anchor.
const colStorageKey = (view) => `vpListColumns_${view}_v2`;
const defaultColumnPrefs = () => ({ order: [...COLS], visible: new Set(COLS) });
const loadColumnPrefs = (view) => {
    try {
        const raw = JSON.parse(localStorage.getItem(colStorageKey(view)) ?? 'null');
        if (raw && Array.isArray(raw.order)) {
            const order = raw.order.filter((id) => COLS.includes(id));
            COLS.forEach((id, i) => { if (!order.includes(id)) order.splice(i, 0, id); });
            const stored = Array.isArray(raw.visible) ? raw.visible.filter((id) => COLS.includes(id)) : COLS;
            return { order, visible: new Set([...REQUIRED_COLS, ...stored]) };
        }
        const v1 = JSON.parse(localStorage.getItem(`vpListColumns_${view}_v1`) ?? 'null');
        if (Array.isArray(v1)) return { order: [...COLS], visible: new Set([...REQUIRED_COLS, ...v1.filter((id) => COLS.includes(id))]) };
    } catch { /* SSR render / corrupt JSON → default */ }
    return defaultColumnPrefs();
};
// Per-column cell renderers (each td carries key=col id for the visibleCols map).
const CELL = {
    id: (p) => <td key="id" className="whitespace-nowrap px-3.5 py-[13px] text-[12px] font-bold tabular-nums text-primary">#{p.id}</td>,
    division: (p) => <td key="division" className="whitespace-nowrap px-3.5 py-[13px] text-[12px] text-foreground">{p.division}</td>,
    company: (p) => <td key="company" className="whitespace-nowrap px-3.5 py-[13px] text-[12px] font-semibold text-foreground">{p.company}</td>,
    schedule: (p) => (
        <td key="schedule" className="whitespace-nowrap px-3.5 py-[13px] text-[12px] text-foreground">
            <span className="flex items-center gap-1.5"><CalendarDays className="size-3.5 shrink-0 text-muted-foreground" /><span className="tabular-nums">{p.date}</span></span>
            <span className="mt-0.5 block pl-5 text-[11px] tabular-nums text-muted-foreground">{p.from}–{p.to}</span>
        </td>
    ),
    meet: (p) => <td key="meet" className="whitespace-nowrap px-3.5 py-[13px] text-[12px] text-muted-foreground">{p.meet}</td>,
    purpose: (p) => <td key="purpose" className="px-3.5 py-[13px] text-[12px] text-foreground">{p.purpose}</td>,
    sales: (p) => <td key="sales" className="whitespace-nowrap px-3.5 py-[13px] text-[12px] text-muted-foreground">{p.sales}</td>,
    status: (p) => <td key="status" className="whitespace-nowrap px-3.5 py-[13px]"><StatusBadge tone={p.statusTone}>{p.status}</StatusBadge></td>,
};

export default function VisitPlansList({ visitPlans, filters, filterOptions, canCreate = false, canCreateOthers = false, view = 'own' }) {
    // Bucket A: one page serves the own list + the View-All tiers. Own keeps the create
    // buttons; every view's rows open the report (owner → file/cancel, tier manager →
    // comment/change-status — the report page gates per-plan by capability).
    const isOwn = view === 'own';
    const isCreateReport = view === 'createReport';
    // Carry the originating menu into the report page so it offers ONLY this tier's actions
    // (legacy ships one report file per menu). Without it the page would fall back to 'own'.
    const openReport = (id) => router.get(route('visit-plans.report', [id, view]));
    const listRouteName = isCreateReport ? 'visit-plans.create-report' : (isOwn ? 'visit-plans.index' : `visit-plans.view-${view}`);
    const calendarRouteName = (isOwn || isCreateReport) ? 'visit-plans.calendar' : `visit-plans.calendar.${view}`;
    const graphView = (isOwn || isCreateReport) ? 'own' : view;
    const heading = ({ own: 'Visit Report', createReport: 'Create Visit Report', all: 'View All - Visit Plan', head: 'View All Visit Plan Head Dept', sm: 'View All Visit Plan SM', mm: 'View All Visit Plan MM' })[view] ?? 'Visit Report';

    const [q, setQ] = useState(filters.search ?? '');
    // Canonical list toolbar: SelectPill dropdowns (open/toggle + click-away), not native selects.
    const [activePill, setActivePill] = useState(null);
    const togglePill = (key) => setActivePill((cur) => (cur === key ? null : key));
    const anyFilter = Boolean(q || filters.division || filters.status);
    const resetFilters = () => { setQ(''); setActivePill(null); reload({ search: '', division: '', status: '', page: 1 }); };

    // Push a server visit with the current filters merged with `next` (page resets to 1
    // on any filter change). preserveState keeps the search box focused/typed; replace
    // avoids stacking history entries per keystroke.
    const reload = (next) => {
        router.get(route(listRouteName), {
            search: q,
            division: filters.division,
            status: filters.status,
            per_page: filters.per_page,
            ...next,
        }, {
            // only: — without it the server still evaluates the filterOptions closure and
            // re-runs both scoped DISTINCT scans on EVERY keystroke and page click.
            // `filters` MUST be listed: the page size and the pill values are read from
            // it, not from local state. See .claude/rules/list-pagination.md.
            only: ['visitPlans', 'filters'],
            preserveState: true, preserveScroll: true, replace: true,
        });
    };

    // Debounce the search box → server (skip the initial mount).
    const firstRender = useRef(true);
    useEffect(() => {
        if (firstRender.current) { firstRender.current = false; return; }
        const t = setTimeout(() => reload({ search: q, page: 1 }), 300);
        return () => clearTimeout(t);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [q]);

    // Server-side sort: the DATABASE orders the whole table, not the browser the page.
    const { sortKey, sortDir, toggleSort } = useServerSortNav(null, filters);
    const rows = visitPlans.data ?? [];

    // Resizable columns — drag a header's right edge to resize.
    const { widthOf, startResize, resizingId, resizeRef } = useResizableColumns(COL_W, COL_W_FALLBACK);

    // Column order + visibility (header drag + ⚙ panel) — persisted per view in localStorage.
    const [colPrefs, setColPrefs] = useState(() => loadColumnPrefs(view));
    const visibleSet = colPrefs.visible;
    const visibleCols = useMemo(() => colPrefs.order.filter((id) => colPrefs.visible.has(id)), [colPrefs]);
    const tableWidth = useMemo(() => visibleCols.reduce((s, id) => s + widthOf(id), 0), [visibleCols, widthOf]);
    const persistCols = (next) => {
        try { localStorage.setItem(colStorageKey(view), JSON.stringify({ order: next.order, visible: [...next.visible] })); } catch { /* private mode */ }
    };
    const toggleColumn = (id) => {
        if (REQUIRED_COLS.has(id)) return;
        setColPrefs((prev) => {
            const visible = new Set(prev.visible);
            visible.has(id) ? visible.delete(id) : visible.add(id);
            const next = { ...prev, visible };
            persistCols(next);
            return next;
        });
    };
    const resetColumns = () => {
        try { localStorage.removeItem(colStorageKey(view)); localStorage.removeItem(`vpListColumns_${view}_v1`); } catch { /* private mode */ }
        setColPrefs(defaultColumnPrefs());
    };

    // Header drag-to-reorder — drop one column title onto another (mirrors LwrListPage).
    const [dragColId, setDragColId] = useState(null);
    const [dragOverColId, setDragOverColId] = useState(null);
    const reorderCols = (fromId, toId) => {
        if (!fromId || !toId || fromId === toId) return;
        setColPrefs((prev) => {
            const fi = prev.order.indexOf(fromId);
            const ti = prev.order.indexOf(toId);
            if (fi < 0 || ti < 0) return prev;
            const order = [...prev.order];
            const [moved] = order.splice(fi, 1);
            order.splice(ti, 0, moved);
            const next = { ...prev, order };
            persistCols(next);
            return next;
        });
    };

    return (
        <section className="flex min-w-0 flex-col gap-4">
            <header className="flex flex-wrap items-center justify-between gap-3">
                <div>
                    <h1 className="m-0 text-2xl font-extrabold tracking-tight text-foreground">{heading}</h1>
                    <p className="m-0 mt-1 text-[13px] font-medium text-muted-foreground">Daftar rencana & laporan kunjungan ke pelanggan.</p>
                </div>
                <div className="flex items-center gap-2">
                    <Link href={route(calendarRouteName)} 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 shadow-sm transition-colors hover:border-primary hover:text-primary">
                        <CalendarDays className="size-3.5" /> Calendar
                    </Link>
                    <Link href={route('visit-plans.graph', graphView)} 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 shadow-sm transition-colors hover:border-primary hover:text-primary">
                        <BarChart3 className="size-3.5" /> Graph
                    </Link>
                    <ExportButton specKey="visitPlanExport" url={route('visit-plans.export', view)} params={{ search: q, division: filters.division, status: filters.status }} label="Export" className="h-9 px-4 text-[11px]" />
                    <CreateActionButton
                        canCreate={canCreate}
                        label="New Visit Plan"
                        href={route('visit-plans.create')}
                        variants={[{ key: 'others', label: 'For Others', can: canCreateOthers, href: route('visit-plans.create-for-others') }]}
                    />
                </div>
            </header>

            <article className={`${CARD} overflow-hidden`}>
                {/* Click-away layer that closes any open filter pill. */}
                {activePill && <div className="fixed inset-0 z-40" onClick={() => setActivePill(null)} />}
                {/* toolbar */}
                <div className="flex flex-wrap items-center gap-2.5 border-b border-border/50 px-5 py-3.5">
                    <label className="relative inline-flex h-8 min-w-[200px] max-w-[320px] flex-1 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">
                        <Search aria-hidden="true" className="size-3.5 shrink-0" />
                        <input type="search" value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search company, purpose, sales…" autoComplete="off"
                            className="min-w-0 flex-1 bg-transparent text-[12.5px] font-medium text-foreground outline-none placeholder:text-muted-foreground/70" />
                    </label>

                    <div className="flex flex-wrap items-center gap-2.5">
                        <SelectPill label="Division" value={filters.division} options={filterOptions.divisions} open={activePill === 'division'} onToggle={() => togglePill('division')} onPick={(v) => { setActivePill(null); reload({ division: v, page: 1 }); }} />
                        <SelectPill label="Status" value={filters.status} options={filterOptions.statuses} open={activePill === 'status'} onToggle={() => togglePill('status')} onPick={(v) => { setActivePill(null); reload({ status: v, page: 1 }); }} />
                    </div>

                    <div className="ml-auto inline-flex items-center gap-2">
                        {anyFilter && (
                            <button type="button" onClick={resetFilters} title="Reset semua filter"
                                className="inline-flex h-8 items-center gap-1.5 rounded-full px-2.5 text-[12px] font-bold text-muted-foreground transition-colors hover:text-primary">
                                <RotateCcw className="size-3.5" /> Reset
                            </button>
                        )}
                        {/* ⚙ column settings — show/hide columns, persisted per view */}
                        <div className="relative z-50">
                            <button type="button" title="Configure columns" aria-label="Configure columns" aria-pressed={activePill === 'columns'}
                                onClick={() => togglePill('columns')}
                                className={`grid size-7 place-items-center rounded-md transition-colors ${activePill === 'columns' ? 'bg-accent text-primary' : 'text-muted-foreground hover:bg-muted hover:text-foreground'}`}>
                                <SlidersHorizontal className="size-3.5" strokeWidth={2.5} />
                            </button>
                            {activePill === 'columns' && (
                                <div className="absolute right-0 top-full z-50 mt-1.5 w-[200px] rounded-xl border border-border bg-surface py-2 shadow-modal">
                                    <div className="flex items-center justify-between px-3.5 pb-1.5">
                                        <span className="text-[10px] font-extrabold uppercase tracking-wider text-muted-foreground">Columns</span>
                                        <button type="button" onClick={resetColumns} className="text-[11px] font-bold text-primary hover:underline">Reset</button>
                                    </div>
                                    {COLS.map((id) => (
                                        <label key={id} className={`flex w-full items-center gap-2.5 px-3.5 py-1.5 text-[12.5px] font-medium ${REQUIRED_COLS.has(id) ? 'cursor-default text-muted-foreground/60' : 'cursor-pointer text-foreground hover:bg-surface-tint'}`}
                                            title={REQUIRED_COLS.has(id) ? 'Required column' : undefined}>
                                            <CheckBox size="sm" checked={visibleSet.has(id)} disabled={REQUIRED_COLS.has(id)} onChange={() => toggleColumn(id)} ariaLabel={`Show column ${COL_LABELS[id]}`} />
                                            {COL_LABELS[id]}
                                        </label>
                                    ))}
                                </div>
                            )}
                        </div>
                    </div>
                </div>

                {/* table */}
                {rows.length === 0 ? (
                    <p className="py-12 text-center text-sm text-muted-foreground">No visit plan matches the filter.</p>
                ) : (
                    <div className="overflow-x-auto">
                        <table style={{ minWidth: tableWidth }} className="w-full table-fixed border-separate border-spacing-0 [&_tbody_td]:overflow-hidden [&_td:first-child]:pl-7 [&_td:last-child]:pr-5 [&_thead_tr:first-child_th:first-child]:rounded-tl-full [&_thead_tr:first-child_th:first-child]:pl-7 [&_thead_tr:first-child_th:last-child]:rounded-tr-full [&_thead_tr:first-child_th:last-child]:pr-5 [&_thead_tr:last-child_th:first-child]:rounded-bl-full [&_thead_tr:last-child_th:first-child]:pl-7 [&_thead_tr:last-child_th:last-child]:rounded-br-full [&_thead_tr:last-child_th:last-child]:pr-5">
                            <colgroup>
                                {visibleCols.map((id) => <col key={id} style={{ width: widthOf(id) }} />)}
                            </colgroup>
                            <thead>
                                <tr>
                                    {visibleCols.map((id) => (
                                        <th key={id}
                                            draggable
                                            onDragStart={(e) => { if (resizeRef.current) { e.preventDefault(); return; } setDragColId(id); }}
                                            onDragOver={(e) => { e.preventDefault(); setDragOverColId(id); }}
                                            onDrop={() => { reorderCols(dragColId, id); setDragColId(null); setDragOverColId(null); }}
                                            onDragEnd={() => { setDragColId(null); setDragOverColId(null); }}
                                            title="Drag to reorder"
                                            className={`${TH} group/col relative cursor-grab select-none active:cursor-grabbing ${dragColId === id ? 'opacity-40' : ''} ${dragOverColId === id && dragColId !== id ? '!bg-accent !text-primary' : ''}`}>
                                            <SortButton id={id} label={COL_LABELS[id]} sortKey={sortKey} sortDir={sortDir} onToggle={toggleSort} />
                                            <ColumnResizeGrip onMouseDown={(e) => startResize(e, id)} active={resizingId === id} />
                                        </th>
                                    ))}
                                </tr>
                            </thead>
                            <tbody>
                                {rows.map((p) => (
                                    <tr key={p.id}
                                        role="link" tabIndex={0}
                                        onClick={() => openReport(p.id)}
                                        onKeyDown={(e) => { if (e.key === 'Enter') openReport(p.id); }}
                                        className="cursor-pointer border-b border-border/60 even:bg-secondary/25 last:border-b-0 hover:bg-secondary/60 focus:outline-none focus-visible:bg-accent/30">
                                        {visibleCols.map((id) => CELL[id](p))}
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                )}

                <ListFooter
                    page={visitPlans.current_page}
                    totalPages={visitPlans.last_page}
                    onPage={(n) => reload({ page: n })}
                    pageSize={filters.per_page}
                    onPageSize={(n) => reload({ per_page: n, page: 1 })}
                    pageSizeOptions={[10, 25, 50]}
                    total={visitPlans.total}
                    from={visitPlans.from}
                    to={visitPlans.to}
                    itemLabel="plans"
                />
            </article>
        </section>
    );
}

VisitPlansList.layout = [AppLayout];
