""" Statistics service for Discord Bot v2.0 Handles batting and pitching statistics retrieval and processing. """ import asyncio import logging from typing import Optional from api.client import get_global_client from models.batting_stats import BattingStats from models.pitching_stats import PitchingStats logger = logging.getLogger(f"{__name__}.StatsService") class StatsService: """ Service for player statistics operations. Features: - Batting statistics retrieval - Pitching statistics retrieval - Season-specific filtering - Error handling and logging """ def __init__(self): """Initialize stats service.""" # We don't inherit from BaseService since we need custom endpoints self._get_client = get_global_client logger.debug("StatsService initialized") async def get_client(self): """Get the API client.""" return await self._get_client() async def get_batting_stats( self, player_id: int, season: int ) -> Optional[BattingStats]: """ Get batting statistics for a player in a specific season. Args: player_id: Player ID season: Season number Returns: BattingStats instance or None if not found """ try: client = await self.get_client() # Call the batting stats view endpoint params = [("player_id", str(player_id)), ("season", str(season))] response = await client.get("views/season-stats/batting", params=params) if not response or "stats" not in response: logger.debug( f"No batting stats found for player {player_id}, season {season}" ) return None stats_list = response["stats"] if not stats_list: logger.debug( f"Empty batting stats for player {player_id}, season {season}" ) return None # Take the first (should be only) result stats_data = stats_list[0] batting_stats = BattingStats.from_api_data(stats_data) logger.debug( f"Retrieved batting stats for player {player_id}: {batting_stats.avg:.3f} AVG" ) return batting_stats except Exception as e: logger.error(f"Error getting batting stats for player {player_id}: {e}") return None async def get_pitching_stats( self, player_id: int, season: int ) -> Optional[PitchingStats]: """ Get pitching statistics for a player in a specific season. Args: player_id: Player ID season: Season number Returns: PitchingStats instance or None if not found """ try: client = await self.get_client() # Call the pitching stats view endpoint params = [("player_id", str(player_id)), ("season", str(season))] response = await client.get("views/season-stats/pitching", params=params) if not response or "stats" not in response: logger.debug( f"No pitching stats found for player {player_id}, season {season}" ) return None stats_list = response["stats"] if not stats_list: logger.debug( f"Empty pitching stats for player {player_id}, season {season}" ) return None # Take the first (should be only) result stats_data = stats_list[0] pitching_stats = PitchingStats.from_api_data(stats_data) logger.debug( f"Retrieved pitching stats for player {player_id}: {pitching_stats.era:.2f} ERA" ) return pitching_stats except Exception as e: logger.error(f"Error getting pitching stats for player {player_id}: {e}") return None async def get_player_stats( self, player_id: int, season: int ) -> tuple[Optional[BattingStats], Optional[PitchingStats]]: """ Get both batting and pitching statistics for a player. Args: player_id: Player ID season: Season number Returns: Tuple of (batting_stats, pitching_stats) - either can be None """ try: # Get both types of stats concurrently batting_stats, pitching_stats = await asyncio.gather( self.get_batting_stats(player_id, season), self.get_pitching_stats(player_id, season), ) logger.debug( f"Retrieved stats for player {player_id}: " f"batting={'yes' if batting_stats else 'no'}, " f"pitching={'yes' if pitching_stats else 'no'}" ) return batting_stats, pitching_stats except Exception as e: logger.error(f"Error getting player stats for {player_id}: {e}") return None, None # Global service instance stats_service = StatsService()