"""
VYNDR Blind Spot Detector
Identifies conditions where the model underperforms.
Tracks catastrophic misses (worst 5%).
"""

import logging

from utils.bayesian import calculate_brier_score

logger = logging.getLogger('vyndr')

# Conditions to check for blind spots
BLIND_SPOT_CONDITIONS = [
    'home', 'road', 'day_game', 'night_game', 'back_to_back',
    'division_game', 'interleague', 'high_altitude', 'dome_game'
]

MIN_SAMPLE_FOR_BLIND_SPOT = 30
DEGRADATION_THRESHOLD = 0.25  # 25% worse than overall


def detect_model_blind_spots(all_outcomes, min_sample=None):
    """
    Find conditions where the model's Brier score is 25%+ worse
    than its overall Brier score. These are the blind spots.

    Args:
        all_outcomes: List of resolved outcome dicts. Each must have:
            'confidence' (float), 'hit' (bool), 'context' (dict of condition flags).
        min_sample: Minimum sample size per condition (default 30).

    Returns:
        List of blind spot dicts with condition, brier_score, overall_brier,
        degradation, and sample_size.
    """
    if min_sample is None:
        min_sample = MIN_SAMPLE_FOR_BLIND_SPOT

    overall_brier = calculate_brier_score(all_outcomes)
    if overall_brier is None or overall_brier == 0:
        return []

    blind_spots = []
    for condition in BLIND_SPOT_CONDITIONS:
        subset = [
            o for o in all_outcomes
            if o.get('context', {}).get(condition)
        ]
        if len(subset) >= min_sample:
            subset_brier = calculate_brier_score(subset)
            if subset_brier is not None and subset_brier > overall_brier * (1 + DEGRADATION_THRESHOLD):
                blind_spots.append({
                    'condition': condition,
                    'brier_score': subset_brier,
                    'overall_brier': overall_brier,
                    'degradation': round((subset_brier - overall_brier) / overall_brier, 2),
                    'sample_size': len(subset)
                })

    return blind_spots


def track_catastrophic_misses(all_outcomes, percentile=0.05):
    """
    Track the WORST misses specifically — not just average performance.
    An A+ grade that misses by 15 points is a reputational disaster.
    Find patterns in conditions that produce catastrophic misses.

    Args:
        all_outcomes: List of resolved outcome dicts. Each must have:
            'actual_value', 'projected_value', 'player_name', 'grade',
            'game_context', 'game_date'.
        percentile: Top percentage of worst misses to track (default 5%).

    Returns:
        List of catastrophic miss dicts with player, grade, projected,
        actual, error, conditions, and date.
    """
    if not all_outcomes:
        return []

    # Calculate absolute error for each outcome
    scored = []
    for o in all_outcomes:
        actual = o.get('actual_value')
        projected = o.get('projected_value')
        if actual is not None and projected is not None:
            scored.append({**o, 'abs_error': abs(actual - projected)})

    if not scored:
        return []

    scored.sort(key=lambda x: x['abs_error'], reverse=True)
    cutoff = int(len(scored) * percentile)
    worst = scored[:max(cutoff, 5)]

    return [{
        'player': o.get('player_name'),
        'grade': o.get('grade'),
        'projected': o.get('projected_value'),
        'actual': o.get('actual_value'),
        'error': o.get('abs_error'),
        'conditions': o.get('game_context', {}),
        'date': o.get('game_date')
    } for o in worst]
