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


/* ------------------------------------------------------------
   AttributesView — the attribute allocation screen
   ------------------------------------------------------------ */
window.AttributesView = function AttributesView({ character, onChange }) {
    const D = SR5_DATA;
    const C = SR5_CALC;

    const metatype = C.getMetatype(character);
    const inCareer = C.isCareerMode(character);
    const karmaAvailable = C.karmaCurrent(character);

    if (!metatype) {
        return (
            <>
                <ContentHeader title="03 / Attributes" heading="Spend attribute points" />
                <div className="card"><div className="card-body muted">
                    Pick a metatype first. Attribute ranges depend on your chosen metatype.
                </div></div>
            </>
        );
    }

    const totalAttrPts = C.attributePointsTotal(character);
    const spentAttrPts = C.attributePointsSpent(character);
    const totalSpecialPts = C.specialPointsTotal(character);
    const spentSpecialPts = C.specialPointsSpent(character);

    if (totalAttrPts === 0 && !inCareer) {
        return (
            <>
                <ContentHeader title="03 / Attributes" heading="Spend attribute points" />
                <div className="card"><div className="card-body muted">
                    Assign a priority letter to the <strong className="accent">Attributes</strong> category first.
                </div></div>
            </>
        );
    }

    const attrsAtMax = C.attributesAtMax(character);
    const hasAnyAtMax = attrsAtMax.length > 0;

    /* Route changes through pending layer in career mode; direct in creation. */
    function handleAttrChange(attrKey, newValue) {
        if (inCareer) onChange(C.stagePendingAttrDelta(character, attrKey, newValue));
        else onChange(C.setAttributeValue(character, attrKey, newValue));
    }
    function handleSpecialChange(attrKey, newValue) {
        if (inCareer) onChange(C.stagePendingAttrDelta(character, attrKey, newValue));
        else onChange(C.setSpecialAttributeValue(character, attrKey, newValue));
    }

    /* Compute whether incrementing the named attribute (by 1 total rating)
       would fit within remaining karma. Accounts for karma already staged
       on OTHER attrs. */
    function canAffordAttrInc(attrKey, currentValue) {
        const p = C.pendingChanges(character);
        const nextRating = currentValue + 1;
        const committed = (() => {
            const isSpecial = !!D.SPECIAL_ATTRIBUTES.find(a => a.key === attrKey);
            return isSpecial ? C.specialAttributeValue(character, attrKey) : C.attributeValue(character, attrKey);
        })();
        /* Cost to take this attribute from committed → nextRating. */
        let stepCostCumulative = 0;
        for (let r = committed + 1; r <= nextRating; r++) stepCostCumulative += C.karmaCostAttributeRaise(r);
        /* Karma already staged on OTHER attrs + other pending categories. */
        const alreadyStagedOnThis = p.attrDeltas?.[attrKey]?.karmaCost || 0;
        const totalIfIncreased = (C.pendingKarmaDelta(character) - alreadyStagedOnThis) + stepCostCumulative;
        return totalIfIncreased <= karmaAvailable;
    }

    function renderAttrRow(attr) {
        const [min, max] = C.getAttributeRange(character, attr.key);
        const committedValue = C.attributeValue(character, attr.key);
        const value = inCareer ? C.attributeValueProjected(character, attr.key) : committedValue;
        const hasPending = inCareer && (value !== committedValue);
        const isThisAtMax = value >= max;
        /* In creation: hard cap at metatype max; only one attr may be at max. */
        const otherAtMax = !inCareer && hasAnyAtMax && !isThisAtMax;

        let canIncOverride, canDecOverride, incTitle;
        if (inCareer) {
            canIncOverride = value < max && canAffordAttrInc(attr.key, value);
            canDecOverride = value > committedValue;  /* only unwind pending raises */
            if (!canIncOverride && value < max) incTitle = 'Not enough karma';
        } else {
            /* Phase 16 — creation: allow karma spillover when attr points exhausted. */
            if (spentAttrPts >= totalAttrPts) {
                const kt = C.karmaTotals(character);
                const costOfNext = C.karmaCostAttributeRaise(value + 1);
                if (kt.remaining < costOfNext) {
                    canIncOverride = false;
                    incTitle = `Needs ${costOfNext} karma (have ${kt.remaining})`;
                }
            }
        }

        return (
            <div className={`attr-row ${hasPending ? 'pending' : ''}`} key={attr.key}>
                <div className="attr-name">
                    <span className="label">{attr.label}</span>
                    <span className="abbr">{attr.abbr}</span>
                </div>
                <AttributeStepper
                    value={value}
                    min={min}
                    max={max}
                    onChange={(v) => handleAttrChange(attr.key, v)}
                    hardCapAtMaxInCreation={otherAtMax}
                    canIncOverride={canIncOverride}
                    canDecOverride={canDecOverride}
                    pending={hasPending}
                    incTitle={incTitle}
                />
                <div className="attr-range">
                    min <span className="slash">/</span> max &nbsp; {min}<span className="slash">/</span>{max}
                </div>
            </div>
        );
    }

    const magicType = C.priorityRow(character, 'magic')?.type;
    const hasMagic = magicType && magicType !== 'mundane';
    const specialAttrsToShow = D.SPECIAL_ATTRIBUTES.filter(sa => {
        if (sa.key === 'edg') return true;
        if (sa.key === 'mag') return hasMagic && magicType !== 'technomancer';
        if (sa.key === 'res') return magicType === 'technomancer';
        return false;
    });

    function renderSpecialRow(attr) {
        const committedValue = C.specialAttributeValue(character, attr.key);
        const value = inCareer ? C.attributeValueProjected(character, attr.key) : committedValue;
        const hasPending = inCareer && (value !== committedValue);
        let min, max;
        if (attr.key === 'edg') {
            [min, max] = metatype.edg;
            /* Phase 19 — Lucky raises Edge metatype max. */
            max = max + C.specialAttributeMaxBonus(character, 'edg');
        } else if (attr.key === 'mag') {
            min = C.priorityRow(character, 'magic')?.magic ?? 0;
            max = 6;
        } else {
            min = 0; max = 6;
        }
        let canIncOverride, canDecOverride, incTitle;
        if (inCareer) {
            canIncOverride = value < max && canAffordAttrInc(attr.key, value);
            canDecOverride = value > committedValue;
            if (!canIncOverride && value < max) incTitle = 'Not enough karma';
        } else {
            /* Phase 16 — creation karma spillover for special attrs. */
            if (spentSpecialPts >= totalSpecialPts) {
                const kt = C.karmaTotals(character);
                const costOfNext = C.karmaCostAttributeRaise(value + 1);
                if (kt.remaining < costOfNext) {
                    canIncOverride = false;
                    incTitle = `Needs ${costOfNext} karma (have ${kt.remaining})`;
                }
            }
        }
        return (
            <div className={`attr-row ${hasPending ? 'pending' : ''}`} key={attr.key}>
                <div className="attr-name">
                    <span className="label">{attr.label}</span>
                    <span className="abbr">{attr.abbr}</span>
                </div>
                <AttributeStepper
                    value={value}
                    min={min}
                    max={max}
                    onChange={(v) => handleSpecialChange(attr.key, v)}
                    canIncOverride={canIncOverride}
                    canDecOverride={canDecOverride}
                    pending={hasPending}
                    incTitle={incTitle}
                />
                <div className="attr-range">
                    min <span className="slash">/</span> max &nbsp; {min}<span className="slash">/</span>{max}
                </div>
            </div>
        );
    }

    /* Karma chip shown in career mode instead of points chips. */
    const karmaRemaining = karmaAvailable - C.pendingKarmaDelta(character);
    const KarmaChip = () => (
        <span className="points-chip" title="Karma available for stat raises">
            <span className="pc-label">karma</span>
            <span className="pc-value">{karmaRemaining} / {karmaAvailable}</span>
        </span>
    );

    const derived = C.derivedStats(character);
    const cm = C.conditionMonitor(character);

    return (
        <>
            <ContentHeader title="03 / Attributes" heading="Spend attribute points" />

            <div className="card">
                <div className="card-header">
                    <h3 className="card-title">Physical &amp; Mental ({metatype.name})</h3>
                    <div className="card-header-right">
                        {inCareer
                            ? <KarmaChip />
                            : <PointsChip label="attr pts" spent={spentAttrPts} total={totalAttrPts} />}
                    </div>
                </div>
                <div className="attr-group-label">Physical</div>
                {D.ATTRIBUTES.filter(a => a.group === 'physical').map(renderAttrRow)}
                <div className="attr-group-label">Mental</div>
                {D.ATTRIBUTES.filter(a => a.group === 'mental').map(renderAttrRow)}
                {!inCareer && attrsAtMax.length > 1 && (
                    <div style={{ padding: '0 20px 14px' }}>
                        <div className="attr-warning">
                            Only ONE attribute may be at its natural maximum during creation.
                            Currently at max: <strong>{attrsAtMax.map(k => D.ATTRIBUTES.find(a => a.key === k)?.abbr || k).join(', ')}</strong>.
                        </div>
                    </div>
                )}
            </div>

            <div className="card">
                <div className="card-header">
                    <h3 className="card-title">Special Attributes</h3>
                    <div className="card-header-right">
                        {inCareer
                            ? <KarmaChip />
                            : <PointsChip label="special pts" spent={spentSpecialPts} total={totalSpecialPts} />}
                    </div>
                </div>
                {specialAttrsToShow.length === 0 ? (
                    <div className="card-body muted" style={{ fontSize: 13 }}>
                        No special attributes available. Edge requires metatype priority to be set.
                    </div>
                ) : (
                    specialAttrsToShow.map(renderSpecialRow)
                )}
            </div>

            <div className="card">
                <div className="card-header">
                    <h3 className="card-title">Derived &amp; Condition Monitor</h3>
                </div>
                <div className="derived-grid">
                    {derived.map(stat => (
                        <div className="derived-cell" key={stat.key}>
                            <span className="label">{stat.label}</span>
                            <span className="value">
                                {stat.value}
                                {stat.suffix && <span className="suffix">{stat.suffix}</span>}
                            </span>
                        </div>
                    ))}
                </div>
                <div style={{ padding: '0 20px 16px' }}>
                    <div className="condition-monitor">
                        <span className="cm-label">Physical</span>
                        <div className="cm-boxes">
                            {Array.from({ length: cm.physical }, (_, i) => <div key={i} className="cm-box" />)}
                        </div>
                    </div>
                    <div className="condition-monitor">
                        <span className="cm-label">Stun</span>
                        <div className="cm-boxes">
                            {Array.from({ length: cm.stun }, (_, i) => <div key={i} className="cm-box" />)}
                        </div>
                    </div>
                </div>
            </div>
        </>
    );
};
