import React, { useEffect, useMemo, useRef, useState } from 'react';
import { deleteHistory, getHistory, getLatest, getStats, recommend } from '../../api';

const fmtKST = (value) => value?.replace('T', ' ') ?? '';

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 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 {
        // ignore storage failures
    }
};

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, value) => acc + value, 0);
    if (!total) return null;
    const min = Math.min(...counts);
    const max = Math.max(...counts);
    const range = max - min;
    const odd = counts.reduce(
        (acc, value, idx) => (idx % 2 === 0 ? acc + value : 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, 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);
        const 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 entries = Object.entries(metrics.buckets);
    const ordered = bucketOrder
        .filter((key) => Object.prototype.hasOwnProperty.call(metrics.buckets, key))
        .map((key) => [key, metrics.buckets[key]]);
    const rest = entries
        .filter(([key]) => !bucketOrder.includes(key))
        .sort((a, b) => {
            const aStart = Number(a[0].split('-')[0]);
            const bStart = Number(b[0].split('-')[0]);
            if (Number.isNaN(aStart) || Number.isNaN(bStart)) return 0;
            return aStart - bStart;
        });
    return [...ordered, ...rest];
};

const MetricBlock = ({ title, metrics }) => {
    if (!metrics) return null;
    const buckets = toBucketEntries(metrics);
    const maxBucket = buckets.length
        ? Math.max(...buckets.map(([, value]) => Number(value) || 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(() => {
        const mid = Math.round(max * 0.5);
        return [max, mid, 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>
    );
};

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,
    });
    const [error, setError] = useState('');
    const overallMetrics = useMemo(
        () => buildMetricsFromFrequency(stats?.frequency),
        [stats]
    );
    const historyMetrics = useMemo(
        () => buildMetricsFromHistory(history),
        [history]
    );

    const refreshLatest = async () => {
        setLoading((s) => ({ ...s, latest: true }));
        setError('');
        try {
            const data = await getLatest();
            setLatest(data);
        } 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();
            const shouldUpdate =
                !cached || cached.total_draws !== data?.total_draws;
            if (shouldUpdate) {
                setStats(data);
                writeStatsCache(data);
            }
        } catch (e) {
            setStatsError(e?.message ?? String(e));
        } finally {
            setStatsLoading(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) => {
        const ok = confirm(`히스토리 #${id}를 삭제할까요?`);
        if (!ok) 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);
        }
    };

    useEffect(() => {
        refreshLatest();
        refreshHistory();
        refreshStats();
    }, []);

    const visibleHistory = historyExpanded ? history : history.slice(0, 5);

    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}

            <div className="lotto-grid">
                <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}
                                />
                            ) : null}
                        </>
                    ) : (
                        <p className="lotto-empty">최신 회차 데이터가 없습니다.</p>
                    )}
                </section>

                <section className="lotto-panel">
                    <div className="lotto-panel__head">
                        <div>
                            <p className="lotto-panel__eyebrow">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} /> : null}
                            {historyMetrics ? (
                                <div className="lotto-compare">
                                    <MetricBlock
                                        title="추천 통계 (히스토리)"
                                        metrics={historyMetrics}
                                    />
                                </div>
                            ) : null}
                            {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}
                                                    />
                                                ) : null}
                                            </div>
                                        ))}
                                    </div>
                                </details>
                            ) : null}
                            {result.explain ? (
                                <details className="lotto-details">
                                    <summary>설명 보기</summary>
                                    <pre>{JSON.stringify(result.explain, null, 2)}</pre>
                                </details>
                            ) : null}
                        </div>
                    ) : (
                        <p className="lotto-empty">아직 추천 결과가 없습니다.</p>
                    )}
                </section>

            </div>

            <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>

            <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((prev) => !prev)
                                }
                                aria-expanded={historyExpanded}
                                aria-label={
                                    historyExpanded
                                        ? '히스토리 접기'
                                        : '히스토리 더보기'
                                }
                            >
                                {historyExpanded ? '접기' : '더보기'}
                                <span
                                    className={`lotto-history-toggle__icon ${
                                        historyExpanded ? 'is-open' : ''
                                    }`}
                                    aria-hidden
                                >
                                    ▼
                                </span>
                            </button>
                        ) : null}
                        <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>
    );
}
