import { useMemo, useState } from 'react';
import { TOOLBAR_GEAR, TOOLBAR_FILTERS } from '@/Components/Table';
import { Link, router } from '@inertiajs/react';
import { Search, RotateCcw, Settings, Download, Pencil, Trash2, X } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { SelectPill } from '@/Components/MenuQuotations/QuotationListPage/QuotationListPills';
import { CustomizeColumnsModal } from '@/Components/Proto/Modals/CustomizeColumnsModal';
import { ListFooter } from '@/Components/Table/ListFooter';
import { CreateActionButton } from '@/Components/Table/CreateActionButton';
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';

/**
 * PrincipalDocuments › Index — admin document library (server-driven).
 * Visual style adapted from Pages/Proto/Documents/Index.jsx; filtering / paging
 * are server-side (PrincipalDocumentController@index) via Inertia partial reloads
 * (only:['documents','filters']) — the project's base server-paginated-list pattern
 * (see Pages/MenuCompanies/Companies/List.jsx).
 */

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). Name stays `required` as the row anchor. Order here = default order.
const COLUMN_GROUPS = [
    { id: 'actions', label: 'Actions' },
    { id: 'document', label: 'Document' },
    { id: 'file', label: 'File' },
];
const COLUMN_DEFS = [
    { id: 'no', label: 'No', groupId: 'document' },
    { id: 'show', label: 'Show', groupId: 'actions' },
    { id: 'download', label: 'Download', groupId: 'actions' },
    { id: 'principal', label: 'Principal Name', groupId: 'document' },
    { id: 'category', label: 'Document Category', groupId: 'document' },
    { id: 'name', label: 'Name', groupId: 'document', required: true },
    { id: 'type', label: 'Type', groupId: 'file' },
    { id: 'size', label: 'Size', num: true, groupId: 'file' },
    { id: 'expiry', label: 'Expiry Date', groupId: 'file' },
    { id: 'edit', label: 'Actions', num: true, groupId: 'actions' },
];

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

// 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();
    }
}

const validExpiry = (v) => v && v !== '0000-00-00';
// 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';

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

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

// Per-column cell renderer — markup identical to the previous hardcoded <td>s.
// `ctx` carries the row number + the two row actions the action column needs.
function renderCell(d, colId, ctx) {
    switch (colId) {
        case 'no': return <span className="tabular-nums text-muted-foreground">{ctx.rowNumber}</span>;
        case 'edit': return (
            <div className="flex items-center justify-end gap-1">
                {d.IsDeleted ? (
                    <button type="button" onClick={() => ctx.restore(d)} title="Restore" aria-label="Restore"
                        className="inline-grid size-7 place-items-center rounded-md text-success-text transition-colors hover:bg-success-bg">
                        <RotateCcw className="size-3.5" />
                    </button>
                ) : (
                    <>
                        <Link href={route('documents.principal.edit', d.ID)} title="Edit" aria-label="Edit"
                            className="inline-grid size-7 place-items-center rounded-md text-primary transition-colors hover:bg-primary/10">
                            <Pencil className="size-3.5" />
                        </Link>
                        <button type="button" onClick={() => ctx.setDeleteTarget(d)} title="Delete" aria-label="Delete"
                            className="inline-grid size-7 place-items-center rounded-md text-danger-text transition-colors hover:bg-danger-bg">
                            <Trash2 className="size-3.5" />
                        </button>
                    </>
                )}
            </div>
        );
        case 'show': return d.IsShow
            ? <span className="inline-flex items-center rounded-full bg-success-bg px-2 py-0.5 text-[10.5px] font-semibold text-success-text">Yes</span>
            : <span className="inline-flex items-center rounded-full bg-secondary px-2 py-0.5 text-[10.5px] font-semibold text-muted-foreground">No</span>;
        case 'download': return (
            <a href={route('documents.principal.download', 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 'principal': return <span className="block max-w-42 truncate font-semibold text-foreground">{d.PrincipalName || '—'}</span>;
        case 'category': return <span className="block max-w-40 truncate text-muted-foreground">{d.DocumentCategoryName || '—'}</span>;
        case 'name': return (
            <span className="flex items-center gap-1.5">
                <span className="block max-w-55 truncate font-medium text-foreground">{d.name}</span>
                {d.IsDeleted && <span className="inline-flex shrink-0 items-center gap-1 rounded-full bg-secondary px-2 py-0.5 text-[9.5px] font-bold text-muted-foreground"><span className="size-1.5 rounded-full bg-danger" aria-hidden="true" /> Deleted</span>}
            </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>;
        case 'expiry': return <span className={`tabular-nums ${validExpiry(d.ExpiryDate) ? 'text-muted-foreground' : 'text-muted-foreground/40'}`}>{validExpiry(d.ExpiryDate) ? d.ExpiryDate : '—'}</span>;
        default: return null;
    }
}

export default function Index({ canCreate = false, documents, filters = {}, principals = [], categories = [] }) {
    const [principalId, setPrincipalId] = useState(filters.PrincipalID ? String(filters.PrincipalID) : '');
    const [categoryId, setCategoryId] = useState(filters.CategoryID ? String(filters.CategoryID) : '');
    const [name, setName] = useState(filters.Name || '');
    const [isDeleted, setIsDeleted] = useState(Boolean(filters.IsDeleted));
    const [deleteTarget, setDeleteTarget] = useState(null);

    // Column show/hide + reorder, persisted per user (same grammar as the Sample Order lists).
    const storageKey = 'principalDocumentColumns_v2';
    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 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;
    };

    // 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.index', filters);
    const rows = documents.data ?? [];
    const { widthOf, startResize, resizingId, resizeRef } = useResizableColumns(COL_W);
    const tableWidth = useMemo(() => visibleCols.reduce((sum, c) => sum + widthOf(c.id), 0), [visibleCols, widthOf]);

    const perPage = Number(filters.npp || documents.per_page || 10);
    const from = documents.from ?? 0;
    const hasActiveFilter = principalId !== '' || categoryId !== '' || name !== '' || isDeleted;

    // Build params from control state (+ overrides) and fire a partial reload of the list.
    const go = (overrides = {}) => {
        const src = {
            PrincipalID: principalId,
            CategoryID: categoryId,
            Name: name,
            IsDeleted: isDeleted ? 'on' : '',
            npp: perPage,
            ...overrides,
        };
        const defaults = { npp: 10, page: 1 };
        const params = {};
        Object.entries(src).forEach(([k, v]) => {
            if (v === '' || v === null || v === undefined || v === false) return;
            if (k in defaults && String(v) === String(defaults[k])) return;
            params[k] = v;
        });
        router.get(route('documents.principal.index'), params, {
            only: ['documents', 'filters'], preserveState: true, preserveScroll: true, replace: true,
        });
    };

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

    const restore = (d) => router.patch(route('documents.principal.restore', d.ID), {}, { preserveScroll: true });
    const confirmDelete = () => {
        if (!deleteTarget) return;
        router.delete(route('documents.principal.destroy', deleteTarget.ID), {
            preserveScroll: true,
            onSuccess: () => setDeleteTarget(null),
        });
    };

    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-2xl font-bold leading-[1.15] tracking-tight text-card-foreground">Documents</h1>
                <div className="flex flex-wrap items-center gap-2">
                    {/* Params mirror go()'s `src` exactly — the live filter state, not the URL. */}
                    <ExportButton
                        specKey="principalDocumentExport"
                        url={route('documents.principal.exportData')}
                        params={{
                            PrincipalID: principalId,
                            CategoryID: categoryId,
                            Name: name,
                            IsDeleted: isDeleted ? 'on' : '',
                        }}
                    />
                    <CreateActionButton canCreate={canCreate} label="Insert Document" href={route('documents.principal.create')} />
                </div>
            </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="Principal" value={principalId}
                        options={principals.map((p) => ({ id: String(p.ID), name: p.PrincipalName }))}
                        onPick={(v) => { setPrincipalId(v); go({ page: 1, PrincipalID: v }); }} />
                    <SelectPill label="Category" value={categoryId}
                        options={categories.map((c) => ({ id: String(c.ID), name: c.DocumentCategoryName }))}
                        onPick={(v) => { setCategoryId(v); go({ page: 1, CategoryID: v }); }} />

                    {/* Toggle pill for soft-deleted rows — canonical red-dot pill (house rule) */}
                    <button type="button" aria-pressed={isDeleted}
                        title={isDeleted ? 'Hide deleted rows' : 'Show deleted rows'}
                        onClick={() => { const v = !isDeleted; setIsDeleted(v); go({ page: 1, IsDeleted: v ? 'on' : '' }); }}
                        className={cn('inline-flex h-8 shrink-0 cursor-pointer select-none items-center gap-2 whitespace-nowrap rounded-full border px-3 text-[12.5px] transition-colors',
                            isDeleted
                                ? 'border-danger/40 bg-danger/10 font-semibold text-danger-text hover:bg-danger/15'
                                : 'border-border/60 bg-card font-medium text-muted-foreground hover:border-danger/40 hover:text-danger-text')}>
                        <span className={cn('size-1.5 rounded-full', isDeleted ? 'bg-danger-text' : 'bg-danger/60')} />
                        <span>Show deleted</span>
                        {isDeleted && (
                            <span className="ml-0.5 inline-grid size-4 place-items-center rounded-full bg-danger-text/15 text-[10px] font-bold">✓</span>
                        )}
                    </button>

                    {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}
                                    onClick={(e) => { if (e.target.closest('a,button,input,label')) return; if (!d.IsDeleted) router.visit(route('documents.principal.edit', d.ID)); }}
                                    className={cn('transition-colors', !d.IsDeleted && 'cursor-pointer', d.IsDeleted ? 'bg-danger-bg/50 hover:bg-danger-bg/70' : '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, restore, setDeleteTarget })}
                                        </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}
            />

            {deleteTarget && (
                <div className="fixed inset-0 z-100 grid place-items-center bg-black/40 p-4" role="dialog" aria-modal="true" onClick={() => setDeleteTarget(null)}>
                    <div className={`${CARD} w-full max-w-sm p-0`} onClick={(e) => e.stopPropagation()}>
                        <header className="flex items-center gap-2.5 border-b border-border px-5 py-4">
                            <span className="inline-grid size-6 shrink-0 place-items-center rounded-full border border-danger/50 text-danger-text" aria-hidden="true"><Trash2 className="size-3.5" /></span>
                            <h2 className="m-0 text-sm font-bold text-card-foreground">Delete Document</h2>
                            <button type="button" onClick={() => setDeleteTarget(null)} className="ml-auto grid size-7 place-items-center rounded-lg text-muted-foreground hover:bg-secondary hover:text-foreground" aria-label="Close">
                                <X className="size-4" />
                            </button>
                        </header>
                        <div className="px-5 py-4 text-[13px] text-foreground">
                            Hapus dokumen <span className="font-bold">{deleteTarget.name}</span>? Data akan disembunyikan (soft delete) dan bisa dipulihkan lewat filter IsDeleted.
                        </div>
                        <footer className="flex items-center justify-start gap-2.5 border-t border-border px-5 py-3.5">
                            <button type="button" onClick={() => setDeleteTarget(null)}
                                className="inline-flex h-9 items-center justify-center rounded-lg border border-input bg-card px-4 text-xs font-bold text-foreground transition-colors hover:border-primary hover:text-primary">Cancel</button>
                            <button type="button" onClick={confirmDelete}
                                className="inline-flex h-9 items-center justify-center gap-1.5 rounded-lg bg-danger px-4 text-xs font-bold text-white shadow-sm transition-[filter] hover:brightness-105">
                                <Trash2 className="size-3.5" /> Delete
                            </button>
                        </footer>
                    </div>
                </div>
            )}
        </section>
    );
}

Index.layout = [AppLayout];
