import { useEffect, useMemo, useRef, useState } from 'react';
import { router } from '@inertiajs/react';
import { AlertTriangle, Calendar, Gauge, RotateCcw, Search } from 'lucide-react';
import AppLayout from '@/Layouts/AppLayout';
import { ListFooter } from '@/Components/Table/ListFooter';
import { CreateActionButton } from '@/Components/Table/CreateActionButton';
import { FilterPill } from '@/Components/ui/filter-pill';
import { DateText, splitDateTime } from '@/Components/Proto/UI/DateText';
import { useServerSort, SortButton } from '@/lib/ServerSort';
import { useColumnPrefs } from '@/lib/useColumnPrefs';
import { useResizableColumns, ColumnResizeGrip } from '@/lib/useResizableColumns';
import { cn } from '@/lib/utils';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/Components/ui/tooltip';

// ─────────────────────────────────────────────────────────────────────────────
// Stock Sample overview (legacy listbarangs.php, menu 22). Master-detail: a
// server-paginated per-barang list on the left, the selected barang's stock lots
// on the right. Rendered from StockSampleController@overview:
//   Inertia::render('MenuStockSample/StockSamples/Index', { items, filters, options })
// Selection is client-side within the current page (resets to the first row on
// page/filter change). Legacy's multi-select category (productcategory HAVING) is
// simplified to a single-select category here — see GH follow-up.
// ─────────────────────────────────────────────────────────────────────────────

const EMPTY_PAGINATOR = { data: [], current_page: 1, last_page: 1, per_page: 10, from: 0, to: 0, total: 0 };

// Columns the SERVER can order by — mirrors StockSampleController::OVERVIEW_SORT_COLUMNS.
// A column not listed here renders a plain label instead of a dead sort button: `masuk` is
// derived AFTER pagination (last incoming date across a barang's lots), so it has no column
// to order by. Sorting it client-side would only reorder the ten rows on screen while the
// arrow implied the whole table.
const SORTABLE = new Set(['principal', 'name', 'stock']);

// Data-driven columns (default order left→right) + default widths for the table-fixed
// layout. Headers are drag-to-reorder; the row-number "No" column stays pinned.
const COLUMN_DEFS = [
    { id: 'no', label: 'No' },
    { id: 'principal', label: 'Principal Name' },
    { id: 'name', label: 'Nama Barang', required: true }, // row anchor
    { id: 'stock', label: 'Total Stock' },
    { id: 'masuk', label: 'Tanggal Masuk' },
];
// At 1600px the left pane fits ~695px in total. Nama Barang keeps only what the longest
// product name needs — the rest goes to Principal and the date, NOT between the name and
// its own stock figure.
const COL_W = { no: 42, principal: 168, name: 212, stock: 120, masuk: 150 };
const RIGHT_COLS = new Set(['no']);
const TD_CLASS = { no: 'text-right tabular-nums text-muted-foreground', principal: 'font-semibold', masuk: 'whitespace-nowrap tabular-nums text-muted-foreground' };

// Per-column cell renderer — markup identical to the previous hardcoded <td>s.
function renderCell(item, colId, ctx) {
    switch (colId) {
        case 'no': return ctx.rowNumber;
        case 'principal': return item.principal || '—';
        case 'name': return item.name;
        case 'stock': return <StockCell item={item} />;
        case 'masuk': return item.lastMasuk ? <DateText value={item.lastMasuk} /> : '—';
        default: return null;
    }
}

function fmtStock(val, unit) {
    const n = new Intl.NumberFormat('en-US').format(Number(val) || 0);
    return unit ? `${n} ${unit}` : n;
}
function lotNote(note) {
    const t = (note || '').trim();
    return t && t !== '—' && t !== '-' ? t : null;
}
const STOCK_PILL_BASE = 'inline-flex items-center gap-1 whitespace-nowrap rounded-full px-2.5 py-1 text-[11px] font-bold';

/**
 * Stock alert. `stockStatus` comes from the server (StockSampleController::stockStatus);
 * '' = no minimum configured and stock is not empty → nothing to alert about.
 *
 * There is no Status COLUMN any more (user decision 2026-08-20): a whole column repeating a
 * verdict the number already implies cost 112px on every row, including the majority that
 * are fine. The verdict now rides ON the number — same colour, same icon — plus a rail down
 * the left edge of the row so a problem row is findable without reading any cell.
 *
 * ⚠️ The ICON is not decoration and must not be dropped in favour of "just make it red":
 * `.claude/rules/design-system.md` requires status to be icon + colour, never colour alone
 * (colour-blind readers, and printed/greyscale screenshots).
 */
const STATUS_TONE = {
    out: { label: 'Out of stock', cls: 'bg-danger-bg text-danger-text', rail: 'var(--color-danger)', Icon: AlertTriangle },
    low: { label: 'Below minimum', cls: 'bg-warning-bg text-warning-text', rail: 'var(--color-warning)', Icon: AlertTriangle },
    ok: { label: 'Safe', cls: 'bg-accent text-primary', rail: null, Icon: null },
};

function StockCell({ item }) {
    const tone = STATUS_TONE[item.stockStatus];
    const Icon = tone?.Icon;
    const hint = Icon ? tone.label : null;
    const minText = item.minQty ? `Minimum stock: ${fmtStock(item.minQty, item.unit)}` : 'No minimum stock configured';

    const pill = (
        <span className={cn(STOCK_PILL_BASE, tone?.cls ?? 'bg-accent text-primary', hint && 'cursor-help')}>
            {Icon && <Icon className="size-3 shrink-0" strokeWidth={2.4} aria-hidden="true" />}
            {fmtStock(item.totalStock, item.unit)}
            {/* Screen readers get the verdict in words; sighted users get icon + colour, and
                spelling it out in the cell is exactly what made the old column redundant. */}
            {hint && <span className="sr-only">{hint}</span>}
        </span>
    );

    return (
        <Tooltip>
            <TooltipTrigger asChild>{pill}</TooltipTrigger>
            <TooltipContent side="top">
                {hint ? <><span className="font-semibold">{hint}</span>{' · '}{minText}</> : minText}
            </TooltipContent>
        </Tooltip>
    );
}

/** Inset shadow, not border-left: a real border would eat into the `table-fixed` width. */
function rowRailStyle(status) {
    const rail = STATUS_TONE[status]?.rail;
    return rail ? { boxShadow: `inset 3px 0 0 0 ${rail}` } : undefined;
}
const STAT_MINI = 'flex min-w-0 items-center gap-2 [&_small]:mb-px [&_small]:block [&_small]:text-[10px] [&_small]:font-bold [&_small]:tracking-[0.02em] [&_small]:text-muted-foreground [&_strong]:block [&_strong]:whitespace-nowrap [&_strong]:text-sm [&_strong]:font-extrabold [&_strong]:leading-[1.1] [&_strong]:text-card-foreground';
const STAT_ICON = 'inline-grid size-7 shrink-0 place-items-center rounded-md bg-secondary text-[11px] font-extrabold text-muted-foreground';

export default function StockSampleIndex({ items = EMPTY_PAGINATOR, filters = {}, options = {}, canCreate = false }) {
    // Rows come back already ordered by the DATABASE — the sort wiring is below, next to
    // go(), because useServerSort needs it. Never re-sort here: that would reorder only
    // this page.
    const rows = items.data ?? [];
    const { widthOf, startResize, resizingId, resizeRef } = useResizableColumns(COL_W);
    // Column order — persisted; direct header drag-to-reorder ("No" pinned via fixedIds).
    const prefs = useColumnPrefs('stockSampleOverviewColumns_v1', COLUMN_DEFS, { resizeGuardRef: resizeRef, fixedIds: ['no'] });
    const tableWidth = useMemo(() => prefs.visibleCols.reduce((sum, c) => sum + widthOf(c.id), 0), [prefs.visibleCols, widthOf]);
    const pageSize = filters.per_page || 10;
    const currentPage = items.current_page;
    const totalPages = items.last_page;

    const [quickQuery, setQuickQuery] = useState(filters.search || '');
    const [selectedId, setSelectedId] = useState(rows[0]?.id ?? null);
    const searchDebounce = useRef(null);

    // Principal/Category are multi. The wire value is the comma-joined id string multiIds()
    // parses server-side; FilterPill wants an array, so the two are converted at this edge
    // and nowhere else. Ids are numeric here, so no name can ever carry a comma into it.
    const asList = (v) => String(v ?? '').split(',').filter(Boolean);
    const principalSel = useMemo(() => asList(filters.principal), [filters.principal]);
    const categorySel = useMemo(() => asList(filters.category), [filters.category]);

    // Keep the selection valid for the current page.
    useEffect(() => {
        if (!rows.some((r) => r.id === selectedId)) setSelectedId(rows[0]?.id ?? null);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [items]);

    const buildParams = (overrides = {}) => {
        const params = {};
        const search = overrides.search ?? quickQuery;
        if (search) params.search = search;
        ['principal', 'category', 'name'].forEach((k) => {
            const v = overrides[k] ?? filters[k] ?? '';
            if (v) params[k] = v;
        });
        const perPage = overrides.per_page ?? pageSize;
        if (perPage && Number(perPage) !== 10) params.per_page = perPage;
        const page = overrides.page ?? currentPage;
        if (page && Number(page) !== 1) params.page = page;
        // Sort has to survive a filter/page change like every other control, and it is read
        // from `filters` (never local state) so the arrow cannot drift from what the server
        // actually ordered by. Defaults are dropped to keep the URL clean.
        const sort = overrides.sort ?? filters.sort;
        const dir = overrides.dir ?? filters.dir;
        if (sort && sort !== 'principal') params.sort = sort;
        if (dir && dir !== 'asc') params.dir = dir;
        return params;
    };
    // only: — without it the server still evaluates the `options` closure on every
    // keystroke and page click. The paginator prop here is `items`, not `rows`; a wrong
    // name fails SILENTLY (preserveState keeps the old rows on screen).
    const go = (overrides) => router.get(route('stock-samples.index'), buildParams(overrides), {
        only: ['items', 'filters'],
        preserveState: true, preserveScroll: true, replace: true,
    });
    const { sortKey, sortDir, toggleSort } = useServerSort(filters, go);
    const onSearchChange = (v) => {
        setQuickQuery(v);
        clearTimeout(searchDebounce.current);
        searchDebounce.current = setTimeout(() => go({ search: v, page: 1 }), 300);
    };
    const setFilter = (key, ids) => go({ [key]: ids.join(','), page: 1 });
    const anyFilter = Boolean(quickQuery || filters.principal || filters.category);
    const clearFilters = () => {
        setQuickQuery('');
        go({ search: '', principal: '', category: '', name: '', page: 1 });
    };

    const selected = useMemo(() => rows.find((r) => r.id === selectedId) || null, [rows, selectedId]);
    // Server-computed (`lastMasuk`): the max runs over EVERY lot, including the used-up ones
    // that never reach `selected.lots` (that list is filtered to qty > 0).
    const lastRestock = selected?.lastMasuk || '';

    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>Stock Sample</span>
                    <span aria-hidden="true">›</span>
                    <span className="text-foreground">Overview</span>
                </p>
                <div className="flex items-start justify-between gap-4">
                    <h1 className="m-0 text-2xl font-bold leading-[1.15] tracking-tight text-card-foreground">Stock Sample</h1>
                    <CreateActionButton canCreate={canCreate} label="Insert Sample" href={route('stock-samples.create')} />
                </div>
            </header>

            <div className="grid items-start gap-5 [grid-template-columns:minmax(280px,1.3fr)_minmax(420px,1fr)] max-[1180px]:grid-cols-1">
                <article className="overflow-hidden rounded-xl border border-border bg-card shadow-sm">
                    <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 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" placeholder="Search product, code, principal…" autoComplete="off"
                                value={quickQuery} onChange={(e) => onSearchChange(e.target.value)}
                                className="min-w-0 flex-1 bg-transparent text-[12.5px] font-medium text-foreground outline-none placeholder:text-muted-foreground/70" />
                        </label>
                        <FilterPill label="Principal" value={principalSel} options={options.principals || []}
                            onChange={(v) => setFilter('principal', v)} />
                        <FilterPill label="Category" value={categorySel} options={options.categories || []}
                            onChange={(v) => setFilter('category', v)} />
                        {anyFilter && (
                            <button type="button" onClick={clearFilters}
                                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>
                    <TooltipProvider>
                    <div className="overflow-x-auto">
                        <table style={{ minWidth: tableWidth }} className="w-full table-fixed border-separate border-spacing-0 [&_thead_th]:whitespace-nowrap [&_thead_th]:bg-secondary/40 [&_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 [&_tbody_td]:overflow-hidden [&_tbody_td]:border-b [&_tbody_td]:border-border/60 [&_tbody_td]:px-4 [&_tbody_td]:py-[16px] [&_tbody_td]:text-[12px] [&_tbody_td]:text-card-foreground [&_tbody_tr]:cursor-pointer [&_tbody_tr:hover]:bg-secondary/60">
                            <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={cn('group/col relative', RIGHT_COLS.has(col.id) && '!text-right', 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-7 text-center italic text-muted-foreground">No items match the current filters.</td></tr>
                                ) : rows.map((item, idx) => (
                                    <tr key={item.id} className={item.id === selectedId ? 'bg-secondary' : ''} onClick={() => setSelectedId(item.id)}>
                                        {prefs.visibleCols.map((col, colIdx) => (
                                            <td key={col.id} className={TD_CLASS[col.id]}
                                                style={colIdx === 0 ? rowRailStyle(item.stockStatus) : undefined}>
                                                {renderCell(item, col.id, { rowNumber: (items.from || 0) + idx })}
                                            </td>
                                        ))}
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>
                    </TooltipProvider>
                    <ListFooter
                        page={currentPage} totalPages={totalPages} onPage={(p) => go({ page: p })}
                        pageSize={Number(pageSize)} onPageSize={(n) => go({ per_page: n, page: 1 })} pageSizeOptions={[10, 25, 50, 100]}
                        total={items.total} itemLabel="items" />
                </article>

                <article className="flex flex-col overflow-hidden rounded-xl border border-border bg-card shadow-sm">
                    <header className="border-b border-border px-6 pb-5 pt-5.5">
                        <small className="m-0 mb-1.5 block text-[10px] font-extrabold uppercase tracking-[0.06em] text-muted-foreground">Principal / Item</small>
                        <h2 className="m-0 mb-4 text-lg font-extrabold leading-[1.3] tracking-[-0.01em] text-card-foreground">{selected ? `${selected.principal || '—'} / ${selected.name}` : '—'}</h2>
                        {/* Min. Stock sits beside Total Stock on purpose — the Status badge in the
                            list is a verdict, and this is the number that verdict is measured against. */}
                        <div className="grid grid-cols-4 gap-0 pt-3 [&>div+div]:border-l [&>div+div]:border-border">
                            <div className={cn(STAT_MINI, 'pl-0 pr-2.5')}>
                                <span className={STAT_ICON} aria-hidden="true">Σ</span>
                                <div><small>Total Stock</small><strong>{selected ? fmtStock(selected.totalStock, selected.unit) : '—'}</strong></div>
                            </div>
                            <div className={cn(STAT_MINI, 'px-2.5')}>
                                <span className={STAT_ICON} aria-hidden="true"><Gauge className="size-3.5" strokeWidth={2.2} /></span>
                                <div>
                                    <small>Min. Stock</small>
                                    <strong className={cn(selected?.stockStatus === 'low' && '!text-danger-text')}>
                                        {selected?.minQty ? fmtStock(selected.minQty, selected.unit) : '—'}
                                    </strong>
                                </div>
                            </div>
                            <div className={cn(STAT_MINI, 'px-2.5')}>
                                <span className={STAT_ICON} aria-hidden="true">#</span>
                                <div><small># of Lots</small><strong>{selected ? (selected.lots?.length || 0) : '—'}</strong></div>
                            </div>
                            <div className={cn(STAT_MINI, 'pl-2.5 pr-0')}>
                                <span className={STAT_ICON} aria-hidden="true"><Calendar className="size-3.5" strokeWidth={2.2} /></span>
                                {/* Date only — the full timestamp does not fit once this row holds four
                                    stats, and every lot's exact time is in the table below anyway. */}
                                <div><small>Last Restock</small><strong title={lastRestock}>{lastRestock ? splitDateTime(lastRestock).date : '—'}</strong></div>
                            </div>
                        </div>
                    </header>
                    <div className="flex min-h-0 flex-1 flex-col items-stretch gap-3.5 px-6 py-5.5">
                        <h3 className="m-0 text-[13px] font-bold tracking-[-0.005em] text-card-foreground">List Lot / Stock</h3>
                        <div className="max-h-[360px] min-h-0 shrink overflow-auto rounded-xl border border-border">
                            <table className="w-full table-fixed border-collapse [&_thead_th]:sticky [&_thead_th]:top-0 [&_thead_th]:border-b [&_thead_th]:border-border [&_thead_th]:bg-card [&_thead_th]:px-3.5 [&_thead_th]:py-2.5 [&_thead_th]:text-left [&_thead_th]:text-[10px] [&_thead_th]:font-extrabold [&_thead_th]:uppercase [&_thead_th]:tracking-[0.04em] [&_thead_th]:text-muted-foreground [&_tbody_td]:border-b [&_tbody_td]:border-border [&_tbody_td]:p-3 [&_tbody_td]:text-xs [&_tbody_td]:text-card-foreground [&_tbody_tr:last-child_td]:border-b-0">
                                <thead>
                                    <tr><th className="w-[28%]">Lot Number</th><th className="w-[16%]">Stock</th><th className="w-[28%]">Tanggal Masuk</th><th className="w-[28%]">Keterangan</th></tr>
                                </thead>
                                <tbody>
                                    {selected && (selected.lots?.length || 0) > 0 ? selected.lots.map((l, i) => (
                                        <tr key={i}>
                                            <td className="font-bold text-foreground">{l.lot || '—'}</td>
                                            <td className="font-bold">{fmtStock(l.stock, l.satuan)}</td>
                                            <td>{l.masuk ? <DateText value={l.masuk} /> : <span className="text-muted-foreground">—</span>}</td>
                                            <td className="text-muted-foreground">{lotNote(l.note) || 'NA'}</td>
                                        </tr>
                                    )) : (<tr><td colSpan={4} className="px-4 py-7 text-center italic text-muted-foreground">No lots available.</td></tr>)}
                                </tbody>
                            </table>
                        </div>
                    </div>
                </article>
            </div>
        </section>
    );
}

StockSampleIndex.layout = [AppLayout];
