"""
BoxScoreService - Query materialized views for formatted box scores.

Provides game statistics, batting stats, and pitching stats by querying
PostgreSQL materialized views created in migration 004.

Author: Claude
Date: 2025-11-07
"""

import logging
from uuid import UUID

from sqlalchemy import text

from app.database.session import AsyncSessionLocal

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


class BoxScoreService:
    """
    Service for retrieving box score data from materialized views.

    Queries three materialized views:
    - game_stats: Team totals and linescore
    - batting_game_stats: Player batting statistics
    - pitching_game_stats: Player pitching statistics
    """

    async def get_box_score(self, game_id: UUID) -> dict | None:
        """
        Get complete box score for a game.

        Args:
            game_id: Game identifier

        Returns:
            Dictionary with game_stats, batting_stats, and pitching_stats
            Returns None if game not found

        Raises:
            Exception: If database query fails
        """
        async with AsyncSessionLocal() as session:
            try:
                # Query all three views
                game_stats = await self._get_game_stats(session, game_id)

                if not game_stats:
                    logger.warning(f"No game stats found for game {game_id}")
                    return None

                batting_stats = await self._get_batting_stats(session, game_id)
                pitching_stats = await self._get_pitching_stats(session, game_id)

                logger.info(
                    f"Retrieved box score for game {game_id}: "
                    f"{len(batting_stats)} batters, {len(pitching_stats)} pitchers"
                )

                return {
                    "game_stats": game_stats,
                    "batting_stats": batting_stats,
                    "pitching_stats": pitching_stats,
                }

            except Exception as e:
                logger.error(
                    f"Failed to get box score for game {game_id}: {e}", exc_info=True
                )
                raise

    async def _get_game_stats(self, session, game_id: UUID) -> dict | None:
        """
        Query game_stats materialized view for team totals and linescore.

        Args:
            session: Active database session
            game_id: Game identifier

        Returns:
            Dictionary with game statistics or None if not found
        """
        query = text("""
            SELECT
                game_id,
                home_runs,
                away_runs,
                home_hits,
                away_hits,
                home_errors,
                away_errors,
                home_linescore,
                away_linescore
            FROM game_stats
            WHERE game_id = :game_id
        """)

        result = await session.execute(query, {"game_id": str(game_id)})
        row = result.fetchone()

        if not row:
            return None

        return {
            "game_id": row[0],
            "home_runs": row[1] or 0,
            "away_runs": row[2] or 0,
            "home_hits": row[3] or 0,
            "away_hits": row[4] or 0,
            "home_errors": row[5] or 0,
            "away_errors": row[6] or 0,
            "home_linescore": row[7] or [],
            "away_linescore": row[8] or [],
        }

    async def _get_batting_stats(self, session, game_id: UUID) -> list[dict]:
        """
        Query batting_game_stats materialized view for player batting lines.

        Args:
            session: Active database session
            game_id: Game identifier

        Returns:
            List of batting statistics dictionaries
        """
        query = text("""
            SELECT
                lineup_id,
                game_id,
                player_card_id,
                pa,
                ab,
                run,
                hit,
                rbi,
                double,
                triple,
                hr,
                bb,
                so,
                hbp,
                sac,
                sb,
                cs,
                gidp
            FROM batting_game_stats
            WHERE game_id = :game_id
            ORDER BY lineup_id
        """)

        result = await session.execute(query, {"game_id": str(game_id)})
        rows = result.fetchall()

        stats = []
        for row in rows:
            stats.append(
                {
                    "lineup_id": row[0],
                    "game_id": row[1],
                    "player_card_id": row[2],
                    "pa": row[3] or 0,
                    "ab": row[4] or 0,
                    "run": row[5] or 0,
                    "hit": row[6] or 0,
                    "rbi": row[7] or 0,
                    "double": row[8] or 0,
                    "triple": row[9] or 0,
                    "hr": row[10] or 0,
                    "bb": row[11] or 0,
                    "so": row[12] or 0,
                    "hbp": row[13] or 0,
                    "sac": row[14] or 0,
                    "sb": row[15] or 0,
                    "cs": row[16] or 0,
                    "gidp": row[17] or 0,
                }
            )

        return stats

    async def _get_pitching_stats(self, session, game_id: UUID) -> list[dict]:
        """
        Query pitching_game_stats materialized view for player pitching lines.

        Args:
            session: Active database session
            game_id: Game identifier

        Returns:
            List of pitching statistics dictionaries
        """
        query = text("""
            SELECT
                lineup_id,
                game_id,
                player_card_id,
                batters_faced,
                hit_allowed,
                run_allowed,
                erun,
                bb,
                so,
                hbp,
                hr_allowed,
                wp,
                ip
            FROM pitching_game_stats
            WHERE game_id = :game_id
            ORDER BY lineup_id
        """)

        result = await session.execute(query, {"game_id": str(game_id)})
        rows = result.fetchall()

        stats = []
        for row in rows:
            stats.append(
                {
                    "lineup_id": row[0],
                    "game_id": row[1],
                    "player_card_id": row[2],
                    "batters_faced": row[3] or 0,
                    "hit_allowed": row[4] or 0,
                    "run_allowed": row[5] or 0,
                    "erun": row[6] or 0,
                    "bb": row[7] or 0,
                    "so": row[8] or 0,
                    "hbp": row[9] or 0,
                    "hr_allowed": row[10] or 0,
                    "wp": row[11] or 0,
                    "ip": float(row[12]) if row[12] is not None else 0.0,
                }
            )

        return stats


# Singleton instance
box_score_service = BoxScoreService()
