import React, { useMemo } from 'react'; import { fmtKST, Ball, NumberRow, copyNumbers, buildMetricsFromFrequency, BEST_PICKS_DEFAULT_SHOW, } from '../lottoUtils'; import useLottoData from '../hooks/useLottoData'; import useManualRecommend from '../hooks/useManualRecommend'; import MetricBlock from '../components/MetricBlock'; import FrequencyChart from '../components/FrequencyChart'; import PerformanceBanner from '../components/PerformanceBanner'; import CombinedRecommendPanel from '../components/CombinedRecommendPanel'; import ReportPanel from '../components/ReportPanel'; import PersonalAnalysisPanel from '../components/PersonalAnalysisPanel'; export default function AnalysisTab() { const ld = useLottoData(); const mr = useManualRecommend(); const overallMetrics = useMemo(() => buildMetricsFromFrequency(ld.stats?.frequency), [ld.stats]); const visibleBestPicks = ld.bestPicksExpanded ? ld.bestPicks : ld.bestPicks.slice(0, BEST_PICKS_DEFAULT_SHOW); const error = ld.error || mr.error; const clearError = () => { ld.setError(''); mr.setError(''); }; return ( <> {error ? (

오류

{error}

) : null} {/* 신뢰도 배너 */} {/* 종합 추론 번호 추천 */} {/* 최신 회차 + 시뮬레이션 추천 */}
{/* Latest Draw */}

Latest Draw

최신 회차

최신 회차와 번호를 빠르게 확인할 수 있습니다.

{ld.loading.latest ? 로딩 중 : null}
{ld.latest ? ( <>

{ld.latest.drawNo}회

{ld.latest.date}

보너스 {ld.latest.bonus}

{overallMetrics && ( )} ) : (

최신 회차 데이터가 없습니다.

)}
{/* Simulation Picks */}

Simulation Picks

시뮬레이션 추천

하루 6회 몬테카를로 시뮬레이션으로 선별된 최적 번호입니다.

{ld.loading.bestPicks ? 로딩 중 : null} {ld.simulating ? 분석 중 : null}
{ld.simResult && (

완료: {ld.simResult.total_generated?.toLocaleString()}개 후보 → 상위 {ld.simResult.best_n_saved}개 저장

최고 점수 {((ld.simResult.best_score ?? 0) * 100).toFixed(1)}% / 평균 {((ld.simResult.avg_score ?? 0) * 100).toFixed(1)}%

)} {ld.bestPicks.length === 0 ? (

{ld.loading.bestPicks ? '불러오는 중...' : "시뮬레이션 결과가 없습니다. '지금 실행'으로 시작하세요."}

) : ( <>
{visibleBestPicks.map((pick) => (
#{pick.rank}
{((pick.score_total ?? 0) * 100).toFixed(1)}%
))}
{ld.bestPicks.length > BEST_PICKS_DEFAULT_SHOW && ( )}

갱신: {fmtKST(ld.bestPicks[0]?.created_at) || '-'} {ld.bestPicks[0]?.based_on_draw ? ` · ${ld.bestPicks[0].based_on_draw}회 기준` : ''}

)}
{/* 이번 주 공략 리포트 */} {/* 통계 분석 */}

Analysis

통계 분석

빈도, Z-score, 갭 분석으로 번호를 분류합니다.

{ld.loading.analysis ? 로딩 중 : null}
{ld.analysis ? (

🔥 핫 번호 출현 빈도 상위 10

{(ld.analysis.hot_numbers ?? []).map((n) => )}

🧊 콜드 번호 출현 빈도 하위 10

{(ld.analysis.cold_numbers ?? []).map((n) => )}

⏰ 오버듀 번호 오래 안 나온 번호 (회차 수)

{(ld.analysis.overdue_numbers ?? []).map((n) => { const stat = (ld.analysis.number_stats ?? []).find((s) => s.number === n); return (
{stat?.gap ?? '-'}회
); })}
역대 합계 평균 {ld.analysis.mean_sum} 표준편차 ±{ld.analysis.std_sum} 분석 회차 {ld.analysis.total_draws?.toLocaleString()} 홀수 3:짝수 3 확률{' '} {ld.analysis.odd_distribution?.['3'] ? `${ld.analysis.odd_distribution['3']}%` : '-'}
) : (

{ld.loading.analysis ? '불러오는 중...' : '통계 분석 데이터가 없습니다.'}

)}
{/* 전체 번호 분포 */}

Distribution

전체 회차 번호 분포

1~45번 번호가 등장한 횟수를 기준으로 분포를 표시합니다.

{ld.statsLoading ? 로딩 중 : null} {ld.stats?.total_draws ? ( {ld.stats.total_draws}회차 ) : null}
{ld.statsError ?

{ld.statsError}

: null} {ld.stats ? ( ) : (

통계 데이터를 불러오지 못했습니다.

)}
{/* 내 번호 패턴 */} {/* 수동 추천 */}

Manual Recommendation

수동 추천

파라미터를 직접 조정해 번호를 추천받을 수 있습니다.

{mr.loading.recommend ? 계산 중 : null}
{mr.presets.map((preset) => ( ))}
{mr.result ? (

추천 ID #{mr.result.id}

기준 회차 {mr.result.based_on_latest_draw ?? '-'}

{mr.result.numbers && } {mr.historyMetrics && (
)} {Array.isArray(mr.result.items) && mr.result.items.length ? (
추천 후보 보기
{mr.result.items.map((item, idx) => (

후보 #{item.id ?? idx + 1}

기준 회차 {item.based_on_draw ?? '-'}

{item.metrics && }
))}
) : null} {mr.result.explain && (
설명 보기
{JSON.stringify(mr.result.explain, null, 2)}
)}
) : (

아직 추천 결과가 없습니다.

)}
{/* 추천 히스토리 */}

History

추천 히스토리

수동 추천 결과를 모아서 확인할 수 있습니다.

{mr.history.length}건 {mr.history.length > 5 && ( )}
{mr.loading.history ?

불러오는 중...

: null} {mr.history.length === 0 ? (

저장된 히스토리가 없습니다.

) : (
{mr.visibleHistory.map((item) => (

#{item.id}

{fmtKST(item.created_at)}

기준 회차 {item.based_on_draw ?? '-'}

window={item.params?.recent_window}, weight={item.params?.recent_weight}, avoid_k={item.params?.avoid_recent_k}

))}
)}
); }