import React, { useEffect, useMemo, useRef, useState } from 'react';
import {
    deleteHistory, getHistory, getLatest, getStats, recommend,
    getBestPicks, getAnalysis, triggerSimulate,
    getPerformanceStats, getLatestReport, getReportHistory,
    getPersonalAnalysis, getPurchases, getPurchaseStats,
    addPurchase, updatePurchase, deletePurchase,
    getCombinedRecommend, getCombinedHistory,
} from '../../api';

/* ─────────────────────────────────────────────
   공통 유틸
───────────────────────────────────────────── */
const fmtKST = (value) => value?.replace('T', ' ') ?? '';

const fmtWon = (n) => {
    if (n == null || isNaN(Number(n))) return '-';
    return new Intl.NumberFormat('ko-KR').format(Math.round(Number(n))) + '원';
};

const ballClass = (n) => {
    if (n <= 10) return 'lotto-ball range-a';
    if (n <= 20) return 'lotto-ball range-b';
    if (n <= 30) return 'lotto-ball range-c';
    if (n <= 40) return 'lotto-ball range-d';
    return 'lotto-ball range-e';
};

const Ball = ({ n }) => <span className={ballClass(n)}>{n}</span>;

const NumberRow = ({ nums }) => (
    <div className="lotto-row">
        {nums.map((n) => <Ball key={n} n={n} />)}
    </div>
);

/* ─────────────────────────────────────────────
   기존 통계 헬퍼
───────────────────────────────────────────── */
const bucketOrder = ['1-10', '11-20', '21-30', '31-40', '41-45'];
const STATS_CACHE_KEY = 'lotto_stats_v1';
const BEST_PICKS_DEFAULT_SHOW = 5;

const readStatsCache = () => {
    if (typeof window === 'undefined') return null;
    try {
        const raw = localStorage.getItem(STATS_CACHE_KEY);
        if (!raw) return null;
        const parsed = JSON.parse(raw);
        if (!parsed || !Array.isArray(parsed.frequency)) return null;
        return parsed;
    } catch { return null; }
};

const writeStatsCache = (data) => {
    if (typeof window === 'undefined') return;
    try { localStorage.setItem(STATS_CACHE_KEY, JSON.stringify(data)); } catch {}
};

const buildFrequencySeries = (frequency) => {
    const map = new Map();
    (frequency ?? []).forEach((item) => {
        const number = Number(item?.number);
        const count = Number(item?.count) || 0;
        if (Number.isFinite(number) && number >= 1 && number <= 45) map.set(number, count);
    });
    const series = Array.from({ length: 45 }, (_, idx) => ({
        number: idx + 1, count: map.get(idx + 1) ?? 0,
    }));
    const max = Math.max(1, ...series.map((item) => item.count));
    return { series, max };
};

const buildMetricsFromCounts = (counts) => {
    if (!counts?.length) return null;
    const total = counts.reduce((acc, v) => acc + v, 0);
    if (!total) return null;
    const min = Math.min(...counts), max = Math.max(...counts);
    const odd = counts.reduce((acc, v, idx) => (idx % 2 === 0 ? acc + v : acc), 0);
    const even = total - odd;
    const buckets = {
        '1-10': counts.slice(0, 10).reduce((a, b) => a + b, 0),
        '11-20': counts.slice(10, 20).reduce((a, b) => a + b, 0),
        '21-30': counts.slice(20, 30).reduce((a, b) => a + b, 0),
        '31-40': counts.slice(30, 40).reduce((a, b) => a + b, 0),
        '41-45': counts.slice(40, 45).reduce((a, b) => a + b, 0),
    };
    return { sum: total, min, max, range: max - min, odd, even, buckets };
};

const buildMetricsFromFrequency = (frequency) => {
    if (!frequency?.length) return null;
    const counts = Array.from({ length: 45 }, () => 0);
    frequency.forEach((item) => {
        const number = Number(item?.number), count = Number(item?.count) || 0;
        if (number >= 1 && number <= 45) counts[number - 1] = count;
    });
    return buildMetricsFromCounts(counts);
};

const buildMetricsFromHistory = (items) => {
    if (!items?.length) return null;
    const counts = Array.from({ length: 45 }, () => 0);
    items.forEach((item) => {
        (item?.numbers ?? []).forEach((value) => {
            const number = Number(value);
            if (number >= 1 && number <= 45) counts[number - 1] += 1;
        });
    });
    return buildMetricsFromCounts(counts);
};

const toBucketEntries = (metrics) => {
    if (!metrics?.buckets) return [];
    const ordered = bucketOrder
        .filter((key) => Object.prototype.hasOwnProperty.call(metrics.buckets, key))
        .map((key) => [key, metrics.buckets[key]]);
    const rest = Object.entries(metrics.buckets)
        .filter(([key]) => !bucketOrder.includes(key))
        .sort((a, b) => Number(a[0].split('-')[0]) - Number(b[0].split('-')[0]));
    return [...ordered, ...rest];
};

/* ─────────────────────────────────────────────
   SubComponents — 기존
───────────────────────────────────────────── */
const MetricBlock = ({ title, metrics }) => {
    if (!metrics) return null;
    const buckets = toBucketEntries(metrics);
    const maxBucket = buckets.length ? Math.max(...buckets.map(([, v]) => Number(v) || 0), 1) : 1;
    const odd = Number(metrics.odd) || 0;
    const even = Number(metrics.even) || 0;
    const totalOE = odd + even || 1;
    const oddPct = (odd / totalOE) * 100;

    return (
        <div className="lotto-metrics">
            <div className="lotto-metrics__head">
                <p className="lotto-metrics__title">{title}</p>
                <span className="lotto-metrics__sum">총 출현 횟수 {metrics.sum ?? '-'}</span>
            </div>
            <div className="lotto-metric-cards">
                <div className="lotto-metric-card">
                    <p className="lotto-metric-card__label">최소 출현</p>
                    <p className="lotto-metric-card__value">{metrics.min ?? '-'}</p>
                </div>
                <div className="lotto-metric-card">
                    <p className="lotto-metric-card__label">최대 출현</p>
                    <p className="lotto-metric-card__value">{metrics.max ?? '-'}</p>
                </div>
                <div className="lotto-metric-card">
                    <p className="lotto-metric-card__label">출현 편차</p>
                    <p className="lotto-metric-card__value">{metrics.range ?? '-'}</p>
                </div>
            </div>
            <div className="lotto-odd-even">
                <div className="lotto-odd-even__labels">
                    <span>홀 {odd}</span><span>짝 {even}</span>
                </div>
                <div className="lotto-odd-even__bar" aria-hidden>
                    <span className="lotto-odd-even__odd" style={{ width: `${oddPct}%` }} />
                    <span className="lotto-odd-even__even" style={{ width: `${100 - oddPct}%` }} />
                </div>
            </div>
            {buckets.length ? (
                <div className="lotto-buckets">
                    {buckets.map(([label, value]) => (
                        <div key={label} className="lotto-bucket">
                            <span className="lotto-bucket__label">{label}</span>
                            <div className="lotto-bucket__bar" aria-hidden>
                                <span style={{ width: `${((Number(value) || 0) / maxBucket) * 100}%` }} />
                            </div>
                            <span className="lotto-bucket__value">{value}</span>
                        </div>
                    ))}
                </div>
            ) : null}
        </div>
    );
};

const FrequencyChart = ({ stats }) => {
    const { series, max } = useMemo(() => buildFrequencySeries(stats?.frequency), [stats]);
    const ticks = useMemo(() => [max, Math.round(max * 0.5), 0], [max]);
    if (!stats) return null;

    return (
        <div className="lotto-chart">
            <div className="lotto-chart__y">
                <span>횟수</span>
                <div className="lotto-chart__ticks">
                    {ticks.map((value) => <span key={value}>{value}</span>)}
                </div>
            </div>
            <div className="lotto-chart__plot" role="list">
                {series.map((item) => {
                    const showLabel = item.number === 1 || item.number % 5 === 0;
                    return (
                        <div key={item.number} className="lotto-chart__col" role="listitem">
                            <span
                                className="lotto-chart__bar"
                                style={{ height: `${(item.count / max) * 100}%` }}
                                title={`${item.number}번: ${item.count}회`}
                                aria-label={`${item.number}번 ${item.count}회`}
                            />
                            <span className="lotto-chart__x" aria-hidden={!showLabel}>
                                {showLabel ? item.number : ''}
                            </span>
                        </div>
                    );
                })}
            </div>
        </div>
    );
};

/* ─────────────────────────────────────────────
   SubComponents — 신규
───────────────────────────────────────────── */

/* 신뢰도 배너 */
const PerformanceBanner = ({ perf }) => {
    if (!perf || perf.total_checked === 0) return null;
    const imp = perf.vs_random?.improvement_pct ?? 0;
    const prizeHits = (perf.by_rank?.rank_3 ?? 0) + (perf.by_rank?.rank_4 ?? 0) + (perf.by_rank?.rank_5 ?? 0);
    return (
        <div className="lotto-perf-banner">
            <span className="lotto-perf-banner__label">신뢰도 지표</span>
            <div className="lotto-perf-banner__items">
                <div className="lotto-perf-banner__item">
                    <span className="lotto-perf-banner__val">{perf.total_checked}</span>
                    <span className="lotto-perf-banner__lbl">검증 회차</span>
                </div>
                <div className="lotto-perf-banner__divider" />
                <div className="lotto-perf-banner__item">
                    <span className="lotto-perf-banner__val">{(perf.avg_correct ?? 0).toFixed(1)}</span>
                    <span className="lotto-perf-banner__lbl">평균 일치수</span>
                </div>
                <div className="lotto-perf-banner__divider" />
                <div className="lotto-perf-banner__item">
                    <span className={`lotto-perf-banner__val ${imp > 0 ? 'is-pos' : ''}`}>
                        {imp > 0 ? '+' : ''}{imp.toFixed(1)}%
                    </span>
                    <span className="lotto-perf-banner__lbl">무작위 대비</span>
                </div>
                <div className="lotto-perf-banner__divider" />
                <div className="lotto-perf-banner__item">
                    <span className="lotto-perf-banner__val">
                        {((perf.rate_3plus ?? 0) * 100).toFixed(1)}%
                    </span>
                    <span className="lotto-perf-banner__lbl">3개↑ 일치율</span>
                </div>
                {prizeHits > 0 && (
                    <>
                        <div className="lotto-perf-banner__divider" />
                        <div className="lotto-perf-banner__item">
                            <span className="lotto-perf-banner__val is-prize">{prizeHits}건</span>
                            <span className="lotto-perf-banner__lbl">3~5등 당첨</span>
                        </div>
                    </>
                )}
            </div>
        </div>
    );
};

/* 신뢰도 링 SVG */
const ConfidenceRing = ({ score }) => {
    const r = 28, c = 2 * Math.PI * r;
    const fill = (score / 100) * c;
    const color = score >= 80 ? '#97c9aa' : score >= 60 ? '#fdd4b1' : '#f7a8a5';
    return (
        <svg width="72" height="72" viewBox="0 0 72 72" className="lotto-confidence-ring" aria-hidden>
            <circle cx="36" cy="36" r={r} stroke="rgba(255,255,255,0.08)" strokeWidth="6" fill="none" />
            <circle
                cx="36" cy="36" r={r}
                stroke={color} strokeWidth="6" fill="none"
                strokeDasharray={`${fill} ${c - fill}`}
                strokeLinecap="round"
                transform="rotate(-90 36 36)"
            />
            <text x="36" y="41" textAnchor="middle" fill={color} fontSize="16" fontWeight="600"
                style={{ fontFamily: 'inherit' }}>
                {score}
            </text>
        </svg>
    );
};

/* ─────────────────────────────────────────────
   종합 추론 추천 패널
───────────────────────────────────────────── */
const METHOD_META = {
    frequency:   { label: '빈도 Z-score',  desc: '역대 출현 빈도가 기댓값보다 높은 번호', color: '#818cf8', icon: '📊' },
    fingerprint: { label: '조합 지문',     desc: '역대 당첨 조합의 합계·홀짝·구간 분포에 맞는 번호', color: '#fbbf24', icon: '🔏' },
    gap:         { label: '갭 분석',       desc: '가장 오래 등장하지 않은 오버듀 번호', color: '#34d399', icon: '⏳' },
    cooccur:     { label: '공동 출현',     desc: '역대에 함께 출현한 빈도가 높은 번호', color: '#f472b6', icon: '🔗' },
    diversity:   { label: '다양성',        desc: '구간 커버리지와 번호 범위를 극대화한 번호', color: '#fb923c', icon: '🌈' },
};
const METHOD_ORDER = ['fingerprint', 'frequency', 'gap', 'cooccur', 'diversity'];
const SCORE_META = [
    { key: 'score_fingerprint', label: '조합 지문',  color: '#fbbf24', weight: 30 },
    { key: 'score_frequency',   label: '빈도 Z',     color: '#818cf8', weight: 25 },
    { key: 'score_gap',         label: '갭 분석',    color: '#34d399', weight: 20 },
    { key: 'score_cooccur',     label: '공동 출현',  color: '#f472b6', weight: 15 },
    { key: 'score_diversity',   label: '다양성',     color: '#fb923c', weight: 10 },
];

const CombinedRecommendPanel = ({ combined, history, loading, histLoading, onRun, onCopy }) => {
    const [histExpand, setHistExpand] = useState(false);

    return (
        <section className="lotto-panel lotto-panel--wide lotto-combined">
            <div className="lotto-panel__head">
                <div>
                    <p className="lotto-panel__eyebrow">AI · 종합 추론</p>
                    <h3>종합 추론 번호 추천</h3>
                    <p className="lotto-panel__sub">
                        5가지 통계 기법(빈도·지문·갭·공동출현·다양성)을 가중 투표로 합산해
                        최적 6개 번호를 도출합니다.
                    </p>
                </div>
                <div className="lotto-panel__actions">
                    {loading && <span className="lotto-chip">분석 중…</span>}
                    <button className="button primary small" onClick={onRun} disabled={loading}>
                        {loading ? '추론 중…' : '🔮 종합 추론 실행'}
                    </button>
                    {history.length > 0 && (
                        <button className="button ghost small" onClick={() => setHistExpand(p => !p)}>
                            이력 {history.length}건 {histExpand ? '▲' : '▼'}
                        </button>
                    )}
                </div>
            </div>

            {!combined && !loading && (
                <p className="lotto-empty">버튼을 눌러 종합 추론을 실행하세요.</p>
            )}

            {combined && (
                <>
                    {/* 기법별 추천 번호 */}
                    <div className="lotto-combined__methods">
                        {METHOD_ORDER.map((key) => {
                            const meta = METHOD_META[key];
                            const m = combined.methods?.[key];
                            if (!m) return null;
                            return (
                                <div key={key} className="lotto-combined__method">
                                    <div className="lotto-combined__method-head">
                                        <span className="lotto-combined__method-icon">{meta.icon}</span>
                                        <div>
                                            <p className="lotto-combined__method-name" style={{ color: meta.color }}>
                                                {meta.label}
                                                <span className="lotto-combined__method-weight"> ({m.weight_pct}%)</span>
                                            </p>
                                            <p className="lotto-combined__method-desc">{meta.desc}</p>
                                        </div>
                                    </div>
                                    <div className="lotto-combined__method-nums">
                                        {m.numbers.map((n) => {
                                            const inFinal = combined.final_numbers.includes(n);
                                            return (
                                                <span
                                                    key={n}
                                                    className={`lotto-ball ${ballClass(n).replace('lotto-ball ', '')} ${inFinal ? 'is-final' : 'is-dim'}`}
                                                >
                                                    {n}
                                                </span>
                                            );
                                        })}
                                    </div>
                                </div>
                            );
                        })}
                    </div>

                    {/* 최종 추론 결과 */}
                    <div className="lotto-combined__final">
                        <div className="lotto-combined__final-head">
                            <span className="lotto-combined__final-badge">종합 추론 결과</span>
                            {combined.deduped && (
                                <span className="lotto-chip lotto-chip--muted">중복 (이미 저장됨)</span>
                            )}
                            <button className="button ghost small" onClick={() => onCopy(combined.final_numbers)}>
                                복사
                            </button>
                        </div>
                        <div className="lotto-combined__final-balls">
                            {combined.final_numbers.map((n) => {
                                const votes = combined.vote_counts?.[String(n)] ?? 0;
                                return (
                                    <div key={n} className="lotto-combined__final-ball-wrap">
                                        <span className={ballClass(n)}>{n}</span>
                                        <span className="lotto-combined__vote-dots">
                                            {Array.from({ length: 5 }).map((_, i) => (
                                                <span key={i} className={`lotto-combined__vote-dot ${i < votes ? 'is-on' : ''}`} />
                                            ))}
                                        </span>
                                    </div>
                                );
                            })}
                        </div>
                        <p className="lotto-combined__final-sub">
                            ● 점은 해당 번호가 채택된 기법 수 (최대 5개)
                        </p>
                    </div>

                    {/* 점수 바 */}
                    <div className="lotto-combined__scores">
                        <p className="lotto-combined__scores-title">조합 품질 점수</p>
                        {SCORE_META.map(({ key, label, color, weight }) => {
                            const val = combined.scores?.[key] ?? 0;
                            const pct = Math.round(val * 100);
                            return (
                                <div key={key} className="lotto-combined__score-row">
                                    <span className="lotto-combined__score-label">{label}</span>
                                    <span className="lotto-combined__score-weight">{weight}%</span>
                                    <div className="lotto-combined__score-bar-wrap">
                                        <div
                                            className="lotto-combined__score-bar"
                                            style={{ width: `${pct}%`, background: color }}
                                        />
                                    </div>
                                    <span className="lotto-combined__score-val">{pct}</span>
                                </div>
                            );
                        })}
                        <div className="lotto-combined__score-total">
                            종합 점수 <strong>{Math.round((combined.scores?.score_total ?? 0) * 100)}</strong> / 100
                        </div>
                    </div>

                    <p className="lotto-combined__disclaimer">
                        ※ 이 추천은 역대 통계 패턴 기반 참고 자료이며, 당첨을 보장하지 않습니다.
                    </p>
                </>
            )}

            {/* 추천 이력 */}
            {histExpand && (
                <div className="lotto-combined__history">
                    <p className="lotto-combined__history-title">종합 추론 이력</p>
                    {histLoading && <p className="lotto-empty">로딩 중…</p>}
                    {history.map((item) => (
                        <div key={item.id} className="lotto-combined__history-item">
                            <div className="lotto-combined__history-meta">
                                <span>#{item.id}</span>
                                <span>{fmtKST(item.created_at)}</span>
                                <span>기준 {item.based_on_draw ?? '-'}회</span>
                            </div>
                            <NumberRow nums={item.numbers} />
                            <button className="button ghost small" onClick={() => onCopy(item.numbers)}>복사</button>
                        </div>
                    ))}
                </div>
            )}
        </section>
    );
};


/* 공략 리포트 패널 */
const ReportPanel = ({ report, history, loading, onRefresh, onSelectDrw }) => {
    const [histExpand, setHistExpand] = useState(false);

    return (
        <section className="lotto-panel lotto-panel--wide">
            <div className="lotto-panel__head">
                <div>
                    <p className="lotto-panel__eyebrow">Weekly Report</p>
                    <h3>이번 주 공략 리포트</h3>
                    {report && (
                        <p className="lotto-panel__sub">
                            {report.target_drw_no}회 대상 · {report.based_on_draw}회 기준
                        </p>
                    )}
                </div>
                <div className="lotto-panel__actions">
                    {loading && <span className="lotto-chip">로딩 중</span>}
                    <button className="button ghost small" onClick={onRefresh} disabled={loading}>
                        새로고침
                    </button>
                    {history?.length > 0 && (
                        <button className="button ghost small" onClick={() => setHistExpand((p) => !p)}>
                            지난 리포트 {histExpand ? '▲' : '▼'}
                        </button>
                    )}
                </div>
            </div>

            {/* 지난 리포트 목록 */}
            {histExpand && history?.length > 0 && (
                <div className="lotto-report-history">
                    {history.map((h) => (
                        <button
                            key={h.drw_no}
                            className="button ghost small"
                            onClick={() => { onSelectDrw(h.drw_no); setHistExpand(false); }}
                        >
                            {h.drw_no}회
                        </button>
                    ))}
                </div>
            )}

            {!report && !loading && (
                <p className="lotto-empty">리포트 데이터가 없습니다.</p>
            )}
            {loading && !report && (
                <p className="lotto-empty">불러오는 중...</p>
            )}

            {report && (
                <>
                    {/* 신뢰도 + 패턴 요약 */}
                    <div className="lotto-report-top">
                        <div className="lotto-report-confidence">
                            <ConfidenceRing score={report.confidence_score ?? 0} />
                            <div>
                                <p className="lotto-report-confidence__title">신뢰도 점수</p>
                                <div className="lotto-report-confidence__factors">
                                    {Object.entries(report.confidence_factors ?? {}).map(([k, v]) => (
                                        <div key={k} className="lotto-report-confidence__factor">
                                            <span className="lotto-report-confidence__factor-lbl">
                                                {k === 'data_volume' ? '데이터 충분도'
                                                    : k === 'pattern_consistency' ? '패턴 안정성'
                                                    : k === 'recent_trend' ? '최근 트렌드' : k}
                                            </span>
                                            <div className="lotto-pick__bar">
                                                <span style={{ width: `${v}%` }} />
                                            </div>
                                            <span className="lotto-report-confidence__factor-val">{v}</span>
                                        </div>
                                    ))}
                                </div>
                            </div>
                        </div>

                        <div className="lotto-report-pattern">
                            <p className="lotto-report-pattern__title">최근 패턴</p>
                            <div className="lotto-report-pattern__stats">
                                <div className="lotto-report-pattern__stat">
                                    <span>합계 평균</span>
                                    <strong>{report.recent_pattern?.recent_sum_avg?.toFixed(1) ?? '-'}</strong>
                                </div>
                                <div className="lotto-report-pattern__stat">
                                    <span>홀수 평균</span>
                                    <strong>{report.recent_pattern?.recent_odd_avg?.toFixed(1) ?? '-'}</strong>
                                </div>
                                {(report.recent_pattern?.triple_appear ?? []).length > 0 && (
                                    <div className="lotto-report-pattern__stat">
                                        <span>3회 연속 출현</span>
                                        <NumberRow nums={report.recent_pattern.triple_appear} />
                                    </div>
                                )}
                            </div>
                        </div>
                    </div>

                    {/* 핫 / 콜드 / 오버듀 */}
                    <div className="lotto-analysis__row">
                        <div className="lotto-analysis__group">
                            <p className="lotto-analysis__label">
                                🔥 핫 번호 <span>최근 10회 과출현</span>
                            </p>
                            <NumberRow nums={report.hot_numbers ?? []} />
                        </div>
                        <div className="lotto-analysis__group">
                            <p className="lotto-analysis__label">
                                🧊 콜드 번호 <span>역대 저빈도 10개</span>
                            </p>
                            <NumberRow nums={report.cold_numbers ?? []} />
                        </div>
                        <div className="lotto-analysis__group">
                            <p className="lotto-analysis__label">
                                ⏰ 오버듀 <span>가장 오래 미출현</span>
                            </p>
                            <NumberRow nums={report.overdue_numbers ?? []} />
                        </div>
                    </div>

                    {/* 전략 추천 세트 */}
                    {(report.recommended_sets ?? []).length > 0 && (
                        <div className="lotto-strategy-cards">
                            {report.recommended_sets.map((set, i) => (
                                <div key={i} className="lotto-strategy-card">
                                    <p className="lotto-strategy-card__name">{set.strategy}</p>
                                    <NumberRow nums={set.numbers} />
                                    <p className="lotto-strategy-card__desc">{set.description}</p>
                                </div>
                            ))}
                        </div>
                    )}
                </>
            )}
        </section>
    );
};

/* 개인 패턴 분석 */
const PersonalAnalysisPanel = ({ data, loading }) => {
    const zones = Object.entries(data?.pattern?.zone_avg ?? {});
    const maxZone = zones.length ? Math.max(...zones.map(([, v]) => Number(v) || 0), 1) : 1;

    return (
        <section className="lotto-panel lotto-panel--wide">
            <div className="lotto-panel__head">
                <div>
                    <p className="lotto-panel__eyebrow">My Pattern</p>
                    <h3>내 번호 패턴</h3>
                    {data && data.total_analyzed > 0 && (
                        <p className="lotto-panel__sub">총 {data.total_analyzed}회 추천 기반 분석</p>
                    )}
                </div>
            </div>

            {(loading || !data || data.total_analyzed === 0) ? (
                <p className="lotto-empty">
                    {loading ? '불러오는 중...' : '추천 이력이 없습니다.'}
                </p>
            ) : (
                <div className="lotto-analysis">
                    <div className="lotto-analysis__row">
                        <div className="lotto-analysis__group">
                            <p className="lotto-analysis__label">
                                내가 자주 선택한 번호 <span>TOP 10</span>
                            </p>
                            <NumberRow nums={data.top_picks ?? []} />
                        </div>

                        <div className="lotto-analysis__group">
                            <p className="lotto-analysis__label">선택 성향</p>
                            <div className="lotto-personal-tendency">
                                {data.vs_draw_avg?.odd_tendency && (
                                    <span className="lotto-personal-tendency__badge">
                                        {data.vs_draw_avg.odd_tendency}
                                    </span>
                                )}
                                {data.vs_draw_avg?.sum_tendency && (
                                    <span className="lotto-personal-tendency__badge">
                                        {data.vs_draw_avg.sum_tendency}
                                    </span>
                                )}
                            </div>
                            <div className="lotto-analysis__stats">
                                <span>홀수 평균 <strong>{data.pattern?.avg_odd_count?.toFixed(1)}</strong></span>
                                <span>합계 평균 <strong>{data.pattern?.avg_sum?.toFixed(1)}</strong></span>
                                <span>
                                    연속번호 포함률{' '}
                                    <strong>
                                        {((data.pattern?.consecutive_rate ?? 0) * 100).toFixed(0)}%
                                    </strong>
                                </span>
                            </div>
                        </div>

                        {zones.length > 0 && (
                            <div className="lotto-analysis__group">
                                <p className="lotto-analysis__label">구간별 선택 비율</p>
                                <div className="lotto-buckets">
                                    {zones.map(([zone, avg]) => (
                                        <div key={zone} className="lotto-bucket">
                                            <span className="lotto-bucket__label">{zone}</span>
                                            <div className="lotto-bucket__bar" aria-hidden>
                                                <span style={{ width: `${((Number(avg) || 0) / maxZone) * 100}%` }} />
                                            </div>
                                            <span className="lotto-bucket__value">{Number(avg).toFixed(1)}</span>
                                        </div>
                                    ))}
                                </div>
                            </div>
                        )}
                    </div>
                </div>
            )}
        </section>
    );
};

/* 구매 기록 패널 */
const emptyPurchaseForm = () => ({ draw_no: '', amount: 5000, sets: 5, prize: 0, note: '' });

const PurchasePanel = ({
    records, stats, loading,
    formOpen, form, formSaving, formError, editId,
    onFormOpen, onFormClose, onFormChange, onFormSubmit,
    onEditStart, onDelete,
}) => {
    const winRate = stats?.total_records > 0
        ? ((stats.prize_count / stats.total_records) * 100).toFixed(1)
        : '0.0';
    const netColor = (stats?.net ?? 0) >= 0 ? 'is-pos' : 'is-neg';

    return (
        <section className="lotto-panel lotto-panel--wide">
            <div className="lotto-panel__head">
                <div>
                    <p className="lotto-panel__eyebrow">Purchase Tracker</p>
                    <h3>구매 기록</h3>
                    <p className="lotto-panel__sub">구매 내역 기록 및 수익률 추적</p>
                </div>
                <div className="lotto-panel__actions">
                    {loading && <span className="lotto-chip">로딩 중</span>}
                    <button className="button small" onClick={onFormOpen} disabled={formOpen}>
                        + 추가
                    </button>
                </div>
            </div>

            {/* 통계 바 */}
            {stats && stats.total_records > 0 && (
                <div className="lotto-purchase-stats">
                    <div className="lotto-purchase-stat">
                        <span className="lotto-purchase-stat__val">{fmtWon(stats.total_invested)}</span>
                        <span className="lotto-purchase-stat__lbl">총 투자</span>
                    </div>
                    <div className="lotto-purchase-stat">
                        <span className="lotto-purchase-stat__val">{fmtWon(stats.total_prize)}</span>
                        <span className="lotto-purchase-stat__lbl">총 당첨금</span>
                    </div>
                    <div className="lotto-purchase-stat">
                        <span className={`lotto-purchase-stat__val ${netColor}`}>
                            {(stats.net ?? 0) >= 0 ? '+' : ''}{fmtWon(stats.net)}
                        </span>
                        <span className="lotto-purchase-stat__lbl">순손익</span>
                    </div>
                    <div className="lotto-purchase-stat">
                        <span className="lotto-purchase-stat__val">{stats.return_rate?.toFixed(1)}%</span>
                        <span className="lotto-purchase-stat__lbl">회수율</span>
                    </div>
                    <div className="lotto-purchase-stat">
                        <span className="lotto-purchase-stat__val">{winRate}%</span>
                        <span className="lotto-purchase-stat__lbl">당첨률</span>
                    </div>
                    {stats.max_prize > 0 && (
                        <div className="lotto-purchase-stat">
                            <span className="lotto-purchase-stat__val is-prize">{fmtWon(stats.max_prize)}</span>
                            <span className="lotto-purchase-stat__lbl">최대 당첨금</span>
                        </div>
                    )}
                </div>
            )}

            {/* 입력 폼 */}
            {formOpen && (
                <form className="lotto-purchase-form" onSubmit={onFormSubmit}>
                    <p className="lotto-purchase-form__title">
                        {editId != null ? '기록 수정' : '구매 기록 추가'}
                    </p>
                    <div className="lotto-purchase-form__grid">
                        <label className="lotto-field">
                            회차
                            <input
                                type="number" min={1}
                                value={form.draw_no}
                                onChange={(e) => onFormChange('draw_no', e.target.value)}
                                placeholder="예: 1181"
                                required
                            />
                        </label>
                        <label className="lotto-field">
                            구매금액
                            <input
                                type="number" step={1000} min={1000}
                                value={form.amount}
                                onChange={(e) => onFormChange('amount', Number(e.target.value))}
                            />
                        </label>
                        <label className="lotto-field">
                            세트 수
                            <input
                                type="number" min={1} max={20}
                                value={form.sets}
                                onChange={(e) => onFormChange('sets', Number(e.target.value))}
                            />
                        </label>
                        <label className="lotto-field">
                            당첨금
                            <input
                                type="number" min={0}
                                value={form.prize}
                                onChange={(e) => onFormChange('prize', Number(e.target.value))}
                            />
                        </label>
                        <label className="lotto-field lotto-purchase-form__note">
                            메모
                            <input
                                type="text"
                                value={form.note}
                                onChange={(e) => onFormChange('note', e.target.value)}
                                placeholder="예: 5등 1개"
                            />
                        </label>
                    </div>
                    {formError && (
                        <p className="lotto-empty" style={{ color: '#f9b6b1' }}>{formError}</p>
                    )}
                    <div className="lotto-purchase-form__actions">
                        <button type="button" className="button ghost small" onClick={onFormClose}>
                            취소
                        </button>
                        <button type="submit" className="button primary small" disabled={formSaving}>
                            {formSaving ? '저장 중...' : editId != null ? '수정 완료' : '추가'}
                        </button>
                    </div>
                </form>
            )}

            {/* 기록 목록 */}
            {records.length === 0 ? (
                <p className="lotto-empty">구매 기록이 없습니다.</p>
            ) : (
                <div className="lotto-purchase-list">
                    <div className="lotto-purchase-list__head">
                        <span>회차</span>
                        <span>투자금</span>
                        <span>당첨금</span>
                        <span>손익</span>
                        <span>메모</span>
                        <span />
                    </div>
                    {records.map((rec) => {
                        const net = (rec.prize ?? 0) - (rec.amount ?? 0);
                        return (
                            <div key={rec.id} className="lotto-purchase-row">
                                <span className="lotto-purchase-row__drw">{rec.draw_no}회</span>
                                <span>{fmtWon(rec.amount)}</span>
                                <span className={(rec.prize ?? 0) > 0 ? 'is-prize' : ''}>
                                    {fmtWon(rec.prize)}
                                </span>
                                <span className={net >= 0 ? 'is-pos' : 'is-neg'}>
                                    {net >= 0 ? '+' : ''}{fmtWon(net)}
                                </span>
                                <span className="lotto-purchase-row__note">{rec.note || '-'}</span>
                                <div className="lotto-purchase-row__actions">
                                    <button className="button ghost small" onClick={() => onEditStart(rec)}>
                                        수정
                                    </button>
                                    <button className="button danger small" onClick={() => onDelete(rec.id)}>
                                        삭제
                                    </button>
                                </div>
                            </div>
                        );
                    })}
                </div>
            )}
        </section>
    );
};

/* ─────────────────────────────────────────────
   Main Functions Component
───────────────────────────────────────────── */
export default function Functions() {
    // ── 기존 상태 ──────────────────────────────────────────────────────────────
    const [latest, setLatest] = useState(null);
    const [params, setParams] = useState({
        recent_window: 200, recent_weight: 2.0, avoid_recent_k: 5,
    });
    const presets = useMemo(() => [
        { name: '기본', recent_window: 200, recent_weight: 2.0, avoid_recent_k: 5 },
        { name: '최근 가중치↑', recent_window: 100, recent_weight: 3.0, avoid_recent_k: 10 },
        { name: '안전(분산)', recent_window: 300, recent_weight: 1.6, avoid_recent_k: 8 },
        { name: '공격(최근)', recent_window: 80, recent_weight: 3.5, avoid_recent_k: 12 },
    ], []);
    const [result, setResult] = useState(null);
    const [history, setHistory] = useState([]);
    const [historyExpanded, setHistoryExpanded] = useState(false);
    const historyEndRef = useRef(null);
    const prevHistoryExpandedRef = useRef(false);
    const [stats, setStats] = useState(() => readStatsCache());
    const [statsLoading, setStatsLoading] = useState(false);
    const [statsError, setStatsError] = useState('');
    const [loading, setLoading] = useState({
        latest: false, recommend: false, history: false, bestPicks: false, analysis: false,
    });
    const [error, setError] = useState('');
    const [bestPicks, setBestPicks] = useState([]);
    const [bestPicksExpanded, setBestPicksExpanded] = useState(false);
    const [analysis, setAnalysis] = useState(null);
    const [simulating, setSimulating] = useState(false);
    const [simResult, setSimResult] = useState(null);

    // ── 신규 상태 ──────────────────────────────────────────────────────────────
    const [combined, setCombined] = useState(null);
    const [combinedLoading, setCombinedLoading] = useState(false);
    const [combinedHistory, setCombinedHistory] = useState([]);
    const [combinedHistLoading, setCombinedHistLoading] = useState(false);

    const [perfStats, setPerfStats] = useState(null);
    const [report, setReport] = useState(null);
    const [reportHistory, setReportHistory] = useState([]);
    const [reportLoading, setReportLoading] = useState(false);
    const [personalAnalysis, setPersonalAnalysis] = useState(null);
    const [personalLoading, setPersonalLoading] = useState(false);
    const [purchases, setPurchases] = useState([]);
    const [purchaseStats, setPurchaseStats] = useState(null);
    const [purchaseLoading, setPurchaseLoading] = useState(false);

    // 구매 폼 상태
    const [purchaseFormOpen, setPurchaseFormOpen] = useState(false);
    const [purchaseForm, setPurchaseForm] = useState(emptyPurchaseForm);
    const [purchaseFormSaving, setPurchaseFormSaving] = useState(false);
    const [purchaseFormError, setPurchaseFormError] = useState('');
    const [purchaseEditId, setPurchaseEditId] = useState(null);

    // ── 파생 값 ────────────────────────────────────────────────────────────────
    const overallMetrics = useMemo(() => buildMetricsFromFrequency(stats?.frequency), [stats]);
    const historyMetrics = useMemo(() => buildMetricsFromHistory(history), [history]);
    const visibleHistory = historyExpanded ? history : history.slice(0, 5);
    const visibleBestPicks = bestPicksExpanded ? bestPicks : bestPicks.slice(0, BEST_PICKS_DEFAULT_SHOW);

    // ── 기존 로드 함수 ─────────────────────────────────────────────────────────
    const refreshLatest = async () => {
        setLoading((s) => ({ ...s, latest: true }));
        setError('');
        try { setLatest(await getLatest()); }
        catch (e) { setError(e?.message ?? String(e)); }
        finally { setLoading((s) => ({ ...s, latest: false })); }
    };

    const refreshHistory = async () => {
        setLoading((s) => ({ ...s, history: true }));
        setError('');
        try {
            const limit = 100; let offset = 0; const allItems = [];
            while (true) {
                const data = await getHistory(limit, offset);
                const items = data.items ?? [];
                allItems.push(...items);
                if (items.length < limit) break;
                offset += limit;
            }
            setHistory(allItems);
        } catch (e) { setError(e?.message ?? String(e)); }
        finally { setLoading((s) => ({ ...s, history: false })); }
    };

    const refreshStats = async () => {
        setStatsLoading(true); setStatsError('');
        try {
            const cached = readStatsCache();
            if (cached && !stats) setStats(cached);
            const data = await getStats();
            if (!cached || cached.total_draws !== data?.total_draws) {
                setStats(data); writeStatsCache(data);
            }
        } catch (e) { setStatsError(e?.message ?? String(e)); }
        finally { setStatsLoading(false); }
    };

    const refreshBestPicks = async () => {
        setLoading((s) => ({ ...s, bestPicks: true }));
        try { setBestPicks((await getBestPicks(20)).items ?? []); }
        catch {}
        finally { setLoading((s) => ({ ...s, bestPicks: false })); }
    };

    const refreshAnalysis = async () => {
        setLoading((s) => ({ ...s, analysis: true }));
        try { setAnalysis(await getAnalysis()); }
        catch {}
        finally { setLoading((s) => ({ ...s, analysis: false })); }
    };

    // ── 신규 로드 함수 ─────────────────────────────────────────────────────────
    const refreshPerfStats = async () => {
        try { setPerfStats(await getPerformanceStats()); } catch {}
    };

    const refreshReport = async () => {
        setReportLoading(true);
        try {
            const [rep, hist] = await Promise.all([
                getLatestReport(),
                getReportHistory(10),
            ]);
            setReport(rep);
            setReportHistory(hist?.reports ?? []);
        } catch {}
        finally { setReportLoading(false); }
    };

    const loadSpecificReport = async (drwNo) => {
        setReportLoading(true);
        try { setReport(await getReport(drwNo)); }
        catch {}
        finally { setReportLoading(false); }
    };

    const runCombinedRecommend = async () => {
        setCombinedLoading(true);
        try {
            const data = await getCombinedRecommend();
            setCombined(data);
            // 이력도 새로고침
            const hist = await getCombinedHistory(30);
            setCombinedHistory(hist?.items ?? []);
        } catch (e) { setError(e?.message ?? String(e)); }
        finally { setCombinedLoading(false); }
    };

    const loadCombinedHistory = async () => {
        setCombinedHistLoading(true);
        try {
            const hist = await getCombinedHistory(30);
            setCombinedHistory(hist?.items ?? []);
        } catch {}
        finally { setCombinedHistLoading(false); }
    };

    const refreshPersonalAnalysis = async () => {
        setPersonalLoading(true);
        try { setPersonalAnalysis(await getPersonalAnalysis()); }
        catch {}
        finally { setPersonalLoading(false); }
    };

    const refreshPurchases = async () => {
        setPurchaseLoading(true);
        try {
            const [recs, st] = await Promise.all([getPurchases(), getPurchaseStats()]);
            setPurchases(recs?.records ?? []);
            setPurchaseStats(st);
        } catch {}
        finally { setPurchaseLoading(false); }
    };

    // ── 시뮬레이션 ─────────────────────────────────────────────────────────────
    const onSimulate = async () => {
        const ok = confirm('시뮬레이션을 즉시 실행할까요?\n20,000개 후보를 분석합니다. (약 1~3분 소요)');
        if (!ok) return;
        setSimulating(true); setSimResult(null); setError('');
        try {
            const data = await triggerSimulate();
            setSimResult(data);
            await refreshBestPicks();
        } catch (e) { setError(e?.message ?? String(e)); }
        finally { setSimulating(false); }
    };

    // ── 수동 추천 ──────────────────────────────────────────────────────────────
    const onRecommend = async () => {
        setLoading((s) => ({ ...s, recommend: true })); setError('');
        try { const data = await recommend(params); setResult(data); await refreshHistory(); }
        catch (e) { setError(e?.message ?? String(e)); }
        finally { setLoading((s) => ({ ...s, recommend: false })); }
    };

    const onDelete = async (id) => {
        if (!confirm(`히스토리 #${id}를 삭제할까요?`)) return;
        setError('');
        try { await deleteHistory(id); setHistory((prev) => prev.filter((item) => item.id !== id)); }
        catch (e) { setError(e?.message ?? String(e)); }
    };

    const copyNumbers = async (nums) => {
        const text = nums.join(', ');
        try { await navigator.clipboard.writeText(text); alert(`복사 완료: ${text}`); }
        catch { prompt('복사해서 사용하세요:', text); }
    };

    // ── 구매 기록 CRUD ─────────────────────────────────────────────────────────
    const handlePurchaseFormOpen = () => {
        setPurchaseEditId(null);
        setPurchaseForm(emptyPurchaseForm());
        setPurchaseFormError('');
        setPurchaseFormOpen(true);
    };

    const handlePurchaseFormClose = () => {
        setPurchaseFormOpen(false);
        setPurchaseEditId(null);
        setPurchaseFormError('');
    };

    const handlePurchaseFormChange = (field, value) => {
        setPurchaseForm((prev) => ({ ...prev, [field]: value }));
    };

    const handlePurchaseEditStart = (rec) => {
        setPurchaseEditId(rec.id);
        setPurchaseForm({
            draw_no: String(rec.draw_no ?? ''),
            amount: rec.amount ?? 5000,
            sets: rec.sets ?? 5,
            prize: rec.prize ?? 0,
            note: rec.note ?? '',
        });
        setPurchaseFormError('');
        setPurchaseFormOpen(true);
    };

    const handlePurchaseFormSubmit = async (e) => {
        e.preventDefault();
        setPurchaseFormSaving(true); setPurchaseFormError('');
        const payload = {
            draw_no: Number(purchaseForm.draw_no),
            amount: Number(purchaseForm.amount),
            sets: Number(purchaseForm.sets),
            prize: Number(purchaseForm.prize),
            note: purchaseForm.note.trim(),
        };
        try {
            if (purchaseEditId != null) {
                const updated = await updatePurchase(purchaseEditId, payload);
                setPurchases((prev) =>
                    prev.map((r) => r.id === purchaseEditId ? (updated ?? { ...payload, id: purchaseEditId }) : r)
                );
            } else {
                const saved = await addPurchase(payload);
                setPurchases((prev) => [saved ?? { ...payload, id: Date.now() }, ...prev]);
            }
            // 통계 재로드
            try { setPurchaseStats(await getPurchaseStats()); } catch {}
            handlePurchaseFormClose();
        } catch (err) {
            setPurchaseFormError(err?.message ?? String(err));
        } finally {
            setPurchaseFormSaving(false);
        }
    };

    const handlePurchaseDelete = async (id) => {
        if (!confirm('이 구매 기록을 삭제할까요?')) return;
        setPurchases((prev) => prev.filter((r) => r.id !== id));
        try {
            await deletePurchase(id);
            try { setPurchaseStats(await getPurchaseStats()); } catch {}
        } catch { refreshPurchases(); }
    };

    // ── 초기 로드 ──────────────────────────────────────────────────────────────
    useEffect(() => {
        refreshLatest();
        refreshHistory();
        refreshStats();
        refreshBestPicks();
        refreshAnalysis();
        refreshPerfStats();
        refreshReport();
        refreshPersonalAnalysis();
        refreshPurchases();
        loadCombinedHistory();
    }, []);

    useEffect(() => {
        if (historyExpanded && !prevHistoryExpandedRef.current) {
            requestAnimationFrame(() => {
                historyEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' });
            });
        }
        prevHistoryExpandedRef.current = historyExpanded;
    }, [historyExpanded, visibleHistory.length]);

    // ── 렌더 ───────────────────────────────────────────────────────────────────
    return (
        <div className="lotto-functions">
            {error ? (
                <div className="lotto-alert">
                    <div>
                        <p className="lotto-alert__title">오류</p>
                        <p className="lotto-alert__message">{error}</p>
                    </div>
                    <button className="button ghost small" onClick={() => setError('')}>닫기</button>
                </div>
            ) : null}

            {/* ── 신뢰도 배너 ── */}
            <PerformanceBanner perf={perfStats} />

            {/* ── 종합 추론 번호 추천 ── */}
            <CombinedRecommendPanel
                combined={combined}
                history={combinedHistory}
                loading={combinedLoading}
                histLoading={combinedHistLoading}
                onRun={runCombinedRecommend}
                onCopy={copyNumbers}
            />

            {/* ── 최신 회차 + 시뮬레이션 추천 ── */}
            <div className="lotto-grid">
                {/* Latest Draw */}
                <section className="lotto-panel">
                    <div className="lotto-panel__head">
                        <div>
                            <p className="lotto-panel__eyebrow">Latest Draw</p>
                            <h3>최신 회차</h3>
                            <p className="lotto-panel__sub">최신 회차와 번호를 빠르게 확인할 수 있습니다.</p>
                        </div>
                        <div className="lotto-panel__actions">
                            {loading.latest ? <span className="lotto-chip">로딩 중</span> : null}
                            <button className="button ghost small" onClick={refreshLatest} disabled={loading.latest}>
                                새로고침
                            </button>
                        </div>
                    </div>
                    {latest ? (
                        <>
                            <div className="lotto-meta">
                                <div>
                                    <p className="lotto-meta__title">{latest.drawNo}회</p>
                                    <p className="lotto-meta__date">{latest.date}</p>
                                </div>
                                <button className="button small" onClick={() => copyNumbers(latest.numbers)}>
                                    번호 복사
                                </button>
                            </div>
                            <NumberRow nums={latest.numbers} />
                            <p className="lotto-bonus">보너스 <strong>{latest.bonus}</strong></p>
                            {overallMetrics && (
                                <MetricBlock title="당첨 통계 (전체 회차)" metrics={overallMetrics} />
                            )}
                        </>
                    ) : (
                        <p className="lotto-empty">최신 회차 데이터가 없습니다.</p>
                    )}
                </section>

                {/* Simulation Picks */}
                <section className="lotto-panel">
                    <div className="lotto-panel__head">
                        <div>
                            <p className="lotto-panel__eyebrow">Simulation Picks</p>
                            <h3>시뮬레이션 추천</h3>
                            <p className="lotto-panel__sub">
                                하루 6회 몬테카를로 시뮬레이션으로 선별된 최적 번호입니다.
                            </p>
                        </div>
                        <div className="lotto-panel__actions">
                            {loading.bestPicks ? <span className="lotto-chip">로딩 중</span> : null}
                            {simulating ? <span className="lotto-chip lotto-chip--active">분석 중</span> : null}
                            <button className="button ghost small" onClick={refreshBestPicks}
                                disabled={loading.bestPicks || simulating}>
                                새로고침
                            </button>
                            <button className="button small" onClick={onSimulate}
                                disabled={simulating || loading.bestPicks}>
                                {simulating ? '실행 중...' : '지금 실행'}
                            </button>
                        </div>
                    </div>

                    {simResult && (
                        <div className="lotto-sim-result">
                            <p>완료: {simResult.total_generated?.toLocaleString()}개 후보 → 상위 {simResult.best_n_saved}개 저장</p>
                            <p>최고 점수 {((simResult.best_score ?? 0) * 100).toFixed(1)}% / 평균 {((simResult.avg_score ?? 0) * 100).toFixed(1)}%</p>
                        </div>
                    )}

                    {bestPicks.length === 0 ? (
                        <p className="lotto-empty">
                            {loading.bestPicks ? '불러오는 중...' : "시뮬레이션 결과가 없습니다. '지금 실행'으로 시작하세요."}
                        </p>
                    ) : (
                        <>
                            <div className="lotto-picks">
                                {visibleBestPicks.map((pick) => (
                                    <div key={pick.id} className="lotto-pick">
                                        <span className="lotto-pick__rank">#{pick.rank}</span>
                                        <div className="lotto-pick__content">
                                            <NumberRow nums={pick.numbers} />
                                            <div className="lotto-pick__score">
                                                <span className="lotto-pick__score-label">
                                                    {((pick.score_total ?? 0) * 100).toFixed(1)}%
                                                </span>
                                                <div className="lotto-pick__bar">
                                                    <span style={{ width: `${(pick.score_total ?? 0) * 100}%` }} />
                                                </div>
                                            </div>
                                        </div>
                                        <button className="button ghost small" onClick={() => copyNumbers(pick.numbers)}>
                                            복사
                                        </button>
                                    </div>
                                ))}
                            </div>
                            {bestPicks.length > BEST_PICKS_DEFAULT_SHOW && (
                                <button
                                    className="button ghost small lotto-history-toggle"
                                    onClick={() => setBestPicksExpanded((p) => !p)}
                                    aria-expanded={bestPicksExpanded}
                                >
                                    {bestPicksExpanded ? '접기' : `모두 보기 (${bestPicks.length}개)`}
                                    <span className={`lotto-history-toggle__icon ${bestPicksExpanded ? 'is-open' : ''}`} aria-hidden>▼</span>
                                </button>
                            )}
                            <p className="lotto-panel__sub">
                                갱신: {fmtKST(bestPicks[0]?.created_at) || '-'}
                                {bestPicks[0]?.based_on_draw ? ` · ${bestPicks[0].based_on_draw}회 기준` : ''}
                            </p>
                        </>
                    )}
                </section>
            </div>

            {/* ── 이번 주 공략 리포트 ── */}
            <ReportPanel
                report={report}
                history={reportHistory}
                loading={reportLoading}
                onRefresh={refreshReport}
                onSelectDrw={loadSpecificReport}
            />

            {/* ── 통계 분석 ── */}
            <section className="lotto-panel lotto-panel--wide">
                <div className="lotto-panel__head">
                    <div>
                        <p className="lotto-panel__eyebrow">Analysis</p>
                        <h3>통계 분석</h3>
                        <p className="lotto-panel__sub">빈도, Z-score, 갭 분석으로 번호를 분류합니다.</p>
                    </div>
                    <div className="lotto-panel__actions">
                        {loading.analysis ? <span className="lotto-chip">로딩 중</span> : null}
                        <button className="button ghost small" onClick={refreshAnalysis} disabled={loading.analysis}>
                            새로고침
                        </button>
                    </div>
                </div>
                {analysis ? (
                    <div className="lotto-analysis">
                        <div className="lotto-analysis__row">
                            <div className="lotto-analysis__group">
                                <p className="lotto-analysis__label">🔥 핫 번호 <span>출현 빈도 상위 10</span></p>
                                <div className="lotto-row">
                                    {(analysis.hot_numbers ?? []).map((n) => <Ball key={n} n={n} />)}
                                </div>
                            </div>
                            <div className="lotto-analysis__group">
                                <p className="lotto-analysis__label">🧊 콜드 번호 <span>출현 빈도 하위 10</span></p>
                                <div className="lotto-row">
                                    {(analysis.cold_numbers ?? []).map((n) => <Ball key={n} n={n} />)}
                                </div>
                            </div>
                            <div className="lotto-analysis__group">
                                <p className="lotto-analysis__label">⏰ 오버듀 번호 <span>오래 안 나온 번호 (회차 수)</span></p>
                                <div className="lotto-row">
                                    {(analysis.overdue_numbers ?? []).map((n) => {
                                        const stat = (analysis.number_stats ?? []).find((s) => s.number === n);
                                        return (
                                            <div key={n} className="lotto-overdue">
                                                <Ball n={n} />
                                                <span className="lotto-overdue__gap">{stat?.gap ?? '-'}회</span>
                                            </div>
                                        );
                                    })}
                                </div>
                            </div>
                        </div>
                        <div className="lotto-analysis__stats">
                            <span>역대 합계 평균 <strong>{analysis.mean_sum}</strong></span>
                            <span>표준편차 <strong>±{analysis.std_sum}</strong></span>
                            <span>분석 회차 <strong>{analysis.total_draws?.toLocaleString()}</strong></span>
                            <span>
                                홀수 3:짝수 3 확률{' '}
                                <strong>
                                    {analysis.odd_distribution?.['3'] ? `${analysis.odd_distribution['3']}%` : '-'}
                                </strong>
                            </span>
                        </div>
                    </div>
                ) : (
                    <p className="lotto-empty">
                        {loading.analysis ? '불러오는 중...' : '통계 분석 데이터가 없습니다.'}
                    </p>
                )}
            </section>

            {/* ── 전체 번호 분포 ── */}
            <section className="lotto-panel lotto-panel--wide">
                <div className="lotto-panel__head">
                    <div>
                        <p className="lotto-panel__eyebrow">Distribution</p>
                        <h3>전체 회차 번호 분포</h3>
                        <p className="lotto-panel__sub">1~45번 번호가 등장한 횟수를 기준으로 분포를 표시합니다.</p>
                    </div>
                    <div className="lotto-panel__actions">
                        {statsLoading ? <span className="lotto-chip">로딩 중</span> : null}
                        {stats?.total_draws ? (
                            <span className="lotto-chip">{stats.total_draws}회차</span>
                        ) : null}
                        <button className="button ghost small" onClick={refreshStats} disabled={statsLoading}>
                            새로고침
                        </button>
                    </div>
                </div>
                {statsError ? <p className="lotto-empty">{statsError}</p> : null}
                {stats ? (
                    <FrequencyChart stats={stats} />
                ) : (
                    <p className="lotto-empty">통계 데이터를 불러오지 못했습니다.</p>
                )}
            </section>

            {/* ── 내 번호 패턴 ── */}
            <PersonalAnalysisPanel data={personalAnalysis} loading={personalLoading} />

            {/* ── 구매 기록 ── */}
            <PurchasePanel
                records={purchases}
                stats={purchaseStats}
                loading={purchaseLoading}
                formOpen={purchaseFormOpen}
                form={purchaseForm}
                formSaving={purchaseFormSaving}
                formError={purchaseFormError}
                editId={purchaseEditId}
                onFormOpen={handlePurchaseFormOpen}
                onFormClose={handlePurchaseFormClose}
                onFormChange={handlePurchaseFormChange}
                onFormSubmit={handlePurchaseFormSubmit}
                onEditStart={handlePurchaseEditStart}
                onDelete={handlePurchaseDelete}
            />

            {/* ── 수동 추천 ── */}
            <section className="lotto-panel">
                <div className="lotto-panel__head">
                    <div>
                        <p className="lotto-panel__eyebrow">Manual Recommendation</p>
                        <h3>수동 추천</h3>
                        <p className="lotto-panel__sub">파라미터를 직접 조정해 번호를 추천받을 수 있습니다.</p>
                    </div>
                    <div className="lotto-panel__actions">
                        {loading.recommend ? <span className="lotto-chip">계산 중</span> : null}
                    </div>
                </div>

                <div className="lotto-presets">
                    {presets.map((preset) => (
                        <button key={preset.name} className="button ghost small"
                            onClick={() => setParams({
                                recent_window: preset.recent_window,
                                recent_weight: preset.recent_weight,
                                avoid_recent_k: preset.avoid_recent_k,
                            })}>
                            {preset.name}
                        </button>
                    ))}
                </div>

                <div className="lotto-form">
                    <label className="lotto-field">
                        recent_window <span>최근 N회차 가중치 범위</span>
                        <input type="number" min={20} max={1000} value={params.recent_window}
                            onChange={(e) => setParams((s) => ({ ...s, recent_window: Number(e.target.value) }))} />
                    </label>
                    <label className="lotto-field">
                        recent_weight <span>최근 회차 가중치</span>
                        <input type="number" step="0.1" min={0.5} max={10} value={params.recent_weight}
                            onChange={(e) => setParams((s) => ({ ...s, recent_weight: Number(e.target.value) }))} />
                    </label>
                    <label className="lotto-field">
                        avoid_recent_k <span>최근 K회차 중복 회피</span>
                        <input type="number" min={0} max={50} value={params.avoid_recent_k}
                            onChange={(e) => setParams((s) => ({ ...s, avoid_recent_k: Number(e.target.value) }))} />
                    </label>
                </div>

                <button className="button primary" onClick={onRecommend} disabled={loading.recommend}>
                    추천 받기
                </button>

                {result ? (
                    <div className="lotto-result">
                        <div className="lotto-result__meta">
                            <div>
                                <p className="lotto-result__id">추천 ID #{result.id}</p>
                                <p className="lotto-result__based">기준 회차 {result.based_on_latest_draw ?? '-'}</p>
                            </div>
                            <button className="button small" onClick={() => copyNumbers(result.numbers)}>
                                번호 복사
                            </button>
                        </div>
                        {result.numbers && <NumberRow nums={result.numbers} />}
                        {historyMetrics && (
                            <div className="lotto-compare">
                                <MetricBlock title="추천 통계 (히스토리)" metrics={historyMetrics} />
                            </div>
                        )}
                        {Array.isArray(result.items) && result.items.length ? (
                            <details className="lotto-details">
                                <summary>추천 후보 보기</summary>
                                <div className="lotto-batch">
                                    {result.items.map((item, idx) => (
                                        <div key={item.id ?? `candidate-${idx}`} className="lotto-batch__item">
                                            <div className="lotto-batch__meta">
                                                <div>
                                                    <p className="lotto-batch__title">후보 #{item.id ?? idx + 1}</p>
                                                    <p className="lotto-batch__sub">기준 회차 {item.based_on_draw ?? '-'}</p>
                                                </div>
                                                <button className="button ghost small" onClick={() => copyNumbers(item.numbers)}>
                                                    복사
                                                </button>
                                            </div>
                                            <NumberRow nums={item.numbers} />
                                            {item.metrics && <MetricBlock title="후보 통계" metrics={item.metrics} />}
                                        </div>
                                    ))}
                                </div>
                            </details>
                        ) : null}
                        {result.explain && (
                            <details className="lotto-details">
                                <summary>설명 보기</summary>
                                <pre>{JSON.stringify(result.explain, null, 2)}</pre>
                            </details>
                        )}
                    </div>
                ) : (
                    <p className="lotto-empty">아직 추천 결과가 없습니다.</p>
                )}
            </section>

            {/* ── 추천 히스토리 ── */}
            <section className="lotto-panel">
                <div className="lotto-panel__head">
                    <div>
                        <p className="lotto-panel__eyebrow">History</p>
                        <h3>추천 히스토리</h3>
                        <p className="lotto-panel__sub">수동 추천 결과를 모아서 확인할 수 있습니다.</p>
                    </div>
                    <div className="lotto-panel__actions">
                        <span className="lotto-chip">{history.length}건</span>
                        {history.length > 5 && (
                            <button className="button ghost small lotto-history-toggle"
                                onClick={() => setHistoryExpanded((p) => !p)}
                                aria-expanded={historyExpanded}>
                                {historyExpanded ? '접기' : '더보기'}
                                <span className={`lotto-history-toggle__icon ${historyExpanded ? 'is-open' : ''}`} aria-hidden>▼</span>
                            </button>
                        )}
                        <button className="button ghost small" onClick={refreshHistory} disabled={loading.history}>
                            새로고침
                        </button>
                    </div>
                </div>

                {loading.history ? <p className="lotto-empty">불러오는 중...</p> : null}
                {history.length === 0 ? (
                    <p className="lotto-empty">저장된 히스토리가 없습니다.</p>
                ) : (
                    <div className="lotto-history">
                        {visibleHistory.map((item) => (
                            <div key={item.id} className="lotto-history__item">
                                <div className="lotto-history__meta">
                                    <p>#{item.id}</p>
                                    <p>{fmtKST(item.created_at)}</p>
                                    <p>기준 회차 {item.based_on_draw ?? '-'}</p>
                                </div>
                                <div className="lotto-history__body">
                                    <NumberRow nums={item.numbers} />
                                    <p className="lotto-history__params">
                                        window={item.params?.recent_window}, weight={item.params?.recent_weight},
                                        avoid_k={item.params?.avoid_recent_k}
                                    </p>
                                </div>
                                <div className="lotto-history__actions">
                                    <button className="button ghost small" onClick={() => copyNumbers(item.numbers)}>
                                        복사
                                    </button>
                                    <button className="button danger small" onClick={() => onDelete(item.id)}>
                                        삭제
                                    </button>
                                </div>
                            </div>
                        ))}
                        <span ref={historyEndRef} />
                    </div>
                )}
            </section>

            <footer className="lotto-foot">
                backend: FastAPI / nginx proxy / DB: sqlite ·{' '}
                <a className="lotto-foot__link" href="/lotto-api.md" download>API 스펙 다운로드</a>
            </footer>
        </div>
    );
}
