/* ============================================================
   Primitives — Entity Picker
   Extracted from components.jsx via split.py.
   Each component reaches React hooks via window.React.
   ============================================================ */
const { useState, useEffect, useRef, useMemo, useCallback, Fragment } = React;


/* ============================================================
   EntityPicker — generic "browse a catalog and pick one" modal.
   ============================================================
   
   Used across gear tabs (weapons, armor, cyberware, bioware,
   electronics, security, medical, misc), magic (spells, adept
   powers, complex forms), and qualities. The core idea: given
   a catalog array, render a searchable/filterable list on the
   left and a detail view on the right; user selects one and
   hits Enter (or clicks Pick).
   
   API contract — every prop's role:
   
     title          string
                    Modal header. e.g. "Browse Weapons".
   
     items          Array<Template>
                    The catalog array. Any shape — template objects
                    just need whatever renderers/filterBy expects.
   
     getItemKey     (item) => string
                    Returns a stable unique id per item. Used for
                    React keys and to track the selected item.
                    For SR5 templates this is almost always item.key.
   
     filterBy       (item, query, activeFilter) => boolean
                    Should this item show given the current search
                    query and active filter chip? Called for every
                    item on every keystroke. Keep it cheap.
   
     filters        Array<{key: string, label: string}>  (optional)
                    Filter chip definitions. Renders as a row of
                    buttons above the list. The activeFilter passed
                    to filterBy is either the chip's key or null.
   
     itemRenderer   (item, {selected, onClick}) => ReactNode
                    How to render each item in the left-rail list.
                    Must spread onClick on the outer element. The
                    'selected' boolean indicates the currently-
                    highlighted item (for styling).
   
     renderDetails  (item) => ReactNode
                    How to render the right-hand detail panel for
                    the currently-selected item.
   
     isAlreadyTaken (item) => boolean                     (optional)
                    If true, the item renders in the "dimmed/owned"
                    style, signaling the user already has this one.
                    Does not prevent picking — just visual hint.
   
     onPick         (item) => void
                    Called when the user confirms selection (Enter,
                    click Pick button, etc.).
   
     onClose        () => void
                    Called on cancel, Escape, backdrop click, or
                    after a successful onPick.
   
   Common failure mode: passing `itemKey` / `detailsRenderer` /
   `searchFields` / `filterChips` — all of which are NOT what this
   picker expects. Runtime checks below throw loudly in that case.
   ============================================================ */
window.EntityPicker = function EntityPicker({
    title,
    items,
    getItemKey,
    renderDetails,
    filterBy,
    filters,
    onPick,
    onClose,
    isAlreadyTaken,
    isBlocked,
    blockedReason,
    itemRenderer,
}) {
    /* Required-prop runtime validation. Fails loudly instead of
       rendering a broken picker silently. Production React typically
       strips these; we don't have a build step, so they always run
       but the cost is trivial compared to the bug they prevent. */
    if (!Array.isArray(items)) {
        throw new Error(`EntityPicker(title="${title}"): 'items' must be an array, got ${typeof items}. Did you mean to pass a catalog like SR5_GEAR.WEAPONS?`);
    }
    if (typeof getItemKey !== 'function') {
        throw new Error(`EntityPicker(title="${title}"): 'getItemKey' must be a function (item) => string. Did you pass 'itemKey' by mistake?`);
    }
    if (typeof itemRenderer !== 'function') {
        throw new Error(`EntityPicker(title="${title}"): 'itemRenderer' must be a function (item, {selected, onClick}) => ReactNode.`);
    }
    if (typeof renderDetails !== 'function') {
        throw new Error(`EntityPicker(title="${title}"): 'renderDetails' must be a function (item) => ReactNode. Did you pass 'detailsRenderer' by mistake?`);
    }
    if (typeof filterBy !== 'function') {
        throw new Error(`EntityPicker(title="${title}"): 'filterBy' must be a function (item, query, activeFilter) => boolean.`);
    }
    if (typeof onPick !== 'function') {
        throw new Error(`EntityPicker(title="${title}"): 'onPick' must be a function (item) => void.`);
    }
    if (typeof onClose !== 'function') {
        throw new Error(`EntityPicker(title="${title}"): 'onClose' must be a function () => void.`);
    }

    const [query, setQuery] = useState('');
    const [activeFilter, setActiveFilter] = useState(null);
    const [selectedKey, setSelectedKey] = useState(null);
    const [extras, setExtras] = useState({});
    const searchRef = useRef(null);

    /* Focus the search box on open, and handle slash-to-focus. */
    useEffect(() => {
        searchRef.current?.focus();
        function onKey(e) {
            if (e.key === '/' && document.activeElement !== searchRef.current) {
                e.preventDefault();
                searchRef.current?.focus();
            }
        }
        window.addEventListener('keydown', onKey);
        return () => window.removeEventListener('keydown', onKey);
    }, []);

    /* Filter and search */
    const filtered = useMemo(() => {
        const q = query.trim().toLowerCase();
        return items.filter(item => {
            if (filterBy) {
                if (!filterBy(item, q, activeFilter)) return false;
            } else if (q) {
                const name = (item.name || item.label || '').toLowerCase();
                if (!name.includes(q)) return false;
            }
            return true;
        });
    }, [items, query, activeFilter, filterBy]);

    const selected = items.find(i => getItemKey(i) === selectedKey);
    const alreadyTaken = selected && isAlreadyTaken ? isAlreadyTaken(selected) : false;
    const blocked = selected && isBlocked ? isBlocked(selected) : false;
    const canPick = selected && !alreadyTaken && !blocked;

    function doPick() {
        if (!canPick) return;
        onPick(selected, extras);
    }

    /* Keyboard navigation */
    useEffect(() => {
        function onKey(e) {
            if (filtered.length === 0) return;
            const idx = filtered.findIndex(i => getItemKey(i) === selectedKey);
            if (e.key === 'ArrowDown') {
                e.preventDefault();
                const next = idx < 0 ? 0 : Math.min(filtered.length - 1, idx + 1);
                setSelectedKey(getItemKey(filtered[next]));
                setExtras({});
            } else if (e.key === 'ArrowUp') {
                e.preventDefault();
                const next = idx <= 0 ? 0 : idx - 1;
                setSelectedKey(getItemKey(filtered[next]));
                setExtras({});
            } else if (e.key === 'Enter' && selected && canPick) {
                if (document.activeElement?.tagName === 'INPUT' &&
                    document.activeElement !== searchRef.current) return;
                e.preventDefault();
                doPick();
            }
        }
        window.addEventListener('keydown', onKey);
        return () => window.removeEventListener('keydown', onKey);
        // eslint-disable-next-line
    }, [filtered, selectedKey, selected, canPick, extras]);

    function handleItemClick(item) {
        if (isAlreadyTaken && isAlreadyTaken(item)) return;
        if (isBlocked && isBlocked(item)) return;
        setSelectedKey(getItemKey(item));
        setExtras({});
    }

    function defaultRow(item) {
        const key = getItemKey(item);
        const taken = isAlreadyTaken ? isAlreadyTaken(item) : false;
        const blk = isBlocked ? isBlocked(item) : false;
        const isSel = selectedKey === key;
        if (itemRenderer) {
            return itemRenderer(item, {
                selected: isSel,
                alreadyTaken: taken,
                blocked: blk,
                onClick: () => handleItemClick(item)
            });
        }
        return null;
    }

    const footer = (
        <>
            <div className="footer-info">
                {filtered.length} {filtered.length === 1 ? 'result' : 'results'}
                {selected && alreadyTaken && <> · <span style={{ color: 'var(--warn)' }}>already added</span></>}
                {selected && blocked && (
                    <> · <span style={{ color: 'var(--bad)' }}>
                        {blockedReason ? blockedReason(selected) : 'not allowed'}
                    </span></>
                )}
            </div>
            <div className="footer-actions">
                <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
                <button className="btn btn-primary" onClick={doPick} disabled={!canPick}>Add</button>
            </div>
        </>
    );

    return (
        <Modal title={title} onClose={onClose} footer={footer}>
            <div className="picker-sidebar">
                <div className="picker-toolbar">
                    <input
                        ref={searchRef}
                        className="picker-search"
                        type="text"
                        value={query}
                        onChange={e => setQuery(e.target.value)}
                        placeholder="Search… (press / to focus)"
                    />
                    {filters && filters.length > 0 && (
                        <div className="picker-filters">
                            <div className={`filter-chip ${activeFilter === null ? 'active' : ''}`}
                                 onClick={() => setActiveFilter(null)}>All</div>
                            {filters.map(f => (
                                <div key={f.key}
                                     className={`filter-chip ${activeFilter === f.key ? 'active' : ''}`}
                                     onClick={() => setActiveFilter(activeFilter === f.key ? null : f.key)}>
                                    {f.label}
                                </div>
                            ))}
                        </div>
                    )}
                </div>
                <div className="picker-list">
                    {filtered.length === 0 ? (
                        <div className="picker-list-empty">no matches</div>
                    ) : (
                        filtered.map(defaultRow)
                    )}
                </div>
            </div>
            <div className="picker-details">
                {selected ? (
                    renderDetails(selected, { extras, setExtras })
                ) : (
                    <div className="picker-details-empty">
                        Select an item from the list to see details.
                        <br /><br />
                        <span className="faint">↑↓ navigate · Enter to add · Esc to close</span>
                    </div>
                )}
            </div>
        </Modal>
    );
};
