// Chat-related UI components
const { useRef, useEffect } = React;

// Languages the Game Master can narrate in. English is the default.
const GAME_LANGUAGES = [
    'English', 'Français', 'Español', 'Deutsch', 'Italiano', 'Português',
    'Nederlands', 'Polski', 'Русский', 'Українська', 'Türkçe', 'العربية',
    '中文', '日本語', '한국어', 'हिन्दी', 'Bahasa Indonesia', 'Tiếng Việt',
    'ไทย', 'Svenska', 'Norsk', 'Dansk', 'Suomi', 'Čeština', 'Ελληνικά',
    'Română', 'Magyar', 'עברית',
];

function LanguageSelector() {
    const [open, setOpen] = React.useState(false);
    const [filter, setFilter] = React.useState('');
    const [lang, setLang] = React.useState(() => {
        try { return localStorage.getItem('gameLanguage') || 'English'; } catch { return 'English'; }
    });
    const rootRef = React.useRef(null);

    React.useEffect(() => {
        if (!open) return;
        const onDoc = (e) => { if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false); };
        const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
        document.addEventListener('mousedown', onDoc);
        document.addEventListener('keydown', onKey);
        return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); };
    }, [open]);

    const select = (l) => {
        setLang(l);
        try { localStorage.setItem('gameLanguage', l); } catch { /* ignore */ }
        if (typeof gtag === 'function') gtag('event', 'language_change', { language: l });
        setOpen(false);
        setFilter('');
    };

    const matches = GAME_LANGUAGES.filter(l => l.toLowerCase().includes(filter.toLowerCase()));

    return (
        <div className="lang-selector" ref={rootRef}>
            <button className="lang-trigger" onClick={() => setOpen(o => !o)} title="Game language">
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                    <circle cx="12" cy="12" r="10"></circle>
                    <line x1="2" y1="12" x2="22" y2="12"></line>
                    <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
                </svg>
                <span>{lang}</span>
            </button>
            {open && (
                <div className="lang-menu">
                    <input
                        className="lang-filter"
                        type="text"
                        placeholder="Search language…"
                        value={filter}
                        onChange={(e) => setFilter(e.target.value)}
                        autoFocus
                    />
                    <div className="lang-list">
                        {matches.map(l => (
                            <button
                                key={l}
                                className={`lang-option ${l === lang ? 'active' : ''}`}
                                onClick={() => select(l)}
                            >
                                {l}
                            </button>
                        ))}
                        {matches.length === 0 && <div className="lang-empty">No match</div>}
                    </div>
                </div>
            )}
        </div>
    );
}

const COUNTRY_TO_ISO2 = {
    'afghanistan': 'AF', 'albania': 'AL', 'algeria': 'DZ', 'argentina': 'AR', 'armenia': 'AM',
    'australia': 'AU', 'austria': 'AT', 'azerbaijan': 'AZ', 'bangladesh': 'BD', 'belarus': 'BY',
    'belgium': 'BE', 'bolivia': 'BO', 'brazil': 'BR', 'bulgaria': 'BG', 'cambodia': 'KH',
    'cameroon': 'CM', 'canada': 'CA', 'chile': 'CL', 'china': 'CN', 'colombia': 'CO',
    'congo': 'CD', 'costa rica': 'CR', 'croatia': 'HR', 'cuba': 'CU', 'czech republic': 'CZ',
    'czechia': 'CZ', 'denmark': 'DK', 'ecuador': 'EC', 'egypt': 'EG', 'ethiopia': 'ET',
    'finland': 'FI', 'france': 'FR', 'georgia': 'GE', 'germany': 'DE', 'ghana': 'GH',
    'greece': 'GR', 'guatemala': 'GT', 'hungary': 'HU', 'india': 'IN', 'indonesia': 'ID',
    'iran': 'IR', 'iraq': 'IQ', 'ireland': 'IE', 'israel': 'IL', 'italy': 'IT',
    'japan': 'JP', 'jordan': 'JO', 'kazakhstan': 'KZ', 'kenya': 'KE', 'kuwait': 'KW',
    'lebanon': 'LB', 'libya': 'LY', 'malaysia': 'MY', 'mexico': 'MX', 'morocco': 'MA',
    'myanmar': 'MM', 'nepal': 'NP', 'netherlands': 'NL', 'new zealand': 'NZ', 'nigeria': 'NG',
    'north korea': 'KP', 'norway': 'NO', 'pakistan': 'PK', 'palestine': 'PS', 'panama': 'PA',
    'peru': 'PE', 'philippines': 'PH', 'poland': 'PL', 'portugal': 'PT', 'qatar': 'QA',
    'romania': 'RO', 'russia': 'RU', 'saudi arabia': 'SA', 'senegal': 'SN', 'serbia': 'RS',
    'singapore': 'SG', 'south africa': 'ZA', 'south korea': 'KR', 'spain': 'ES', 'sri lanka': 'LK',
    'sudan': 'SD', 'sweden': 'SE', 'switzerland': 'CH', 'syria': 'SY', 'taiwan': 'TW',
    'thailand': 'TH', 'tunisia': 'TN', 'turkey': 'TR', 'turkiye': 'TR', 'ukraine': 'UA',
    'united arab emirates': 'AE', 'uae': 'AE', 'united kingdom': 'GB', 'uk': 'GB',
    'united states': 'US', 'usa': 'US', 'uruguay': 'UY', 'uzbekistan': 'UZ',
    'venezuela': 'VE', 'vietnam': 'VN', 'yemen': 'YE', 'zimbabwe': 'ZW',
};

function countryFlag(countryName) {
    if (!countryName) return '';
    const iso = COUNTRY_TO_ISO2[countryName.toLowerCase().trim()];
    if (!iso) return '';
    return String.fromCodePoint(...[...iso].map(c => 0x1F1E6 + c.charCodeAt(0) - 65));
}

function LeaderCard({ leader }) {
    if (!leader || !leader.name) return null;
    const flag = countryFlag(leader.country);
    return (
        <div className="leader-card">
            <div className="leader-card-info">
                <div className="leader-card-name">{leader.name}</div>
                {leader.title && <div className="leader-card-title">{leader.title}</div>}
                <div className="leader-card-meta">
                    {leader.country && <span>{flag && `${flag} `}{leader.country}</span>}
                    {leader.born && <span>b. {leader.born}</span>}
                    {leader.party && <span>{leader.party}</span>}
                </div>
                {leader.trait && <div className="leader-card-trait">{leader.trait}</div>}
            </div>
        </div>
    );
}

function AchievementBanner({ achievement }) {
    return (
        <div className="achievement-banner">
            <div className="achievement-icon">
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
                </svg>
            </div>
            <div className="achievement-content">
                <div className="achievement-label">ACHIEVEMENT UNLOCKED</div>
                <div className="achievement-title">{achievement.title}</div>
                {achievement.description && <div className="achievement-desc">{achievement.description}</div>}
            </div>
        </div>
    );
}

function highlightNarrativeData(html) {
    return html.replace(
        /(?<![<\w])(\d[\d,.]*\s*%|\$[\d,.]+[BMKbmk]?|€[\d,.]+[BMKbmk]?|\d[\d,.]*\s*(?:billion|million|trillion|troops|soldiers|km|miles|casualties|votes|seats|points|days|hours|weeks|months|years))\b/gi,
        '<span class="hl-data hl-clickable">$1</span>'
    );
}

function ExplainPopover({ term, rect, onClose, context }) {
    const [explanation, setExplanation] = React.useState(null);
    const [loading, setLoading] = React.useState(true);
    const popoverRef = React.useRef(null);

    React.useEffect(() => {
        claudeClient.explainTerm(term, context)
            .then(setExplanation)
            .catch(() => setExplanation('Could not load explanation.'))
            .finally(() => setLoading(false));
    }, [term]);

    React.useEffect(() => {
        const handleClick = (e) => {
            if (popoverRef.current && !popoverRef.current.contains(e.target)) onClose();
        };
        const handleKey = (e) => { if (e.key === 'Escape') onClose(); };
        document.addEventListener('mousedown', handleClick);
        document.addEventListener('keydown', handleKey);
        return () => { document.removeEventListener('mousedown', handleClick); document.removeEventListener('keydown', handleKey); };
    }, [onClose]);

    return (
        <div className="explain-popover" ref={popoverRef}>
            <div className="explain-term">{term}</div>
            <div className="explain-body">
                {loading ? <span className="explain-loading">Loading...</span> : explanation}
            </div>
        </div>
    );
}

function ChatMessage({ message, onRetry }) {
    const roleClasses = {
        narrator: 'chat-message narrator',
        player: 'chat-message player',
        system: 'chat-message system',
        event: 'chat-message event',
    };

    const [explainTarget, setExplainTarget] = React.useState(null);

    const getDisplayContent = () => {
        let text = message.content || '';
        text = text.replace(/```(?:gamestate|choices)[\s\n][\s\S]*?```/g, '');
        text = text.replace(/```(?:gamestate|choices)[\s\n][\s\S]*$/g, '');
        return text.trim();
    };

    const handleNarrativeClick = (e) => {
        const el = e.target.closest('strong, .hl-clickable');
        if (!el) return;
        const term = el.textContent.trim();
        if (!term) return;
        const rect = el.getBoundingClientRect();
        const context = message.content?.slice(0, 1000) || '';
        setExplainTarget({ term, rect, context });
    };

    const renderContent = () => {
        const content = getDisplayContent();
        if (!content) return null;
        if (message.role === 'narrator' && typeof marked !== 'undefined') {
            const rawHtml = marked.parse(content);
            const sanitized = typeof DOMPurify !== 'undefined' ? DOMPurify.sanitize(rawHtml) : rawHtml;
            const html = highlightNarrativeData(sanitized);
            return <div className="content markdown-content" onClick={handleNarrativeClick} dangerouslySetInnerHTML={{ __html: html }} />;
        }
        return <div className="content">{content}</div>;
    };

    const achievement = message.gameStateUpdates?.achievement;

    return (
        <div className={roleClasses[message.role] || 'chat-message system'} data-turn={message.turn}>
            {renderContent()}
            {message.retryable && onRetry && (
                <button className="chat-retry-btn" onClick={onRetry}>Retry</button>
            )}
            {achievement && <AchievementBanner achievement={achievement} />}
            {explainTarget && (
                <ExplainPopover
                    term={explainTarget.term}
                    rect={explainTarget.rect}
                    context={explainTarget.context}
                    onClose={() => setExplainTarget(null)}
                />
            )}
        </div>
    );
}

const THINKING_LABELS = [
    'Theorizing...', 'Plotting...', 'Scheming...', 'Calculating...', 'Strategizing...',
    'Simulating...', 'Analyzing...', 'Deliberating...', 'Maneuvering...', 'Assessing...',
    'Projecting...', 'Weighing options...', 'Reading the board...', 'Consulting sources...',
];

function TypingIndicator() {
    const label = React.useMemo(
        () => THINKING_LABELS[Math.floor(Math.random() * THINKING_LABELS.length)],
        []
    );
    return (
        <div className="typing-indicator">
            <span className="thinking-text">{label}</span>
        </div>
    );
}

function gravityColor(gravity) {
    if (gravity == null) return null;
    const g = Math.max(1, Math.min(10, gravity));
    // Map 1-10 across the full hue spectrum: blue(220) → cyan → green → yellow → orange → red → magenta → violet(280)
    // We go: 220 → 180 → 120 → 60 → 30 → 0 → 330 → 290
    const hueStops = [220, 200, 170, 140, 100, 60, 30, 0, 330, 290];
    const idx = g - 1;
    const hue = hueStops[idx];
    return { hue, border: `hsla(${hue}, 50%, 60%, 0.35)`, borderHover: `hsla(${hue}, 50%, 60%, 0.6)`, bgHover: `hsla(${hue}, 50%, 60%, 0.06)`, id: `hsl(${hue}, 45%, 62%)` };
}

function ChoiceButtons({ choices, onSelect, disabled, onRequestIntel }) {
    if (!choices || choices.length === 0) return null;

    return (
        <div className="choice-container">
            {onRequestIntel && (
                <button
                    className="intel-btn"
                    onClick={onRequestIntel}
                    disabled={disabled}
                    title="Hear your advisors' read on the options before deciding — uses tokens, once per turn"
                >
                    Consult your advisors <span className="intel-btn-cost">· uses tokens</span>
                </button>
            )}
            {choices.map((choice) => {
                const gc = gravityColor(choice.gravity);
                return (
                    <button
                        key={choice.id}
                        onClick={() => onSelect(choice)}
                        disabled={disabled}
                        className={`choice-btn ${disabled ? 'disabled' : ''}`}
                        style={gc ? { borderColor: gc.border, '--gravity-border-hover': gc.borderHover, '--gravity-bg-hover': gc.bgHover, '--gravity-id': gc.id } : undefined}
                    >
                        <div className="choice-main">
                            <span className="choice-id" style={gc ? { color: gc.id } : undefined}>{choice.id}.</span>
                            <span className="choice-label">{choice.label}</span>
                        </div>
                    </button>
                );
            })}
        </div>
    );
}

function ScenarioSelector({ onSelectScenario, onCustomGame, gameList = [], onShowLadder }) {
    const [search, setSearch] = React.useState('');
    const [sort, setSort] = React.useState('most-played');
    const [stats, setStats] = React.useState({});
    const [scenarios, setScenarios] = React.useState([]);
    const [reportTarget, setReportTarget] = React.useState(null); // { id, title }
    const [reportReason, setReportReason] = React.useState('');
    const [reportStatus, setReportStatus] = React.useState(null); // null | 'sending' | 'done' | 'error' | 'duplicate'

    React.useEffect(() => {
        firebaseClient.loadScenarioStats().then(setStats);
        firebaseClient.loadScenarios().then(setScenarios);
    }, []);

    // All scenarios come from Firestore (official ones + admin-created customs)
    const allScenarios = scenarios;

    const getTitle = (s) => typeof s.title === 'string' ? s.title : (s.title.en || Object.values(s.title)[0]);
    const getSubtitle = (s) => typeof s.subtitle === 'string' ? s.subtitle : (s.subtitle?.en || '');
    const getDesc = (s) => typeof s.description === 'string' ? s.description : (s.description?.en || '');
    const getPlays = (s) => stats[s.id]?.plays || 0;
    const getWinRate = (s) => {
        const st = stats[s.id];
        if (!st) return null;
        const total = (st.victories || 0) + (st.defeats || 0);
        if (total === 0) return null;
        return Math.round((st.victories || 0) / total * 100);
    };

    // Match scenario to player's game history: 'victory' | 'game_over' | 'playing' | null
    const getScenarioStatus = (s) => {
        const title = getTitle(s);
        const matches = gameList.filter(g => g.playerTheme === title);
        if (matches.length === 0) return null;
        if (matches.some(g => g.gamePhase === 'playing')) return 'playing';
        if (matches.some(g => g.gamePhase === 'victory')) return 'victory';
        return 'game_over';
    };
    const formatDate = (d) => {
        if (!d) return '';
        const [y, m, day] = d.split('-');
        const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
        return `${months[parseInt(m, 10) - 1]} ${parseInt(day, 10)}, ${y}`;
    };

    // Filter
    const filtered = React.useMemo(() => {
        let list = allScenarios;
        if (search.trim()) {
            const q = search.toLowerCase();
            list = list.filter(s =>
                getTitle(s).toLowerCase().includes(q) ||
                getSubtitle(s).toLowerCase().includes(q) ||
                getDesc(s).toLowerCase().includes(q)
            );
        }
        return list;
    }, [search, allScenarios]);

    // Sort
    const sorted = React.useMemo(() => {
        const list = [...filtered];
        if (sort === 'latest') list.reverse();
        else if (sort === 'most-played') list.sort((a, b) => getPlays(b) - getPlays(a));
        else if (sort === 'chrono') list.sort((a, b) => (b.startDate || '').localeCompare(a.startDate || ''));
        else if (sort === 'hardest') list.sort((a, b) => {
            const wrA = getWinRate(a);
            const wrB = getWinRate(b);
            // Scenarios with no data go to the end
            if (wrA === null && wrB === null) return 0;
            if (wrA === null) return 1;
            if (wrB === null) return -1;
            return wrA - wrB; // lowest win rate first = hardest
        });
        return list;
    }, [filtered, sort, stats]);

    return (
        <div className="scenario-selector">
            <div className="scenario-header">
                <div className="scenario-header-top">
                    <h2 className="scenario-title">RISK</h2>
                    <div className="scenario-toolbar">
                        <div className="scenario-search">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                <circle cx="11" cy="11" r="8"></circle>
                                <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
                            </svg>
                            <input
                                type="text"
                                value={search}
                                onChange={(e) => {
                                    setSearch(e.target.value);
                                    if (e.target.value && typeof gtag === 'function') gtag('event', 'scenario_search', { query: e.target.value.slice(0, 50) });
                                }}
                                placeholder="Search..."
                                className="scenario-search-input"
                            />
                        </div>
                        <select
                            value={sort}
                            onChange={(e) => {
                                setSort(e.target.value);
                                if (typeof gtag === 'function') gtag('event', 'scenario_sort', { sort_by: e.target.value });
                            }}
                            className="scenario-sort"
                        >
                            <option value="most-played">Most played</option>
                            <option value="hardest">Hardest</option>
                            <option value="latest">Latest</option>
                            <option value="chrono">Chronological</option>
                        </select>
                    </div>
                </div>
                <p className="scenario-subtitle">
                    Pick a scenario or create your own
                    {onShowLadder && (
                        <button className="scenario-ladder-link" onClick={(e) => { e.stopPropagation(); onShowLadder(); }}>
                            Ladder
                        </button>
                    )}
                </p>
            </div>

            <div className="scenario-grid">
                <button className="scenario-card scenario-card-custom" onClick={(e) => { e.stopPropagation(); if (typeof gtag === 'function') gtag('event', 'custom_game_click'); onCustomGame(); }}>
                    <span className="scenario-premium-badge">Premium</span>
                    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M12 20h9"></path>
                        <path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"></path>
                    </svg>
                    <div className="scenario-card-title">Create my own scenario</div>
                    <div className="scenario-card-desc">Design a custom crisis. Win it, then share it with the community.</div>
                </button>
                {sorted.map((scenario, idx) => {
                    const status = getScenarioStatus(scenario);
                    return (
                    <button
                        key={scenario.id}
                        className={`scenario-card ${status ? `scenario-${status}` : ''}`}
                        onClick={() => { if (typeof gtag === 'function') gtag('event', 'scenario_select', { scenario_id: scenario.id, title: getTitle(scenario).slice(0, 50), source: scenario.source || 'official' }); onSelectScenario(scenario); }}
                        style={{ animationDelay: `${(idx + 1) * 0.03}s` }}
                    >
                        {scenario.source === 'community' && <span className="scenario-community-badge">Community</span>}
                        {scenario.source === 'community' && (
                            <button
                                className="scenario-report-btn"
                                title="Report scenario"
                                onClick={(e) => {
                                    e.stopPropagation();
                                    setReportTarget({ id: scenario.id, title: getTitle(scenario) });
                                    setReportReason('');
                                    setReportStatus(null);
                                }}
                            >
                                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                    <path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"></path>
                                    <line x1="4" y1="22" x2="4" y2="15"></line>
                                </svg>
                            </button>
                        )}
                        <div className="scenario-card-title">{getTitle(scenario)}</div>
                        <div className="scenario-card-subtitle">{getSubtitle(scenario)}</div>
                        {scenario.startDate && <div className="scenario-card-date">{formatDate(scenario.startDate)}</div>}
                        <div className="scenario-card-desc">{getDesc(scenario)}</div>
                        <div className="scenario-card-footer">
                            <span className="scenario-card-plays">{getPlays(scenario)} plays</span>
                            {getWinRate(scenario) !== null && (
                                <span className={`scenario-card-winrate ${getWinRate(scenario) <= 20 ? 'winrate-hard' : getWinRate(scenario) <= 50 ? 'winrate-medium' : 'winrate-easy'}`}>
                                    {getWinRate(scenario)}% win
                                </span>
                            )}
                        </div>
                    </button>
                    );
                })}
            </div>

            {sorted.length === 0 && (
                <div className="scenario-empty">
                    No scenarios found
                </div>
            )}

            {reportTarget && (
                <div className="report-modal-overlay" onClick={() => { if (reportStatus !== 'sending') setReportTarget(null); }}>
                    <div className="report-modal" onClick={e => e.stopPropagation()}>
                        {reportStatus === 'done' ? (
                            <React.Fragment>
                                <div className="report-modal-title">Reported</div>
                                <p className="report-modal-desc">Thank you for your report. We will review this scenario.</p>
                                <div className="report-modal-actions">
                                    <button className="report-modal-btn report-modal-cancel" onClick={() => setReportTarget(null)}>Close</button>
                                </div>
                            </React.Fragment>
                        ) : (
                            <React.Fragment>
                                <div className="report-modal-title">Report scenario</div>
                                <p className="report-modal-desc">Report "{reportTarget.title}" for inappropriate content.</p>
                                <textarea
                                    className="report-modal-input"
                                    placeholder="Reason (optional)"
                                    value={reportReason}
                                    onChange={e => setReportReason(e.target.value)}
                                    maxLength={200}
                                    rows={3}
                                />
                                {reportStatus === 'error' && <div className="report-modal-error">Failed to submit report. Please try again.</div>}
                                {reportStatus === 'duplicate' && <div className="report-modal-error">You have already reported this scenario.</div>}
                                <div className="report-modal-actions">
                                    <button className="report-modal-btn report-modal-cancel" onClick={() => setReportTarget(null)} disabled={reportStatus === 'sending'}>Cancel</button>
                                    <button
                                        className="report-modal-btn report-modal-submit"
                                        disabled={reportStatus === 'sending'}
                                        onClick={() => {
                                            setReportStatus('sending');
                                            firebaseClient.callFunction('reportScenario', { scenarioId: reportTarget.id, reason: reportReason.trim() })
                                                .then(() => setReportStatus('done'))
                                                .catch(err => {
                                                    if (err?.message?.includes('already-exists')) setReportStatus('duplicate');
                                                    else setReportStatus('error');
                                                });
                                        }}
                                    >
                                        {reportStatus === 'sending' ? 'Sending...' : 'Submit'}
                                    </button>
                                </div>
                            </React.Fragment>
                        )}
                    </div>
                </div>
            )}
        </div>
    );
}

function GameOverBanner({ epitaph, turn, playerTheme, shareSummary, achievements, isVictory, scenarioId, gameId, published, customScenario }) {
    const [ladderData, setLadderData] = React.useState(null);
    const [ladderLoading, setLadderLoading] = React.useState(false);
    const [publishState, setPublishState] = React.useState(published ? 'published' : null); // null | 'confirm' | 'publishing' | 'published' | 'error'
    const [publishError, setPublishError] = React.useState(null);

    const GAME_URL = 'https://risk-beta.com';

    // Fetch scenario ranking on mount
    React.useEffect(() => {
        const sid = scenarioId || playerTheme;
        if (!sid) return;
        setLadderLoading(true);
        firebaseClient.callFunction('getLadder', { scenarioId: sid })
            .then(setLadderData)
            .catch(err => console.warn('[Ladder] Failed to load:', err))
            .finally(() => setLadderLoading(false));
    }, [scenarioId, playerTheme]);

    const achievementCount = achievements?.length || 0;

    // Build share card text
    const buildShareCard = () => {
        const lines = [];
        if (isVictory) {
            lines.push(`I conquered "${playerTheme || 'Unknown'}" in ${turn} turn${turn !== 1 ? 's' : ''} 🏆`);
        } else {
            lines.push(`I survived ${turn} turn${turn !== 1 ? 's' : ''} in "${playerTheme || 'Unknown'}" 💀`);
        }
        if (shareSummary) {
            lines.push('');
            lines.push(shareSummary);
        } else if (epitaph) {
            lines.push('');
            lines.push(`"${epitaph}"`);
        }
        lines.push('');
        lines.push(`Can you do better? ${GAME_URL}`);
        return lines.join('\n');
    };

    const shareText = buildShareCard();

    const handleShareX = () => {
        const url = `https://twitter.com/intent/tweet?text=${encodeURIComponent(shareText)}`;
        window.open(url, '_blank', 'width=550,height=420');
        if (typeof gtag === 'function') {
            gtag('event', 'share_click', { method: 'twitter', turn, theme: playerTheme });
        }
    };

    return (
        <div className={`game-over-banner${isVictory ? ' game-over-victory' : ''}`}>
            <div className="game-over-text" style={isVictory ? { color: 'var(--color-success)' } : undefined}>
                {isVictory ? 'VICTORY' : 'GAME OVER'}
            </div>
            <div className="game-over-turns" style={isVictory ? { color: 'var(--color-success)' } : undefined}>in {turn || 0} turn{(turn || 0) !== 1 ? 's' : ''}</div>

            {ladderLoading ? (
                <div className="game-over-ranking-loading">Loading ranking...</div>
            ) : ladderData?.entries?.length > 0 && (() => {
                const myEntry = ladderData.entries.find(e => e.isCurrentUser);
                const myRank = myEntry ? ladderData.entries.indexOf(myEntry) + 1 : null;
                const total = ladderData.entries.length;
                const topEntries = ladderData.entries.slice(0, 5);
                return (
                    <div className="game-over-ranking">
                        <div className="game-over-ranking-title">Scenario ranking</div>
                        {myRank && (
                            <div className="game-over-ranking-you">
                                You are ranked <strong>#{myRank}</strong> out of {total} player{total > 1 ? 's' : ''}
                            </div>
                        )}
                        <div className="game-over-ranking-table">
                            {topEntries.map((entry, idx) => (
                                <div key={idx} className={`game-over-ranking-row${entry.isCurrentUser ? ' game-over-ranking-row--you' : ''}`}>
                                    <span className="game-over-ranking-pos">#{idx + 1}</span>
                                    <span className="game-over-ranking-tag">{entry.playerTag}</span>
                                    <span className="game-over-ranking-detail">{entry.wins} win{entry.wins > 1 ? 's' : ''} · avg {entry.avgTurns} · best {entry.bestTurns}</span>
                                </div>
                            ))}
                            {myRank && myRank > 5 && (
                                <React.Fragment>
                                    <div className="game-over-ranking-row game-over-ranking-row--ellipsis">···</div>
                                    <div className="game-over-ranking-row game-over-ranking-row--you">
                                        <span className="game-over-ranking-pos">#{myRank}</span>
                                        <span className="game-over-ranking-tag">{myEntry.playerTag}</span>
                                        <span className="game-over-ranking-detail">{myEntry.wins} win{myEntry.wins > 1 ? 's' : ''} · avg {myEntry.avgTurns} · best {myEntry.bestTurns}</span>
                                    </div>
                                </React.Fragment>
                            )}
                        </div>
                    </div>
                );
            })()}

            <div className="game-over-actions">
                <button className="game-over-share-x" onClick={handleShareX}>
                    Share on
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
                        <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
                    </svg>
                </button>
                {isVictory && scenarioId && scenarioId.startsWith('custom') && gameId && publishState !== 'published' && publishState !== 'confirm' && (
                    <button
                        className="game-over-publish-btn"
                        onClick={() => { if (typeof gtag === 'function') gtag('event', 'publish_click', { scenario_id: scenarioId }); setPublishState('confirm'); }}
                    >
                        Publish to community
                    </button>
                )}
                {(publishState === 'published' || publishState === 'unpublishing') && (
                    <button
                        className="game-over-unpublish-btn"
                        disabled={publishState === 'unpublishing'}
                        onClick={() => {
                            setPublishState('unpublishing');
                            if (typeof gtag === 'function') gtag('event', 'unpublish', { scenario_id: scenarioId });
                            firebaseClient.callFunction('unpublishScenario', { gameId })
                                .then(() => setPublishState(null))
                                .catch(err => {
                                    console.error('[Unpublish] Failed:', err);
                                    setPublishState('published');
                                });
                        }}
                    >
                        {publishState === 'unpublishing' ? 'Removing...' : 'Unpublish'}
                    </button>
                )}
            </div>

            {publishState === 'confirm' && customScenario && (
                <div className="publish-confirm-overlay" onClick={() => setPublishState(null)}>
                    <div className="publish-confirm-modal" onClick={e => e.stopPropagation()}>
                        <h3 className="publish-confirm-title">Publish to community?</h3>
                        <p className="publish-confirm-desc">Other players will see this scenario and can play it. Here's what they'll see:</p>
                        <div className="publish-confirm-preview">
                            <div className="publish-confirm-preview-title">{customScenario.title}</div>
                            {customScenario.subtitle && <div className="publish-confirm-preview-subtitle">{customScenario.subtitle}</div>}
                            {customScenario.description && <div className="publish-confirm-preview-description">{customScenario.description}</div>}
                        </div>
                        {publishError && <div className="publish-confirm-error">{publishError}</div>}
                        <div className="publish-confirm-buttons">
                            <button className="publish-confirm-btn publish-confirm-cancel" onClick={() => { setPublishState(null); setPublishError(null); }}>
                                Cancel
                            </button>
                            <button
                                className="publish-confirm-btn publish-confirm-submit"
                                disabled={publishState === 'publishing'}
                                onClick={() => {
                                    setPublishState('publishing');
                                    setPublishError(null);
                                    if (typeof gtag === 'function') gtag('event', 'publish_confirm', { scenario_id: scenarioId });
                                    firebaseClient.callFunction('publishScenario', { gameId })
                                        .then(() => {
                                            setPublishState('published');
                                            if (typeof gtag === 'function') gtag('event', 'publish_success', { scenario_id: scenarioId });
                                        })
                                        .catch(err => {
                                            console.error('[Publish] Failed:', err);
                                            const msg = err?.message || 'Publication failed';
                                            const reason = msg.includes('permission-denied') ? 'moderation_rejected' : msg.includes('already-exists') ? 'title_exists' : 'error';
                                            if (typeof gtag === 'function') gtag('event', 'publish_error', { scenario_id: scenarioId, reason });
                                            setPublishError(reason === 'moderation_rejected' ? 'Content rejected by moderation.' : reason === 'title_exists' ? 'A scenario with this title already exists.' : 'Publication failed. Please try again.');
                                            setPublishState('confirm');
                                        });
                                }}
                            >
                                Publish
                            </button>
                        </div>
                    </div>
                </div>
            )}
        </div>
    );
}

function LadderPage() {
    const [data, setData] = React.useState(null);
    const [loading, setLoading] = React.useState(true);

    React.useEffect(() => {
        setLoading(true);
        firebaseClient.callFunction('getLadder', {})
            .then(setData)
            .catch(err => console.error('[Ladder] Failed:', err))
            .finally(() => setLoading(false));
    }, []);

    return (
        <div className="settings-page-body">
            <h1 className="settings-page-title">Ladder</h1>

            {loading ? (
                <div className="ladder-loading">Loading...</div>
            ) : !data?.entries?.length ? (
                <div className="ladder-empty">Win a scenario to see your ranking here.</div>
            ) : (
                <div className="ladder-table">
                    <div className="ladder-table-header">
                        <div className="ladder-col-name">Scenario</div>
                        <div className="ladder-col">Wins</div>
                        <div className="ladder-col">Rank</div>
                        <div className="ladder-col">My avg</div>
                        <div className="ladder-col">Global avg</div>
                        <div className="ladder-col">My best</div>
                        <div className="ladder-col">Ladder best</div>
                    </div>
                    {data.entries.map((entry, idx) => (
                        <div key={entry.id} className="ladder-table-row" style={{ animationDelay: `${idx * 0.03}s` }}>
                            <div className="ladder-col-name">{entry.playerTheme}</div>
                            <div className="ladder-col">{entry.wins}</div>
                            <div className="ladder-col ladder-col-rank">#{entry.rank}<span className="ladder-col-total">/{entry.totalPlayers}</span></div>
                            <div className="ladder-col">~{entry.avgTurns}</div>
                            <div className="ladder-col ladder-col-global">~{entry.globalAvgTurns}</div>
                            <div className="ladder-col">{entry.bestTurns}</div>
                            <div className="ladder-col ladder-col-record">{entry.globalBestTurns}</div>
                        </div>
                    ))}
                </div>
            )}
        </div>
    );
}

function AdminPage() {
    const [data, setData] = React.useState(null);
    const [loading, setLoading] = React.useState(true);
    const [removing, setRemoving] = React.useState(null);

    React.useEffect(() => {
        setLoading(true);
        firebaseClient.callFunction('getReports', {})
            .then(setData)
            .catch(err => console.error('[Admin] Failed to load reports:', err))
            .finally(() => setLoading(false));
    }, []);

    const handleRemove = (scenarioId) => {
        if (!confirm('Remove this scenario permanently?')) return;
        setRemoving(scenarioId);
        firebaseClient.callFunction('removeScenario', { scenarioId })
            .then(() => {
                setData(prev => ({ entries: prev.entries.filter(e => e.scenarioId !== scenarioId) }));
            })
            .catch(err => console.error('[Admin] Remove failed:', err))
            .finally(() => setRemoving(null));
    };

    return (
        <div className="settings-page-body">
            <h1 className="settings-page-title">Admin - Reports</h1>
            {loading ? (
                <div className="admin-loading">Loading reports...</div>
            ) : !data?.entries?.length ? (
                <div className="admin-empty">No reports.</div>
            ) : (
                <div className="admin-reports-list">
                    {data.entries.map(entry => (
                        <div key={entry.scenarioId} className="admin-report-card">
                            <div className="admin-report-header">
                                <div className="admin-report-title">{entry.title}</div>
                                <span className="admin-report-count">{entry.count} report{entry.count > 1 ? 's' : ''}</span>
                            </div>
                            <div className="admin-report-reasons">
                                {entry.reports.map((r, i) => (
                                    <div key={i} className="admin-report-reason">
                                        {r.reason || '(no reason)'}
                                        <span className="admin-report-date">{r.createdAt ? new Date(r.createdAt).toLocaleDateString() : ''}</span>
                                    </div>
                                ))}
                            </div>
                            <button
                                className="admin-remove-btn"
                                disabled={removing === entry.scenarioId}
                                onClick={() => handleRemove(entry.scenarioId)}
                            >
                                {removing === entry.scenarioId ? 'Removing...' : 'Remove scenario'}
                            </button>
                        </div>
                    ))}
                </div>
            )}
        </div>
    );
}

function SettingsPageView({ page, onClose }) {
    React.useEffect(() => {
        if (typeof gtag === 'function') gtag('event', 'settings_page_view', { page });
    }, [page]);

    const backButton = (
        <div className="settings-page-header">
            <button className="settings-page-back" onClick={onClose} aria-label="Back">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <line x1="19" y1="12" x2="5" y2="12"></line>
                    <polyline points="12 19 5 12 12 5"></polyline>
                </svg>
            </button>
        </div>
    );

    const renderPage = () => {
        if (page === 'subscription') return <SubscriptionPage />;
        if (page === 'privacy') return <PrivacyPage />;
        if (page === 'terms') return <TermsPage />;
        if (page === 'ladder') return <LadderPage />;
        if (page === 'admin') return <AdminPage />;
        return null;
    };

    return (
        <div className="settings-page">
            {backButton}
            {renderPage()}
        </div>
    );
}

function LegalSection({ title, children }) {
    return (
        <div className="legal-section">
            <h2 className="legal-section-title">{title}</h2>
            <div className="legal-section-body">{children}</div>
        </div>
    );
}

function LegalTable({ headers, rows }) {
    return (
        <div className="legal-table-wrap">
            <table className="legal-table">
                <thead>
                    <tr>{headers.map((h, i) => <th key={i}>{h}</th>)}</tr>
                </thead>
                <tbody>
                    {rows.map((row, i) => (
                        <tr key={i}>{row.map((cell, j) => <td key={j}>{cell}</td>)}</tr>
                    ))}
                </tbody>
            </table>
        </div>
    );
}

function PrivacyPage() {
    return (
        <div className="settings-page-body legal-page">
            <h1 className="settings-page-title">Privacy Policy</h1>
            <p className="legal-updated">Last updated: May 31, 2026</p>

            <LegalSection title="Data Controller">
                <p>RISK is published by Laurent Delorme. For any questions about your personal data: <strong>contact@playrisk.io</strong></p>
            </LegalSection>

            <LegalSection title="Data Collected">
                <p>We only collect data strictly necessary for the service.</p>
                <LegalTable
                    headers={['Data', 'Purpose', 'Legal Basis']}
                    rows={[
                        ['Email address', 'Authentication via Google', 'Contract performance'],
                        ['Game history', 'Save and restore your games', 'Contract performance'],
                        ['Payment data', 'Subscription management (Stripe)', 'Contract performance'],
                    ]}
                />
                <p>We do <strong>not</strong> collect browsing data, third-party cookies, or location data.</p>
            </LegalSection>

            <LegalSection title="Sub-processors">
                <LegalTable
                    headers={['Service', 'Usage', 'Location']}
                    rows={[
                        ['Firebase (Google)', 'Authentication, database, hosting', 'EU / US'],
                        ['Stripe', 'Payment and billing', 'US'],
                        ['Anthropic (Claude)', 'Game content generation', 'US'],
                    ]}
                />
            </LegalSection>

            <LegalSection title="Data Usage">
                <ul>
                    <li>Your data is used <strong>exclusively</strong> for game functionality and account management.</li>
                    <li>No data is sold, rented, or shared with third parties.</li>
                    <li>AI conversations are <strong>not</strong> used for model training.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Data Retention">
                <ul>
                    <li>Account data retained while your account is active.</li>
                    <li>Saved games retained until you delete them.</li>
                    <li>After account deletion, all data erased within 30 days.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Your Rights">
                <p>Under GDPR: access, rectify, erase, port, restrict, and object. Contact <strong>contact@playrisk.io</strong> — response within 30 days.</p>
            </LegalSection>

            <LegalSection title="Security">
                <p>Data transmitted via HTTPS, stored on secure infrastructure (Google Cloud, Stripe). Production access is restricted and audited.</p>
            </LegalSection>
        </div>
    );
}

function TermsPage() {
    return (
        <div className="settings-page-body legal-page">
            <h1 className="settings-page-title">Terms of Use</h1>
            <p className="legal-updated">Last updated: May 31, 2026</p>

            <LegalSection title="Purpose">
                <p>These Terms of Use govern access to and use of the RISK game, published by Laurent Delorme.</p>
            </LegalSection>

            <LegalSection title="Acceptance">
                <p>By creating an account or using the Service, you unconditionally accept these Terms.</p>
            </LegalSection>

            <LegalSection title="Service Description">
                <p>RISK is a fictional geopolitical simulation game for entertainment. Narrative content is AI-generated. All scenarios and events are <strong>purely fictional</strong>.</p>
            </LegalSection>

            <LegalSection title="User Account">
                <ul>
                    <li>Registration via Google authentication.</li>
                    <li>You are responsible for your account security.</li>
                    <li>One account per person.</li>
                    <li>We reserve the right to suspend any account in case of abuse.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Subscription & Payment">
                <ul>
                    <li>Access requires a paid subscription.</li>
                    <li>Payments processed by Stripe. We do not store banking information.</li>
                    <li>Monthly subscription, automatically renewable.</li>
                    <li>Cancel anytime, effective at end of current period.</li>
                    <li>No refunds for the current billing period.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Usage Limits">
                <ul>
                    <li>Each subscription includes a monthly token quota.</li>
                    <li>Additional tokens can be purchased.</li>
                    <li>Abusive, automated, or misappropriated use is prohibited.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Generated Content">
                <ul>
                    <li>AI content may contain inaccuracies. It does not constitute advice.</li>
                    <li>Games and scenarios you create belong to you.</li>
                    <li>We may use anonymized data to improve the Service.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Intellectual Property">
                <p>The code, design, RISK brand, and all Service elements are the publisher's property. Unauthorized reproduction is prohibited.</p>
            </LegalSection>

            <LegalSection title="Limitation of Liability">
                <ul>
                    <li>Service provided "as is" with no guarantee of permanent availability.</li>
                    <li>We are not liable for indirect damages.</li>
                    <li>Maintenance interruptions do not entitle compensation.</li>
                </ul>
            </LegalSection>

            <LegalSection title="Changes to Terms">
                <p>We may modify these Terms at any time. Users will be notified by email of material changes.</p>
            </LegalSection>

            <LegalSection title="Governing Law">
                <p>French law. Competent courts of Paris.</p>
            </LegalSection>

            <LegalSection title="Contact">
                <p><strong>contact@playrisk.io</strong></p>
            </LegalSection>
        </div>
    );
}

function ReferralSection() {
    const [referralInfo, setReferralInfo] = React.useState(null);
    const [loading, setLoading] = React.useState(true);
    const [copied, setCopied] = React.useState(false);
    const [manualCode, setManualCode] = React.useState('');
    const [applyError, setApplyError] = React.useState(null);
    const [applyLoading, setApplyLoading] = React.useState(false);
    const [applySuccess, setApplySuccess] = React.useState(false);

    React.useEffect(() => {
        firebaseClient.getReferralInfo()
            .then(setReferralInfo)
            .catch(() => {})
            .finally(() => setLoading(false));
    }, []);

    const handleCopy = async () => {
        const code = referralInfo?.code;
        if (!code) return;
        if (typeof gtag === 'function') gtag('event', 'referral_copy_code');
        try {
            await navigator.clipboard.writeText(code);
            setCopied(true);
            setTimeout(() => setCopied(false), 2000);
        } catch {
            const input = document.createElement('input');
            input.value = link;
            document.body.appendChild(input);
            input.select();
            document.execCommand('copy');
            document.body.removeChild(input);
            setCopied(true);
            setTimeout(() => setCopied(false), 2000);
        }
    };

    const handleApplyCode = async () => {
        const code = manualCode.trim();
        if (!code) return;
        setApplyError(null);
        setApplyLoading(true);
        if (typeof gtag === 'function') gtag('event', 'referral_apply_attempt');
        try {
            await firebaseClient.applyReferralCode(code);
            setApplySuccess(true);
            setManualCode('');
            if (typeof gtag === 'function') gtag('event', 'referral_apply_success');
            const info = await firebaseClient.getReferralInfo();
            setReferralInfo(info);
        } catch (err) {
            const msg = err.message || 'Failed to apply code';
            if (msg.includes('already have a referrer')) setApplyError('You already have a referrer.');
            else if (msg.includes('while subscribed')) setApplyError('Cannot apply referral code while subscribed.');
            else if (msg.includes('Invalid referral code') || msg.includes('not-found')) setApplyError('Invalid referral code.');
            else if (msg.includes('own referral code')) setApplyError('You cannot use your own code.');
            else setApplyError(msg);
            if (typeof gtag === 'function') gtag('event', 'referral_apply_error', { error: msg.slice(0, 100) });
        } finally {
            setApplyLoading(false);
        }
    };

    if (loading) return null;

    const code = referralInfo?.code;
    const locked = !!referralInfo?.locked;
    const referrals = referralInfo?.referrals || [];
    const rewarded = referrals.filter(r => r.status === 'rewarded').length;
    const pending = referrals.filter(r => r.status === 'pending').length;
    const hasReferrer = !!referralInfo?.referredBy;

    return (
        <div className="ref-section">
            <h2 className="sub-packs-title">Invite friends</h2>
            <div className="ref-card">
                <div className="ref-description">
                    Invite your friends and you both win:
                </div>
                <div className="ref-rewards">
                    <div className="ref-reward-item">
                        <span className="ref-reward-icon">You</span>
                        <span className="ref-reward-text">Earn <strong>5M tokens</strong> (1 free month) when your friend subscribes to Premium</span>
                    </div>
                    <div className="ref-reward-item">
                        <span className="ref-reward-icon">Friend</span>
                        <span className="ref-reward-text">Gets <strong>500k tokens</strong> free when they subscribe to Premium</span>
                    </div>
                </div>

                {locked && (
                    <div className="ref-locked">Subscribe to Premium to unlock your referral code.</div>
                )}

                {code && (
                    <div className="ref-link-row">
                        <div className="ref-code-box">{code}</div>
                        <button className="ref-copy-btn" onClick={handleCopy}>
                            {copied ? 'Copied!' : 'Copy code'}
                        </button>
                    </div>
                )}

                {(rewarded > 0 || pending > 0) && (
                    <div className="ref-stats">
                        {rewarded > 0 && (
                            <div className="ref-stat">
                                <span className="ref-stat-number">{rewarded}</span>
                                <span className="ref-stat-label">rewarded</span>
                            </div>
                        )}
                        {pending > 0 && (
                            <div className="ref-stat">
                                <span className="ref-stat-number">{pending}</span>
                                <span className="ref-stat-label">pending</span>
                            </div>
                        )}
                    </div>
                )}
            </div>

            {locked && !hasReferrer && !applySuccess && (
                <div className="ref-apply">
                    <div className="ref-apply-label">Have a referral code? Enter it and get <strong>500k free tokens</strong> when you subscribe to Premium.</div>
                    <div className="ref-apply-row">
                        <input
                            className="ref-apply-input"
                            type="text"
                            placeholder="Enter code"
                            value={manualCode}
                            onChange={(e) => setManualCode(e.target.value.toUpperCase())}
                            maxLength={8}
                        />
                        <button
                            className="ref-apply-btn"
                            onClick={handleApplyCode}
                            disabled={applyLoading || !manualCode.trim()}
                        >
                            {applyLoading ? '...' : 'Apply'}
                        </button>
                    </div>
                    {applyError && <div className="ref-apply-error">{applyError}</div>}
                </div>
            )}
            {applySuccess && (
                <div className="ref-apply-success">Referral code applied — you'll get 500k free tokens after you subscribe to Premium!</div>
            )}
        </div>
    );
}

function SubscriptionPage() {
    const [profile, setProfile] = React.useState(null);
    const [loading, setLoading] = React.useState(true);
    const [actionLoading, setActionLoading] = React.useState(false);
    const [error, setError] = React.useState(null);
    const [ledger, setLedger] = React.useState([]);

    React.useEffect(() => {
        // Use cached profile for instant render, then refresh in background
        const cached = firebaseClient.getCachedProfile();
        if (cached) {
            setProfile(cached);
            setLoading(false);
        }
        firebaseClient.getUserProfile().then(p => {
            setProfile(p);
            setLoading(false);
        }).catch(() => setLoading(false));
        firebaseClient.loadPurchaseHistory().then(setLedger).catch(() => {});
    }, []);

    const handleSubscribe = async () => {
        setError(null);
        setActionLoading('subscribe');
        if (typeof gtag === 'function') gtag('event', 'subscription_start');
        try {
            await firebaseClient.subscribe();
        } catch (err) {
            console.error('Checkout failed:', err);
            setError(err.message || 'Checkout failed');
            setActionLoading(false);
        }
    };

    const handleManage = async () => {
        setActionLoading('manage');
        if (typeof gtag === 'function') gtag('event', 'manage_subscription_click');
        try {
            await firebaseClient.manageSubscription();
        } catch (err) {
            console.error('Portal failed:', err);
            if (typeof gtag === 'function') gtag('event', 'manage_subscription_error', { error: err.message?.slice(0, 100) });
            setActionLoading(false);
        }
    };

    const handleBuyPack = async (packKey) => {
        setError(null);
        setActionLoading(packKey);
        if (typeof gtag === 'function') gtag('event', 'token_pack_purchase', { pack: packKey });
        try {
            await firebaseClient.buyTokenPack(packKey);
        } catch (err) {
            console.error('Token pack purchase failed:', err);
            setError(err.message || 'Purchase failed');
            setActionLoading(false);
        }
    };

    if (loading) {
        return (
            <div className="settings-page-body">
                <h1 className="settings-page-title">Tokens</h1>
                <div className="sub-loading">Loading...</div>
            </div>
        );
    }

    const sub = profile?.subscription || {};
    const usage = profile?.usage || {};
    const status = sub.status || 'inactive';
    const isSubscribed = status === 'active';
    const tokenLimit = sub.tokenLimit || 0;
    const tokensUsed = usage.tokensUsed || 0;
    const bonusTokens = usage.bonusTokens || 0;

    const formatTokens = (n) => {
        if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
        if (n >= 1000) return Math.round(n / 1000) + 'k';
        return String(n);
    };

    return (
        <div className="settings-page-body">
            <h1 className="settings-page-title">Tokens</h1>
            <p className="sub-page-intro">
                Each turn you play consumes tokens.
            </p>

            {(() => {
                const subRemaining = isSubscribed ? Math.max(0, tokenLimit - tokensUsed) : 0;
                const totalAvailable = subRemaining + bonusTokens;
                const remainingPercent = tokenLimit > 0 ? Math.max(0, Math.min(100, Math.round((subRemaining / tokenLimit) * 100))) : 0;
                return (
                    <div className={`sub-usage-section${totalAvailable <= 0 ? ' sub-usage-danger' : ''}`}>
                        <div className="sub-usage-header" style={{ marginBottom: 0 }}>
                            <span>Tokens available</span>
                            <span className="sub-usage-numbers" style={totalAvailable <= 0 ? { color: 'var(--color-danger)' } : undefined}>
                                {formatTokens(totalAvailable)}
                            </span>
                        </div>
                        {bonusTokens > 0 && (
                            <div className="sub-usage-subnote">incl. {formatTokens(bonusTokens)} from packs &amp; rewards — these never reset</div>
                        )}
                        {isSubscribed && (
                            <>
                                <div className="sub-usage-header" style={{ marginTop: 14 }}>
                                    <span>Monthly plan</span>
                                    <span className="sub-usage-numbers">{formatTokens(subRemaining)} <span className="sub-usage-turns">of {formatTokens(tokenLimit)} left</span></span>
                                </div>
                                <div className="sub-usage-bar">
                                    <div className="sub-usage-fill" style={{ width: (100 - remainingPercent) + '%', background: 'rgba(255, 45, 45, 0.75)' }} />
                                </div>
                                {sub.currentPeriodEnd && (
                                    <div className="sub-usage-recharge">
                                        Refills to {formatTokens(tokenLimit)} on {new Date(sub.currentPeriodEnd).toLocaleDateString('en-US', { day: 'numeric', month: 'long' })}
                                    </div>
                                )}
                            </>
                        )}
                    </div>
                );
            })()}

            {error && (
                <div style={{ color: 'var(--color-danger)', fontSize: '13px', padding: '8px 12px', background: 'rgba(239,68,68,0.1)', border: '1px solid rgba(239,68,68,0.2)', borderRadius: '8px', marginBottom: '12px' }}>
                    {error}
                </div>
            )}

            <div className="sub-packs-section">
                <h2 className="sub-packs-title">Tokens</h2>
                <div className="sub-packs-grid">
                    {[
                        { key: 'starter', tokens: '100k', price: '$0.99' },
                        { key: 'small', tokens: '500k', price: '$4.49', save: '+10%' },
                        { key: 'medium', tokens: '1.5M', price: '$12.49', save: '+20%' },
                        { key: 'large', tokens: '4M', price: '$29.99', save: '+30%' },
                    ].map(pack => (
                        <button
                            key={pack.key}
                            className="sub-pack-card"
                            onClick={() => handleBuyPack(pack.key)}
                            disabled={!!actionLoading}
                        >
                            <div className="sub-pack-tokens">{pack.tokens}</div>
                            <div className="sub-pack-label">tokens</div>
                            <div className="sub-pack-price">{pack.price}</div>
                            {pack.save && <div className="sub-pack-save">{pack.save} tokens / $</div>}
                            {pack.tag && <div className="sub-pack-save">{pack.tag}</div>}
                            {actionLoading === pack.key && (
                                <div className="sub-pack-loading">Redirecting...</div>
                            )}
                        </button>
                    ))}
                </div>
            </div>

            <h2 className="sub-packs-title">Subscriptions</h2>

            {isSubscribed ? (
                <>
                    <div className="sub-plan-card">
                        <div className="sub-plan-header">
                            <div className="sub-plan-name">PREMIUM</div>
                            <div className="sub-plan-badge">Active</div>
                        </div>
                        <div className="sub-plan-price">$29.99<span> / month</span></div>
                        <ul className="sub-upgrade-features">
                            <li>5M tokens / month</li>
                            <li>+65% tokens / $ — best rate</li>
                            <li>Custom scenario creation</li>
                        </ul>
                        {sub.currentPeriodEnd && (
                            <div className="sub-plan-renew">
                                Renews: {new Date(sub.currentPeriodEnd).toLocaleDateString('en-US', { day: 'numeric', month: 'long', year: 'numeric' })}
                            </div>
                        )}
                    </div>

                    <button className="sub-manage-btn" onClick={handleManage} disabled={!!actionLoading}>
                        {actionLoading === 'manage' ? 'Redirecting...' : 'Manage subscription'}
                    </button>
                </>
            ) : (
                <div className="sub-upgrade">
                    <div className="sub-upgrade-card sub-upgrade-card-premium">
                        <div className="sub-upgrade-badge">Best value</div>
                        <div className="sub-upgrade-title">PREMIUM</div>
                        <div className="sub-upgrade-price">$29.99<span> / month</span></div>
                        <ul className="sub-upgrade-features">
                            <li>5M tokens / month</li>
                            <li>+65% tokens / $ — best rate</li>
                            <li>Custom scenario creation</li>
                        </ul>
                        <button className="sub-upgrade-btn sub-upgrade-btn-premium" onClick={handleSubscribe} disabled={!!actionLoading}>
                            {actionLoading === 'subscribe' ? 'Redirecting...' : 'Subscribe'}
                        </button>
                    </div>
                </div>
            )}

            <ReferralSection />

            {ledger.length > 0 && (
                <div className="sub-history-section">
                    <h2 className="sub-packs-title">History</h2>
                    <div className="sub-history-list">
                        {ledger.map(entry => {
                            const date = entry.createdAt?.toDate ? entry.createdAt.toDate() : new Date(entry.createdAt);
                            const dateStr = date.toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' });

                            let label, detail;
                            switch (entry.type) {
                                case 'subscription_update':
                                    label = entry.status === 'active' ? 'Subscription activated' : 'Subscription updated';
                                    break;
                                case 'subscription_canceled':
                                    label = 'Subscription canceled';
                                    break;
                                case 'token_pack_purchase':
                                    label = 'Token pack purchase';
                                    detail = `+${formatTokens(entry.tokens)} tokens`;
                                    break;
                                case 'payment_failed':
                                    label = 'Payment failed';
                                    break;
                                case 'referral_reward':
                                    label = 'Referral reward';
                                    detail = `+${formatTokens(entry.tokens)} tokens`;
                                    break;
                                default:
                                    label = entry.type;
                            }

                            return (
                                <div key={entry.id} className="sub-history-row">
                                    <span className="sub-history-date">{dateStr}</span>
                                    <span className="sub-history-label">{label}</span>
                                    {detail && <span className="sub-history-detail">{detail}</span>}
                                </div>
                            );
                        })}
                    </div>
                </div>
            )}
        </div>
    );
}

function AutoResizeTextarea({ value, onChange, ...props }) {
    const textareaRef = useRef(null);

    useEffect(() => {
        const textarea = textareaRef.current;
        if (textarea) {
            textarea.style.height = 'auto';
            textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
        }
    }, [value]);

    return (
        <textarea
            ref={textareaRef}
            value={value}
            onChange={onChange}
            rows={1}
            style={{ minHeight: '40px', maxHeight: '120px', overflowY: 'auto', resize: 'none' }}
            {...props}
        />
    );
}
