"""
Calculate statistical fields from PlayOutcome.

Called when recording a play to populate stat fields for materialized view aggregation.
"""

import logging

from app.config.result_charts import PlayOutcome
from app.core.play_resolver import PlayResult
from app.models.game_models import GameState

logger = logging.getLogger(f"{__name__}.PlayStatCalculator")


class PlayStatCalculator:
    """
    Converts play outcome to statistical fields for database.

    Stats are written to plays table and aggregated via materialized views.
    Following legacy API pattern from major-domo /plays/batting and /plays/pitching.
    """

    @staticmethod
    def calculate_stats(
        outcome: PlayOutcome,
        result: PlayResult,
        state_before: GameState,
        state_after: GameState,
    ) -> dict[str, int]:
        """
        Calculate all stat fields for a play.

        Args:
            outcome: The PlayOutcome enum value
            result: PlayResult with detailed outcome info
            state_before: GameState before play resolution
            state_after: GameState after play resolution

        Returns:
            dict with stat fields (pa, ab, hit, run, etc.)
        """
        stats: dict[str, int] = {
            "pa": 0,
            "ab": 0,
            "hit": 0,
            "run": 0,
            "rbi": 0,
            "double": 0,
            "triple": 0,
            "homerun": 0,
            "bb": 0,
            "so": 0,
            "hbp": 0,
            "sac": 0,
            "ibb": 0,
            "sb": 0,
            "cs": 0,
            "gidp": 0,
            "error": 0,
            "wild_pitch": 0,
            "passed_ball": 0,
            "balk": 0,
            "pick_off": 0,
            "outs_recorded": 0,
        }

        # Plate appearance (everything except non-PA events)
        if outcome not in [
            PlayOutcome.STOLEN_BASE,
            PlayOutcome.CAUGHT_STEALING,
            PlayOutcome.WILD_PITCH,
            PlayOutcome.PASSED_BALL,
            PlayOutcome.BALK,
            PlayOutcome.PICK_OFF,
        ]:
            stats["pa"] = 1

        # At bat (PA minus walks, HBP, sac)
        if stats["pa"] == 1 and outcome not in [
            PlayOutcome.WALK,
            PlayOutcome.HIT_BY_PITCH,
            PlayOutcome.INTENTIONAL_WALK,
        ]:
            stats["ab"] = 1

        # Hits - check if outcome is a hit
        if outcome.is_hit():
            stats["hit"] = 1

            # Determine hit type
            if outcome in [
                PlayOutcome.DOUBLE_2,
                PlayOutcome.DOUBLE_3,
                PlayOutcome.DOUBLE_UNCAPPED,
            ]:
                stats["double"] = 1
            elif outcome == PlayOutcome.TRIPLE:
                stats["triple"] = 1
            elif outcome == PlayOutcome.HOMERUN:
                stats["homerun"] = 1

        # Other batting outcomes
        if outcome == PlayOutcome.WALK:
            stats["bb"] = 1
        elif outcome == PlayOutcome.INTENTIONAL_WALK:
            stats["ibb"] = 1
            stats["bb"] = 1  # IBB counts as BB too
        elif outcome == PlayOutcome.STRIKEOUT:
            stats["so"] = 1
        elif outcome == PlayOutcome.HIT_BY_PITCH:
            stats["hbp"] = 1
        elif outcome == PlayOutcome.GROUNDBALL_A:
            # GROUNDBALL_A is double play if possible
            stats["gidp"] = 1

        # Baserunning events (non-PA)
        if outcome == PlayOutcome.STOLEN_BASE:
            stats["sb"] = 1
        elif outcome == PlayOutcome.CAUGHT_STEALING:
            stats["cs"] = 1

        # Pitching events (non-PA)
        if outcome == PlayOutcome.WILD_PITCH:
            stats["wild_pitch"] = 1
        elif outcome == PlayOutcome.PASSED_BALL:
            stats["passed_ball"] = 1
        elif outcome == PlayOutcome.BALK:
            stats["balk"] = 1
        elif outcome == PlayOutcome.PICK_OFF:
            stats["pick_off"] = 1

        # Calculate runs scored from state change
        # Check which team is batting to determine which score changed
        if state_before.half == "top":
            stats["run"] = state_after.away_score - state_before.away_score
        else:
            stats["run"] = state_after.home_score - state_before.home_score

        # RBI logic - runs scored minus runs on errors
        # If play had an error, don't credit RBI
        if hasattr(result, "error_occurred") and result.error_occurred:
            stats["rbi"] = 0
        else:
            stats["rbi"] = stats["run"]

        # Outs recorded
        stats["outs_recorded"] = state_after.outs - state_before.outs

        # Error tracking (from X-Check plays)
        if hasattr(result, "error_occurred") and result.error_occurred:
            stats["error"] = 1

        return stats
