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


/* ------------------------------------------------------------
   QualitiesView — the main Phase 3 view.
   ------------------------------------------------------------ */
window.QualitiesView = function QualitiesView({ character, onChange }) {
    const C = SR5_CALC;
    const Q = SR5_QUALITIES;
    const inCareer = C.isCareerMode(character);
    const karmaAvailable = inCareer ? C.karmaCurrent(character) : 0;
    const pendingDelta = inCareer ? C.pendingKarmaDelta(character) : 0;
    const karmaRemaining = inCareer ? karmaAvailable - pendingDelta : 0;

    const [pickerOpen, setPickerOpen] = useState(null);  /* 'positive' | 'negative' | null */
    const [customOpen, setCustomOpen] = useState(null);

    const qualities = C.characterQualities(character);
    const positive = qualities.filter(q => q.type === 'positive');
    const negative = qualities.filter(q => q.type === 'negative');
    const { starting, positive: posSpent, negative: negGained, remaining } = C.karmaTotals(character);
    const posCap = C.qualityCapPositive(character);
    const negCap = C.qualityCapNegative(character);

    const posState = posSpent > posCap ? 'over-cap' : (posSpent === posCap ? 'at-cap' : '');
    const negState = negGained > negCap ? 'over-cap' : (negGained === negCap ? 'at-cap' : '');

    /* Pending layer — career mode only. */
    const pendingCh = inCareer ? C.pendingChanges(character) : {};
    const pendingNewQualities = pendingCh.newQualities || [];
    const pendingRemovedNegIds = new Set((pendingCh.removedNegativeQualities || []).map(r => r.qualityId));
    const pendingNewPos = pendingNewQualities.filter(q => q.type === 'positive');
    const pendingNewNeg = pendingNewQualities.filter(q => q.type === 'negative');

    const positiveTemplates = Q.POSITIVE.map(q => ({ ...q, type: 'positive' }));
    const negativeTemplates = Q.NEGATIVE.map(q => ({ ...q, type: 'negative' }));

    function isAlreadyTaken(template) {
        /* A template is "taken" if committed OR pending-new. */
        if (C.qualityHasKey(character, template.key)) return true;
        if (pendingNewQualities.some(q => q.key === template.key)) return true;
        return false;
    }

    function handlePick(template, extras) {
        /* Phase 19 — selection gate. Block if required but missing. */
        if (template.needsSelection && !extras.selection) {
            alert(`Please pick a ${template.needsSelection.kind === 'mentorSpirit' ? 'mentor spirit' : template.needsSelection.kind} before adding this quality.`);
            return;
        }
        if (inCareer) {
            /* Check karma before staging. */
            const ranks = template.karmaPerRank ? (extras.ranks || 1) : undefined;
            const listedKarma = template.karmaPerRank
                ? template.karmaPerRank * (ranks || 1)
                : template.karma;
            const willCost = listedKarma * 2;
            if (pendingDelta + willCost > karmaAvailable) {
                alert(`Not enough karma: this quality costs ${willCost} karma (listed × 2 in career), you have ${karmaRemaining} remaining.`);
                return;
            }
            onChange(C.stagePendingNewQuality(character, template, extras));
            setPickerOpen(null);
        } else {
            /* Creation: allow over-cap positives if the player has leftover karma.
               Per CRB p. 99, the 25-karma positive cap is the creation-step budget;
               after that, any additional positive karma comes out of Step 8
               leftover karma. Warn at the boundary. */
            const ranks = template.karmaPerRank ? (extras.ranks || 1) : undefined;
            const listedKarma = template.karmaPerRank
                ? template.karmaPerRank * (ranks || 1)
                : template.karma;
            if (template.type === 'positive') {
                const posAfter = posSpent + listedKarma;
                const overCapAfter = Math.max(0, posAfter - posCap);
                const overCapNow = Math.max(0, posSpent - posCap);
                const newOverCap = overCapAfter - overCapNow;
                if (newOverCap > 0 && remaining < newOverCap) {
                    alert(`Not enough leftover karma for this over-cap positive quality. Need ${newOverCap} karma from leftover pool, have ${remaining}.`);
                    return;
                }
                if (posAfter > posCap && posSpent <= posCap) {
                    if (!confirm(`Taking this quality will push your positive-quality spend over the 25-karma cap. The extra ${posAfter - posCap} karma will come out of your leftover karma pool. Proceed?`)) {
                        return;
                    }
                }
            }
            onChange(C.addQualityFromTemplate(character, template, extras));
            setPickerOpen(null);
        }
    }

    function handleRemove(id) {
        if (inCareer) {
            /* Buy-off path for negative qualities. Positive removal not allowed in career. */
            const q = qualities.find(qq => qq.id === id);
            if (!q) return;
            if (q.type !== 'negative') {
                alert("Positive qualities can't be removed in career mode.");
                return;
            }
            const willCost = q.karma * 2;
            if (pendingDelta + willCost > karmaAvailable) {
                alert(`Not enough karma: buying off ${q.name} costs ${willCost} karma (granted × 2), you have ${karmaRemaining} remaining.`);
                return;
            }
            onChange(C.stagePendingRemoveNegativeQuality(character, id));
        } else {
            onChange(C.removeQuality(character, id));
        }
    }

    function handleUndoBuyoff(id) {
        onChange(C.unstagePendingRemoveNegativeQuality(character, id));
    }

    function handleUndoPendingNew(tempId) {
        onChange(C.unstagePendingNewQuality(character, tempId));
    }

    function handleUpdateNotes(id, notes) {
        /* Notes on committed qualities are read-only in career (pre-existing
           edits). Creation mode keeps the usual flow. */
        if (inCareer) return;
        onChange(C.updateQuality(character, id, { notes }));
    }

    function handleUpdateRanks(id, ranks) {
        /* Rank edits on committed qualities not wired in career mode. */
        if (inCareer) return;
        onChange(C.updateQuality(character, id, { ranks }));
    }

    function renderQualityRow(q) {
        const template = q.key ? Q.findQuality(q.key) : null;
        const isRated = template?.karmaPerRank;
        const isPendingBuyoff = inCareer && q.type === 'negative' && pendingRemovedNegIds.has(q.id);
        return (
            <div className={`quality-row ${q.type} ${isPendingBuyoff ? 'pending-buyoff' : ''}`} key={q.id}>
                <div>
                    <div className="qr-name">
                        {q.name}
                        {/* Phase 19 — selection as an accent pill. Mentor spirit, Aptitude, etc. */}
                        {q.selection && (() => {
                            if (template?.needsSelection?.kind === 'skill') {
                                const sk = SR5_DATA.ACTIVE_SKILLS.find(s => s.key === q.selection);
                                return <span className="quality-selection-pill">{sk?.label || q.selection}</span>;
                            }
                            if (template?.needsSelection?.kind === 'attribute') {
                                const a = SR5_DATA.ATTRIBUTES.find(x => x.key === q.selection);
                                return <span className="quality-selection-pill">{a?.label || q.selection}</span>;
                            }
                            if (template?.needsSelection?.kind === 'mentorSpirit') {
                                const m = SR5_MAGIC.findMentorSpirit(q.selection);
                                return <span className="quality-selection-pill">{m?.name || q.selection}</span>;
                            }
                            return <span className="quality-selection-pill">{q.selection}</span>;
                        })()}
                        {isPendingBuyoff && (
                            <span style={{ marginLeft: 8, fontSize: 10, letterSpacing: '0.1em', color: 'var(--accent)' }}>
                                — pending buyoff
                            </span>
                        )}
                    </div>
                    {template?.description && !(q.key === 'mentor_spirit' && q.selection) && (
                        <div className="qr-desc">{template.description}</div>
                    )}
                    {/* Phase 19 fix — show mentor's own advantage/disadvantage when selected. */}
                    {q.key === 'mentor_spirit' && q.selection && (() => {
                        const mentor = SR5_MAGIC.findMentorSpirit(q.selection);
                        if (!mentor) return null;
                        return (
                            <div className="qr-desc" style={{ lineHeight: 1.5 }}>
                                <div><strong className="accent">Advantage:</strong> {mentor.advantage}</div>
                                <div style={{ marginTop: 2 }}><strong>Disadvantage:</strong> {mentor.disadvantage}</div>
                            </div>
                        );
                    })()}
                    {template?.requires && (
                        <div className="qr-desc" style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                            <em>requires: {template.requires}</em>
                        </div>
                    )}
                    <div className="qr-notes">
                        <input
                            className="qr-notes-input"
                            type="text"
                            value={q.notes || ''}
                            disabled={inCareer}
                            onChange={e => handleUpdateNotes(q.id, e.target.value)}
                            placeholder={
                                q.key?.startsWith('addiction') ? 'substance (e.g. Long Haul)' :
                                q.key?.startsWith('allergy') ? 'allergen (e.g. sunlight)' :
                                q.key === 'aptitude' ? 'skill (e.g. Pistols)' :
                                q.key === 'exceptional_attr' ? 'attribute' :
                                q.key === 'incompetent' ? 'skill' :
                                q.key === 'mentor_spirit' ? 'mentor' :
                                q.key === 'prejudiced' ? 'target (e.g. Corporates)' :
                                q.key === 'wanted' ? 'organization' :
                                q.key === 'natural_immunity' ? 'substance' :
                                'notes…'
                            }
                        />
                    </div>
                </div>
                <div className="qr-karma">{q.karma}</div>
                {isPendingBuyoff ? (
                    <button className="knowledge-remove-btn"
                            onClick={() => handleUndoBuyoff(q.id)}
                            title="Undo pending buyoff">↶</button>
                ) : (
                    <button className="knowledge-remove-btn"
                            onClick={() => {
                                const msg = inCareer
                                    ? (q.type === 'negative'
                                        ? `Buy off ${q.name} for ${q.karma * 2} karma?`
                                        : `Positive qualities can't be removed in career mode.`)
                                    : `Remove ${q.name}?`;
                                if (inCareer && q.type === 'positive') { alert(msg); return; }
                                if (confirm(msg)) handleRemove(q.id);
                            }}
                            title={inCareer
                                ? (q.type === 'negative' ? `Buy off (2× granted karma)` : 'Positive removal unavailable in career')
                                : 'Remove'}>×</button>
                )}
                {isRated && (
                    <div className="qr-ranks" style={{ gridColumn: 2 }}>
                        <span className="label">×</span>
                        <button className="stepper-btn" style={{ width: 20, height: 20, fontSize: 12 }}
                                onClick={() => handleUpdateRanks(q.id, Math.max(1, (q.ranks || 1) - 1))}
                                disabled={inCareer || (q.ranks || 1) <= 1}>−</button>
                        <span className="skill-rating-value" style={{ fontSize: 13, minWidth: 14 }}>{q.ranks || 1}</span>
                        <button className="stepper-btn" style={{ width: 20, height: 20, fontSize: 12 }}
                                onClick={() => handleUpdateRanks(q.id, Math.min(template.maxRanks || 4, (q.ranks || 1) + 1))}
                                disabled={inCareer || (q.ranks || 1) >= (template.maxRanks || 4)}>+</button>
                    </div>
                )}
            </div>
        );
    }

    function renderPendingNewRow(pq) {
        return (
            <div className={`quality-row ${pq.type} pending-new`} key={pq.tempId}>
                <div>
                    <div className="qr-name">
                        {pq.name}
                        <span style={{ marginLeft: 8, fontSize: 10, letterSpacing: '0.1em', color: 'var(--accent)' }}>
                            — pending new
                        </span>
                    </div>
                    <div className="qr-desc" style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                        karma: {pq.karmaCost} ({pq.listedKarma} listed × 2 in career)
                        {pq.ranks ? ` · rating ${pq.ranks}` : ''}
                    </div>
                </div>
                <div className="qr-karma" style={{ color: 'var(--accent)' }}>{pq.karmaCost}</div>
                <button className="knowledge-remove-btn"
                        onClick={() => handleUndoPendingNew(pq.tempId)}
                        title="Discard this pending new quality">×</button>
            </div>
        );
    }

    function pickerItemRenderer(q, { selected, alreadyTaken, onClick }) {
        const displayCost = inCareer
            ? (q.karmaPerRank ? `${q.karmaPerRank * 2}/rank (2×)` : `${q.karma * 2} (2×)`)
            : (q.karmaPerRank ? `${q.karmaPerRank}/rank` : `${q.karma}`);
        return (
            <div key={q.key}
                 className={`picker-item ${q.type} ${selected ? 'selected' : ''} ${alreadyTaken ? 'already-taken' : ''}`}
                 onClick={onClick}>
                <span className="pi-name">{q.name}</span>
                <span className="pi-karma">{displayCost}</span>
                {q.tags && q.tags.length > 0 && (
                    <div className="pi-meta">{q.tags.slice(0, 4).join(' · ')}</div>
                )}
            </div>
        );
    }

    function pickerDetails(q, { extras, setExtras }) {
        const ranks = extras.ranks || 1;
        const listedKarma = q.karmaPerRank ? q.karmaPerRank * ranks : q.karma;
        const displayKarma = inCareer ? listedKarma * 2 : listedKarma;
        return (
            <>
                <h3 className="picker-details-title">{q.name}</h3>
                <div className={`picker-details-cost ${q.type}`}>
                    <span className="cost-label">Karma {inCareer ? '(career: 2×)' : ''}</span>
                    <span className="cost-value">
                        {q.type === 'positive' ? '−' : '+'}
                        {q.karmaPerRank
                            ? (inCareer
                                ? `${displayKarma} (${q.karmaPerRank}/rank × ${ranks} × 2)`
                                : `${displayKarma} (${q.karmaPerRank}/rank × ${ranks})`)
                            : displayKarma}
                    </span>
                </div>
                {q.karmaPerRank && (
                    <div className="picker-details-rank-input">
                        <label>Ranks</label>
                        <RatingStepper
                            value={ranks}
                            min={1}
                            max={q.maxRanks || 4}
                            onChange={(n) => setExtras({ ...extras, ranks: n })}
                            stopPropagation
                        />
                        <span className="muted mono" style={{ fontSize: 11, marginLeft: 8 }}>max {q.maxRanks}</span>
                    </div>
                )}
                {q.description && (
                    <div className="picker-details-section">
                        <div className="picker-details-label">Effect</div>
                        <div className="picker-details-text">{q.description}</div>
                    </div>
                )}
                {/* Phase 19 — selection input for qualities that require a pick. */}
                {q.needsSelection && (
                    <div className="picker-details-section">
                        <div className="picker-details-label">{q.needsSelection.label || 'Selection'}</div>
                        <QualitySelectionInput
                            kind={q.needsSelection.kind}
                            value={extras.selection || ''}
                            onChange={v => setExtras({ ...extras, selection: v })}
                            character={character}
                        />
                        {q.needsSelection.kind === 'mentorSpirit' && extras.selection && (() => {
                            const mentor = SR5_MAGIC.findMentorSpirit(extras.selection);
                            if (!mentor) return null;
                            return (
                                <div style={{ marginTop: 10, padding: 10, background: 'rgba(240, 168, 66, 0.06)', borderLeft: '2px solid var(--accent-dim)', borderRadius: 2 }}>
                                    <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--accent)', marginBottom: 4 }}>{mentor.name}</div>
                                    <div style={{ fontSize: 11, lineHeight: 1.5 }}>
                                        <strong>Advantage:</strong> {mentor.advantage}
                                    </div>
                                    <div style={{ fontSize: 11, lineHeight: 1.5, marginTop: 4 }}>
                                        <strong>Disadvantage:</strong> {mentor.disadvantage}
                                    </div>
                                </div>
                            );
                        })()}
                    </div>
                )}
                {q.requires && (
                    <div className="picker-details-section">
                        <div className="picker-details-label">Requires</div>
                        <div className="picker-details-text">{q.requires}</div>
                    </div>
                )}
                {q.tags && q.tags.length > 0 && (
                    <div className="picker-details-section">
                        <div className="picker-details-label">Tags</div>
                        <div className="picker-details-tags">
                            {q.tags.map(t => <span key={t} className="picker-tag">{t}</span>)}
                        </div>
                    </div>
                )}
                {q.source && (
                    <div className="picker-details-source">{q.source}</div>
                )}
            </>
        );
    }

    return (
        <>
            <ContentHeader title="05 / Qualities" heading="Positive &amp; negative traits" />

            {inCareer ? (
                /* Career-mode summary: just the karma chip. Creation caps
                   (25 karma each direction) don't apply mid-career. */
                <div className="karma-summary">
                    <div className="karma-stat">
                        <span className="k-label">Karma Earned</span>
                        <span className="k-value">{character.career?.karmaEarned || 0}</span>
                    </div>
                    <div className="karma-stat">
                        <span className="k-label">Karma Spent</span>
                        <span className="k-value">{character.career?.karmaSpent || 0}</span>
                    </div>
                    <div className={`karma-stat ${pendingDelta > 0 ? 'positive' : ''}`}>
                        <span className="k-label">Pending Spend</span>
                        <span className="k-value">{pendingDelta}</span>
                    </div>
                    <div className={`karma-stat ${karmaRemaining >= 0 ? 'free' : 'over'}`}>
                        <span className="k-label">Karma Remaining</span>
                        <span className="k-value">{karmaRemaining}</span>
                        <span className="k-cap">after pending</span>
                    </div>
                </div>
            ) : (
                <div className="karma-summary">
                    <div className="karma-stat">
                        <span className="k-label">Starting Karma</span>
                        <span className="k-value">{starting}</span>
                    </div>
                    <div className={`karma-stat positive ${posState}`}>
                        <span className="k-label">Positive (cost)</span>
                        <span className="k-value">{posSpent}</span>
                        <span className="k-cap">cap {posCap}</span>
                    </div>
                    <div className={`karma-stat negative ${negState}`}>
                        <span className="k-label">Negative (gained)</span>
                        <span className="k-value">{negGained}</span>
                        <span className="k-cap">cap {negCap}</span>
                    </div>
                    <div className={`karma-stat ${remaining >= 0 ? 'free' : 'over'}`}>
                        <span className="k-label">Karma Remaining</span>
                        <span className="k-value">{remaining}</span>
                        <span className="k-cap">for later purchases</span>
                    </div>
                </div>
            )}

            <div className="qualities-columns">
                <div className="card qualities-column positive">
                    <div className="card-header">
                        <h3 className="card-title">Positive Qualities</h3>
                    </div>
                    {positive.length === 0 && pendingNewPos.length === 0 ? (
                        <div className="quality-column-empty">none yet — add below</div>
                    ) : (
                        <>
                            {positive.map(renderQualityRow)}
                            {pendingNewPos.map(renderPendingNewRow)}
                        </>
                    )}
                    <div className="quality-add-bar">
                        <button className="add-button" onClick={() => setPickerOpen('positive')}>
                            <span className="plus-icon">+</span>Browse {inCareer ? '(2× karma)' : ''}
                        </button>
                        {!inCareer && (
                            <button className="add-button" style={{ marginLeft: 6 }}
                                    onClick={() => setCustomOpen('positive')}>
                                <span className="plus-icon">+</span>Custom
                            </button>
                        )}
                    </div>
                </div>

                <div className="card qualities-column negative">
                    <div className="card-header">
                        <h3 className="card-title">Negative Qualities</h3>
                    </div>
                    {negative.length === 0 && pendingNewNeg.length === 0 ? (
                        <div className="quality-column-empty">none yet — add below</div>
                    ) : (
                        <>
                            {negative.map(renderQualityRow)}
                            {pendingNewNeg.map(renderPendingNewRow)}
                        </>
                    )}
                    <div className="quality-add-bar">
                        <button className="add-button"
                                onClick={() => setPickerOpen('negative')}
                                disabled={inCareer}
                                title={inCareer ? "Negatives can't be added in career mode — only bought off" : ''}>
                            <span className="plus-icon">+</span>Browse
                        </button>
                        {!inCareer && (
                            <button className="add-button" style={{ marginLeft: 6 }}
                                    onClick={() => setCustomOpen('negative')}>
                                <span className="plus-icon">+</span>Custom
                            </button>
                        )}
                    </div>
                </div>
            </div>

            {pickerOpen && (
                <EntityPicker
                    title={pickerOpen === 'positive'
                        ? `Add a Positive Quality${inCareer ? ' (2× karma in career)' : ''}`
                        : 'Add a Negative Quality'}
                    items={pickerOpen === 'positive' ? positiveTemplates : negativeTemplates}
                    getItemKey={q => q.key}
                    filters={Q.TAGS.map(t => ({ key: t, label: t }))}
                    filterBy={(q, query, filter) => {
                        if (filter && !(q.tags || []).includes(filter)) return false;
                        if (query && !q.name.toLowerCase().includes(query)) return false;
                        return true;
                    }}
                    isAlreadyTaken={isAlreadyTaken}
                    itemRenderer={pickerItemRenderer}
                    renderDetails={pickerDetails}
                    onPick={handlePick}
                    onClose={() => setPickerOpen(null)}
                />
            )}

            {customOpen && (
                <CustomQualityDialog
                    type={customOpen}
                    onSubmit={(name, karma, notes) => {
                        onChange(C.addCustomQuality(character, customOpen, name, karma, notes));
                        setCustomOpen(null);
                    }}
                    onClose={() => setCustomOpen(null)}
                />
            )}
        </>
    );
};

/* ============================================================
   QualitySelectionInput (Phase 19)

   Renders the appropriate picker for a quality's needsSelection:
   - attribute:     dropdown of physical + mental attributes
   - skill:         searchable dropdown of active skills
   - mentorSpirit:  dropdown of CRB mentor spirits
   ============================================================ */
window.QualitySelectionInput = function QualitySelectionInput({ kind, value, onChange, character }) {
    const D = SR5_DATA;
    const M = SR5_MAGIC;
    if (kind === 'attribute') {
        return (
            <select className="input" value={value} onChange={e => onChange(e.target.value)}>
                <option value="">— pick an attribute —</option>
                {D.ATTRIBUTES.map(a => (
                    <option key={a.key} value={a.key}>{a.label}</option>
                ))}
            </select>
        );
    }
    if (kind === 'skill') {
        return (
            <select className="input" value={value} onChange={e => onChange(e.target.value)}>
                <option value="">— pick a skill —</option>
                {D.ACTIVE_SKILLS.map(s => (
                    <option key={s.key} value={s.key}>{s.label}</option>
                ))}
            </select>
        );
    }
    if (kind === 'mentorSpirit') {
        return (
            <select className="input" value={value} onChange={e => onChange(e.target.value)}>
                <option value="">— pick a mentor spirit —</option>
                {M.MENTOR_SPIRITS.map(m => (
                    <option key={m.key} value={m.key}>{m.name}</option>
                ))}
            </select>
        );
    }
    return null;
};
