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


/* ------------------------------------------------------------
   AdeptPowersSection — used by adepts (full magic view) and mystic
   adepts (embedded under spells). When `embedded` is true we skip
   the top-level header.
   ------------------------------------------------------------ */
window.AdeptPowersSection = function AdeptPowersSection({ character, onChange, embedded }) {
    const C = SR5_CALC;
    const M = SR5_MAGIC;
    const [pickerOpen, setPickerOpen] = useState(false);
    const [customOpen, setCustomOpen] = useState(false);
    const [tagFilter, setTagFilter] = useState(null);

    const inCareer = C.isCareerMode(character);
    const pendingCh = inCareer ? C.pendingChanges(character) : {};
    const pendingNewPowers = pendingCh.newAdeptPowers || [];

    /* In career mode, use projected PP so pending Magic raises and pending PP buys
       show up in the meter and the picker's PP-affordability gates. */
    const ppTotal = inCareer ? C.powerPointsTotalProjected(character) : C.powerPointsTotal(character);
    const ppSpent = inCareer ? C.powerPointsSpentProjected(character) : C.powerPointsSpent(character);
    const ppRemaining = inCareer ? C.powerPointsRemainingProjected(character) : C.powerPointsRemaining(character);
    const powers = C.characterAdeptPowers(character);
    const ppPct = ppTotal > 0 ? Math.min(100, (ppSpent / ppTotal) * 100) : 0;
    const ppState = ppRemaining < 0 ? 'over' : (ppRemaining === 0 ? 'done' : '');

    function handlePick(template, extras) {
        if (inCareer) {
            /* PP-gated, not karma. Check affordability in PP. */
            const level = template.costPerLevel
                ? Math.max(1, Math.min(template.maxLevels || 6, (extras || {}).level || 1))
                : undefined;
            const ppCost = M.powerPPCost(template, level);
            if (ppCost > ppRemaining) {
                alert(`Not enough Power Points: this power costs ${ppCost} PP, you have ${ppRemaining.toFixed(2)} remaining${pendingCh.newPowerPoints ? ' (including pending PP buys)' : ''}.`);
                return;
            }
            onChange(C.stagePendingNewAdeptPower(character, template, extras));
            setPickerOpen(false);
        } else {
            onChange(C.addAdeptPowerFromTemplate(character, template, extras));
            setPickerOpen(false);
        }
    }
    function handleRemove(id) {
        if (inCareer) {
            alert("Adept powers can't be removed in career mode.");
            return;
        }
        onChange(C.removeAdeptPower(character, id));
    }
    function handleUnstagePendingPower(tempId) {
        onChange(C.unstagePendingNewAdeptPower(character, tempId));
    }
    function handleUpdateLevel(id, level) {
        if (inCareer) return;
        onChange(C.updateAdeptPower(character, id, { level }));
    }
    function handleUpdateNotes(id, notes) {
        if (inCareer) return;
        onChange(C.updateAdeptPower(character, id, { notes }));
    }
    function handleUpdateSelection(id, selection) {
        if (inCareer) return;
        onChange(C.updateAdeptPower(character, id, { selection }));
    }

    function renderPendingPowerRow(pp) {
        const tpl = M.findAdeptPower(pp.key);
        return (
            <div className="power-row pending-new" key={pp.tempId}>
                <div className="pwr-name">
                    {pp.name}
                    <span style={{ marginLeft: 8, fontSize: 10, letterSpacing: '0.1em', color: 'var(--accent)' }}>
                        — pending ({pp.ppCost} PP)
                    </span>
                    {pp.selection && <span className="pwr-selection">({pp.selection})</span>}
                    {tpl?.description && <div className="pwr-desc">{tpl.description}</div>}
                </div>
                <div className="pwr-act">{tpl?.activation || '—'}</div>
                <div className="pwr-pp accent">{pp.ppCost}</div>
                <div className="pwr-selection-display">{pp.selection || '—'}</div>
                <div className="pwr-level-display">{pp.level || '—'}</div>
                <button className="knowledge-remove-btn"
                        onClick={() => handleUnstagePendingPower(pp.tempId)}
                        title="Discard this pending power">×</button>
            </div>
        );
    }

    function renderPowerRow(p) {
        const tpl = p.key ? M.findAdeptPower(p.key) : null;
        const isRated = tpl?.costPerLevel;
        const sourceClass = (tpl?.source || '').toLowerCase().includes('crb') ? 'crb'
                          : (tpl?.source || '').toLowerCase().includes('grimoire') ? 'sg' : '';
        return (
            <div className="power-row" key={p.id}>
                <div className="pwr-name">
                    {p.name}
                    {p.selection && <span className="pwr-selection">({p.selection})</span>}
                    {tpl?.source && <span className={`power-source-pill ${sourceClass}`}>{abbreviateSource(tpl.source)}</span>}
                    {tpl?.description && <div className="pwr-desc">{tpl.description}</div>}
                    <div className="pwr-meta-row">
                        {tpl?.activation && tpl.activation !== '—' ? `${tpl.activation} · ` : ''}
                        {tpl?.duration || ''}
                        {tpl?.prerequisite && (
                            <> · requires {M.findAdeptPower(tpl.prerequisite)?.name || tpl.prerequisite}</>
                        )}
                    </div>
                </div>
                <div className="pwr-stat">{tpl?.activation || '—'}</div>
                <div className="pwr-stat pp">{(p.ppCost || 0).toFixed(2)}</div>
                <div className="pwr-stat">
                    {p.selection ? (
                        <input type="text" value={p.selection || ''}
                               onChange={e => handleUpdateSelection(p.id, e.target.value)}
                               style={{ width: '100%', padding: '4px 6px', background: 'var(--bg-base)',
                                        border: '1px solid var(--border-subtle)', color: 'var(--text-primary)',
                                        fontFamily: 'var(--font-sans)', fontSize: 11, borderRadius: 2 }}
                               placeholder="selection…" />
                    ) : tpl?.requiresSelection ? (
                        <span className="muted mono" style={{ fontSize: 10 }}>—</span>
                    ) : (
                        <span className="muted">—</span>
                    )}
                </div>
                <div className="pwr-level">
                    {isRated ? (
                        <>
                            <button className="stepper-btn" style={{ width: 20, height: 20, fontSize: 12 }}
                                    onClick={() => handleUpdateLevel(p.id, Math.max(1, (p.level || 1) - 1))}
                                    disabled={(p.level || 1) <= 1}>−</button>
                            <span style={{ minWidth: 16, textAlign: 'center', fontFamily: 'var(--font-mono)' }}>{p.level || 1}</span>
                            <button className="stepper-btn" style={{ width: 20, height: 20, fontSize: 12 }}
                                    onClick={() => handleUpdateLevel(p.id, Math.min(tpl.maxLevels || 6, (p.level || 1) + 1))}>+</button>
                        </>
                    ) : (
                        <span className="muted mono" style={{ fontSize: 11 }}>—</span>
                    )}
                </div>
                <button className="knowledge-remove-btn"
                        onClick={() => { if (confirm(`Remove ${p.name}?`)) handleRemove(p.id); }}
                        title="Remove">×</button>
            </div>
        );
    }

    return (
        <>
            {/* PP meter */}
            {ppTotal > 0 ? (
                <div className="pp-meter">
                    <div className="pp-big">
                        <span className="pp-label">Power Points</span>
                        <span className={`pp-value ${ppState}`}>
                            {ppSpent.toFixed(2)}
                            <span className="pp-max"> / {ppTotal.toFixed(2)}</span>
                        </span>
                    </div>
                    <div className="essence-bar-wrap">
                        <div className="essence-bar-labels">
                            <span>spent: {ppSpent.toFixed(2)}</span>
                            <span>{ppRemaining < 0 ? `over by ${Math.abs(ppRemaining).toFixed(2)}` : `remaining: ${ppRemaining.toFixed(2)}`}</span>
                        </div>
                        <div className="pp-bar">
                            <div className={`pp-bar-fill ${ppState}`} style={{ width: `${ppPct}%` }} />
                        </div>
                    </div>
                    <div className="essence-magic">
                        <div className="em-label">Powers</div>
                        <div className="em-value">{powers.length}</div>
                    </div>
                </div>
            ) : (
                <div className="adept-empty">
                    No Power Points available. Mystic Adepts: use the split slider above to allocate Magic toward powers instead of spells.
                </div>
            )}

            {/* Power table */}
            {(powers.length > 0 || pendingNewPowers.length > 0) ? (
                <div className="power-table">
                    <div className="power-table-head">
                        <div>Power</div>
                        <div style={{ textAlign: 'center' }}>Activation</div>
                        <div style={{ textAlign: 'center' }}>PP</div>
                        <div style={{ textAlign: 'center' }}>Selection</div>
                        <div style={{ textAlign: 'center' }}>Level</div>
                        <div></div>
                    </div>
                    {powers.map(renderPowerRow)}
                    {pendingNewPowers.map(renderPendingPowerRow)}
                </div>
            ) : ppTotal > 0 ? (
                <div className="adept-empty">no powers yet — browse the catalog or add a custom power</div>
            ) : null}

            {ppTotal > 0 && (
                <div className="gear-add-bar">
                    <button className="add-button" onClick={() => setPickerOpen(true)}>
                        <span className="plus-icon">+</span>Browse Adept Powers {inCareer ? '(PP-gated)' : ''}
                    </button>
                    {!inCareer && (
                        <button className="add-button" onClick={() => setCustomOpen(true)}>
                            <span className="plus-icon">+</span>Custom Power
                        </button>
                    )}
                </div>
            )}

            {pickerOpen && (
                <AdeptPowerPickerModal
                    character={character}
                    onPick={handlePick}
                    onClose={() => setPickerOpen(false)}
                />
            )}

            {customOpen && (
                <CustomAdeptPowerDialog
                    onSubmit={payload => {
                        onChange(C.addCustomAdeptPower(character, payload));
                        setCustomOpen(false);
                    }}
                    onClose={() => setCustomOpen(false)}
                />
            )}

            {!embedded && (
                <div className="phase-note" style={{ marginTop: 20 }}>
                    <strong>Phase 5b.</strong> Full Core Rulebook adept power list (~35 powers) plus selected Street Grimoire additions (Berserk, Cool Resolve, Counterstrike, Riposte, Smashing Blow, Nerve Strike, etc).
                    Each power shows source — CRB (gold), SG (purple). Rated powers have inline level steppers; powers needing a selection (skill/attribute/sense) prompt for it during purchase.
                    Custom powers cover anything not in the catalog.
                </div>
            )}
        </>
    );
};


/* Helper for source pill abbreviation */
window.abbreviateSource = function abbreviateSource(src) {
    if (!src) return '';
    if (src.includes('CRB')) return 'CRB';
    if (src.includes('Grimoire')) return 'SG';
    if (src.includes('Spells')) return 'SS';
    if (src.includes('Bandages')) return 'BB';
    return src.slice(0, 4).toUpperCase();
}
