import random
from collections import Counter
from typing import Dict, Any, List, Tuple

from .utils import weighted_sample_6

def recommend_numbers(
    draws: List[Tuple[int, List[int]]],
    *,
    recent_window: int = 200,
    recent_weight: float = 2.0,
    avoid_recent_k: int = 5,
    seed: int | None = None,
) -> Dict[str, Any]:
    """
    가벼운 통계 기반 추천:
    - 전체 빈도 + 최근(recent_window) 빈도에 가중치를 더한 가중 샘플링
    - 최근 avoid_recent_k 회차에 나온 번호는 확률을 낮춤(완전 제외는 아님)
    """
    if seed is not None:
        random.seed(seed)

    # 전체 빈도
    all_nums = [n for _, nums in draws for n in nums]
    freq_all = Counter(all_nums)

    # 최근 빈도
    recent = draws[-recent_window:] if len(draws) >= recent_window else draws
    recent_nums = [n for _, nums in recent for n in nums]
    freq_recent = Counter(recent_nums)

    # 최근 k회차 번호(패널티)
    last_k = draws[-avoid_recent_k:] if len(draws) >= avoid_recent_k else draws
    last_k_nums = set(n for _, nums in last_k for n in nums)

    # 가중치 구성
    weights = {}
    for n in range(1, 46):
        w = freq_all[n] + recent_weight * freq_recent[n]
        if n in last_k_nums:
            w *= 0.6  # 최근에 너무 방금 나온 건 살짝 덜 뽑히게
        weights[n] = max(w, 0.1)

    # 중복 없이 6개 뽑기(가중 샘플링)
    chosen_sorted = sorted(weighted_sample_6(weights))

    explain = {
        "recent_window": recent_window,
        "recent_weight": recent_weight,
        "avoid_recent_k": avoid_recent_k,
        "top_all": [n for n, _ in freq_all.most_common(10)],
        "top_recent": [n for n, _ in freq_recent.most_common(10)],
        "last_k_draws": [d for d, _ in last_k],
    }

    return {"numbers": chosen_sorted, "explain": explain}


def recommend_with_heatmap(
    draws: List[Tuple[int, List[int]]],
    past_recommendations: List[Dict[str, Any]],
    *,
    heatmap_window: int = 10,
    heatmap_weight: float = 1.5,
    recent_window: int = 200,
    recent_weight: float = 2.0,
    avoid_recent_k: int = 5,
    seed: int | None = None,
) -> Dict[str, Any]:
    """
    히트맵 기반 가중치 추천:
    - 과거 추천 번호들의 적중률을 분석하여 잘 맞춘 번호에 가중치 부여
    - 기존 통계 기반 추천과 결합
    
    Args:
        draws: 실제 당첨 번호 리스트 [(회차, [번호들]), ...]
        past_recommendations: 과거 추천 데이터 [{"numbers": [...], "correct_count": N, "based_on_draw": M}, ...]
        heatmap_window: 히트맵 분석할 최근 추천 개수
        heatmap_weight: 히트맵 가중치 (높을수록 과거 적중 번호 선호)
    """
    if seed is not None:
        random.seed(seed)
    
    # 1. 기존 통계 기반 가중치 계산
    all_nums = [n for _, nums in draws for n in nums]
    freq_all = Counter(all_nums)
    
    recent = draws[-recent_window:] if len(draws) >= recent_window else draws
    recent_nums = [n for _, nums in recent for n in nums]
    freq_recent = Counter(recent_nums)
    
    last_k = draws[-avoid_recent_k:] if len(draws) >= avoid_recent_k else draws
    last_k_nums = set(n for _, nums in last_k for n in nums)
    
    # 2. 히트맵 생성: 과거 추천에서 적중한 번호들의 빈도
    heatmap = Counter()
    recent_recs = past_recommendations[-heatmap_window:] if len(past_recommendations) >= heatmap_window else past_recommendations
    
    for rec in recent_recs:
        if rec.get("correct_count", 0) > 0:  # 적중한 추천만
            # 적중 개수에 비례해서 가중치 부여 (많이 맞춘 추천일수록 높은 가중)
            weight = rec["correct_count"] ** 1.5  # 제곱으로 강조
            for num in rec["numbers"]:
                heatmap[num] += weight
    
    # 3. 최종 가중치 = 기존 통계 + 히트맵
    weights = {}
    for n in range(1, 46):
        w = freq_all[n] + recent_weight * freq_recent[n]
        
        # 히트맵 가중치 추가
        if n in heatmap:
            w += heatmap_weight * heatmap[n]
        
        # 최근 출현 번호 패널티
        if n in last_k_nums:
            w *= 0.6
        
        weights[n] = max(w, 0.1)
    
    # 4. 가중 샘플링으로 6개 선택
    chosen_sorted = sorted(weighted_sample_6(weights))
    
    # 5. 설명 데이터
    explain = {
        "recent_window": recent_window,
        "recent_weight": recent_weight,
        "avoid_recent_k": avoid_recent_k,
        "heatmap_window": heatmap_window,
        "heatmap_weight": heatmap_weight,
        "top_all": [n for n, _ in freq_all.most_common(10)],
        "top_recent": [n for n, _ in freq_recent.most_common(10)],
        "top_heatmap": [n for n, _ in heatmap.most_common(10)],
        "last_k_draws": [d for d, _ in last_k],
        "analyzed_recommendations": len(recent_recs),
    }
    
    return {"numbers": chosen_sorted, "explain": explain}

