import { useMemo, useState } from 'react';
import { TOOLBAR_GEAR, TOOLBAR_FILTERS } from '@/Components/Table';
import { router } from '@inertiajs/react';
import { Search, RotateCcw, Settings, Download } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { FilterPill } from '@/Components/ui/filter-pill';
import { SelectPill } from '@/Components/MenuQuotations/QuotationListPage/QuotationListPills';
import { CustomizeColumnsModal } from '@/Components/Proto/Modals/CustomizeColumnsModal';
import { ListFooter } from '@/Components/Table/ListFooter';
import { ExportButton } from '@/lib/excel/ExportButton';
import { SortButton } from '@/lib/ClientSort';
import { useServerSortNav } from '@/lib/ServerSort';
import { useResizableColumns, ColumnResizeGrip } from '@/lib/useResizableColumns';
import { cn } from '@/lib/utils';

/**
 * PrincipalDownload › Index — read-only, security-scoped principal-document
 * download view (regular: assigned principals + sales-view categories + IsShow=1).
 * Server-driven filter/paging via Inertia partial reloads (only:['documents','filters']),
 * matching the app's list idiom (see Pages/MenuDocuments/PrincipalDocuments/Index.jsx).
 * Backend: PrincipalDocumentDownloadController@index (route documents.principal.browse).
 *
 * READ-ONLY browse: no Edit / Delete / Restore / Insert, no IsShow / Expiry columns —
 * just filters + a table of Download links. Filters live in a compact toolbar directly
 * above the table (Sample Order / Quotation grammar); columns are hide/reorder-able.
 */

const CARD = 'rounded-2xl border border-border bg-card shadow-sm';
const TH = 'whitespace-nowrap bg-secondary/50 px-3.5 py-3 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground first:rounded-l-full first:pl-5 last:rounded-r-full last:pr-5';
const TD = 'overflow-hidden whitespace-nowrap border-b border-border/60 px-3.5 py-[16px] align-middle text-[12px] first:pl-5 last:pr-5';

// Column catalogue — `groupId` buckets the column inside the Customize Columns modal
// (hide + reorder). Document Name stays `required` as the row anchor.
const COLUMN_GROUPS = [
    { id: 'document', label: 'Document' },
    { id: 'file', label: 'File' },
];
const COLUMN_DEFS = [
    { id: 'no', label: 'No', groupId: 'document' },
    { id: 'download', label: 'Download', groupId: 'document' },
    { id: 'category', label: 'Document Category', groupId: 'document' },
    { id: 'principal', label: 'Principal Name', groupId: 'document' },
    { id: 'name', label: 'Document Name', groupId: 'document', required: true },
    { id: 'type', label: 'Type', groupId: 'file' },
    { id: 'size', label: 'Size', num: true, groupId: 'file' },
];

// Sortable columns — id → RAW row value (data columns only; No / Download excluded).
// 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(['category', 'principal', 'name', 'type', 'size']);

// Default column widths (px) for the resizable table-fixed layout.
const COL_W = { no: 64, download: 120, category: 180, principal: 190, name: 260, type: 160, size: 110 };

// Legacy size display = nf(size/1000): kilobytes (÷1000) with 2 decimals + " kb".
const fmtKb = (bytes) => (Number(bytes || 0) / 1000).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' kb';

// Per-column cell renderer — markup identical to the previous hardcoded <td>s.
function renderCell(d, colId, ctx) {
    switch (colId) {
        case 'no': return <span className="tabular-nums text-muted-foreground">{ctx.rowNumber}</span>;
        case 'download': return (
            <a href={route('documents.principal.browse.file', d.ID)}
                className="inline-flex items-center gap-1 text-[11px] font-bold text-primary transition-colors hover:underline">
                <Download className="size-3" /> Download
            </a>
        );
        case 'category': return <span className="block max-w-40 truncate text-muted-foreground">{d.DocumentCategoryName || '—'}</span>;
        case 'principal': return <span className="block max-w-42 truncate font-semibold text-foreground">{d.PrincipalName || '—'}</span>;
        case 'name': return <span className="block max-w-55 truncate font-medium text-foreground">{d.name}</span>;
        case 'type': return <span className="block max-w-37.5 truncate text-muted-foreground">{d.type}</span>;
        case 'size': return <span className="tabular-nums text-muted-foreground">{fmtKb(d.size)}</span>;
        default: return null;
    }
}

// Pinned chrome columns — not draggable and not drop targets for the header drag.
const FIXED_COL_IDS = new Set(['no', 'download']);

// Column state = ordered [{id, visible}] — order AND visibility both persist.
const defaultColumnState = () => COLUMN_DEFS.map((d) => ({ id: d.id, visible: true }));
function loadColumnState(storageKey) {
    try {
        const raw = localStorage.getItem(storageKey);
        if (!raw) return defaultColumnState();
        const parsed = JSON.parse(raw).filter((c) => c && COLUMN_DEFS.some((d) => d.id === c.id));
        COLUMN_DEFS.forEach((d, i) => { if (!parsed.some((c) => c.id === d.id)) parsed.splice(i, 0, { id: d.id, visible: true }); });
        return parsed;
    } catch {
        return defaultColumnState();
    }
}

export default function Index({ documents, filters = {}, categories = [], principals = [], groupDivisions = [] }) {
    const [name, setName] = useState(filters.Name || '');
    const [categoryId, setCategoryId] = useState(filters.CategoryID ? String(filters.CategoryID) : '');
    const [principalIds, setPrincipalIds] = useState(Array.isArray(filters.PrincipalID) ? filters.PrincipalID.map(Number) : []);
    const [groupDivIds, setGroupDivIds] = useState(Array.isArray(filters.GroupDivID) ? filters.GroupDivID.map(Number) : []);

    // Client-side sort over the current server page + resizable columns (house pattern).
    // Server-side sort: the DATABASE orders the whole table, not the browser the page.
    const { sortKey, sortDir, toggleSort } = useServerSortNav('documents.principal.browse', filters);
    const rows = documents.data ?? [];
    const { widthOf, startResize, resizingId, resizeRef } = useResizableColumns(COL_W);

    const perPage = Number(filters.npp || documents.per_page || 10);
    const from = documents.from ?? 0;
    const hasActiveFilter = name !== '' || categoryId !== '' || principalIds.length > 0 || groupDivIds.length > 0;

    // Column show/hide + reorder, persisted per user.
    const storageKey = 'principalDownloadColumns_v1';
    const colDefById = useMemo(() => new Map(COLUMN_DEFS.map((d) => [d.id, d])), []);
    const [columnState, setColumnState] = useState(() => loadColumnState(storageKey));
    const [customizeOpen, setCustomizeOpen] = useState(false);
    const visibleCols = useMemo(() => columnState.filter((c) => c.visible).map((c) => colDefById.get(c.id)).filter(Boolean), [columnState, colDefById]);
    const isDefaultOrder = columnState.length === COLUMN_DEFS.length && columnState.every((c, i) => c.id === COLUMN_DEFS[i].id && c.visible);
    const tableWidth = useMemo(() => visibleCols.reduce((sum, c) => sum + widthOf(c.id), 0), [visibleCols, widthOf]);

    const persistCols = (next) => { try { localStorage.setItem(storageKey, JSON.stringify(next)); } catch { /* ignore */ } };
    const handleApplyColumns = (next) => { setColumnState(next); persistCols(next); };
    // Direct header drag-to-reorder (LwrListPage pattern) — splices columnState and
    // persists via persistCols; resizeRef bails out so a grip drag never starts a column drag.
    const [dragColId, setDragColId] = useState(null);
    const [dragOverColId, setDragOverColId] = useState(null);
    const reorderCols = (fromId, toId) => {
        if (!fromId || !toId || fromId === toId || FIXED_COL_IDS.has(fromId) || FIXED_COL_IDS.has(toId)) return;
        setColumnState((prev) => {
            const from = prev.findIndex((c) => c.id === fromId);
            const to = prev.findIndex((c) => c.id === toId);
            if (from < 0 || to < 0) return prev;
            const next = [...prev];
            const [moved] = next.splice(from, 1);
            next.splice(to, 0, moved);
            persistCols(next);
            return next;
        });
    };
    const dragProps = (id) => (FIXED_COL_IDS.has(id) ? {} : {
        draggable: true,
        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 · drag right edge to resize',
    });
    const dragClass = (id) => (FIXED_COL_IDS.has(id) ? '' : cn('cursor-grab select-none active:cursor-grabbing', dragColId === id && 'opacity-40', dragOverColId === id && dragColId !== id && 'bg-accent text-primary'));
    // Returns the default state so the modal's Reset can seed its draft with it.
    const resetCols = () => {
        const next = defaultColumnState();
        setColumnState(next);
        try { localStorage.removeItem(storageKey); } catch { /* ignore */ }
        return next;
    };

    // Build params from control state (+ overrides) and fire a partial reload of the list.
    // Arrays (PrincipalID/GroupDivID) serialize to PrincipalID[]=1&PrincipalID[]=2; omit when empty.
    const go = (overrides = {}) => {
        const src = {
            Name: name,
            CategoryID: categoryId,
            PrincipalID: principalIds,
            GroupDivID: groupDivIds,
            npp: perPage,
            ...overrides,
        };
        const defaults = { npp: 10, page: 1 };
        const params = {};
        Object.entries(src).forEach(([k, v]) => {
            if (Array.isArray(v)) { if (v.length) params[k] = v; return; }
            if (v === '' || v === null || v === undefined) return;
            if (k in defaults && String(v) === String(defaults[k])) return;
            params[k] = v;
        });
        router.get(route('documents.principal.browse'), params, {
            only: ['documents', 'filters'], preserveState: true, preserveScroll: true, replace: true,
        });
    };

    const reset = () => {
        setName(''); setCategoryId(''); setPrincipalIds([]); setGroupDivIds([]);
        router.get(route('documents.principal.browse'), {}, {
            only: ['documents', 'filters'], preserveState: true, preserveScroll: true, replace: true,
        });
    };

    const principalOptions = principals.map((p) => ({ id: p.ID, name: p.PrincipalName }));
    const groupDivOptions = groupDivisions.map((g) => ({ id: g.ID, name: g.GroupDivisionName }));
    const categoryOptions = categories.map((c) => ({ id: String(c.ID), name: c.DocumentCategoryName }));

    return (
        <section className="flex min-w-0 flex-col gap-5">
            <header className="flex flex-wrap items-center justify-between gap-3">
                <h1 className="m-0 text-xl font-bold leading-[1.2] text-card-foreground">Principal Documents — Download</h1>
                {/* Export re-applies the scoped query server-side; params mirror go()'s live filter state. */}
                <ExportButton
                    specKey="principalDownloadExport"
                    url={route('documents.principal.browse.exportData')}
                    params={{ Name: name, CategoryID: categoryId, PrincipalID: principalIds, GroupDivID: groupDivIds }}
                />
            </header>

            <article className={CARD}>
                {/* Compact filter toolbar — same grammar as the Sample Order / Quotation lists. */}
                <div 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-[240px] 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"
                            placeholder="Search name…"
                            autoComplete="off"
                            value={name}
                            onChange={(e) => setName(e.target.value)}
                            onKeyDown={(e) => { if (e.key === 'Enter') go({ 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. 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="Category" value={categoryId} options={categoryOptions}
                        onPick={(v) => { setCategoryId(v); go({ page: 1, CategoryID: v }); }} />
                    <FilterPill label="Principal" value={principalIds} options={principalOptions}
                        onChange={(v) => { setPrincipalIds(v); go({ page: 1, PrincipalID: v }); }} />
                    <FilterPill label="Group Division" value={groupDivIds} options={groupDivOptions}
                        onChange={(v) => { setGroupDivIds(v); go({ page: 1, GroupDivID: v }); }} />

                    {hasActiveFilter && (
                        <button type="button" onClick={reset} title="Reset all active filters"
                            className="inline-flex h-8 cursor-pointer items-center gap-1.5 rounded-full px-2.5 text-[12.5px] font-semibold text-muted-foreground transition-colors hover:bg-danger/10 hover:text-danger-text">
                            <RotateCcw className="size-3.5" />
                            <span>Reset filters</span>
                        </button>
                    )}

                    <div className="ml-auto inline-flex items-center gap-2">
                        {!isDefaultOrder && (
                            <button type="button" onClick={resetCols} title="Reset column order"
                                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>
                        )}
                    </div>
                    </div>
                </div>

                <div className="overflow-x-auto">
                    <table style={{ minWidth: tableWidth }} className="w-full table-fixed border-separate border-spacing-0 text-left">
                        <colgroup>
                            {visibleCols.map((c) => <col key={c.id} style={{ width: widthOf(c.id) }} />)}
                        </colgroup>
                        <thead>
                            <tr>
                                {visibleCols.map((c) => (
                                    <th key={c.id} {...dragProps(c.id)} className={cn(TH, 'group/col relative', c.num && 'text-right', dragClass(c.id))}>
                                        {SORTABLE.has(c.id)
                                            ? <SortButton id={c.id} label={c.label} sortKey={sortKey} sortDir={sortDir} onToggle={toggleSort} />
                                            : c.label}
                                        <ColumnResizeGrip onMouseDown={(e) => startResize(e, c.id)} active={resizingId === c.id} />
                                    </th>
                                ))}
                            </tr>
                        </thead>
                        <tbody>
                            {rows.length === 0 ? (
                                <tr><td colSpan={visibleCols.length} className={`${TD} py-10 text-center text-muted-foreground`}>No document matches the filter.</td></tr>
                            ) : rows.map((d, i) => (
                                <tr key={d.ID} className="transition-colors even:bg-secondary/25 hover:bg-secondary/60">
                                    {visibleCols.map((c) => (
                                        <td key={c.id} className={cn(TD, c.num && 'text-right')}>
                                            {renderCell(d, c.id, { rowNumber: from + i })}
                                        </td>
                                    ))}
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>

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

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

Index.layout = [AppLayout];
