""" Player Service Business logic for player-related operations, extracted from Player model. Handles URL generation, formatting, and player description logic. """ import logging from typing import Dict, Literal, Optional, Union from sqlmodel import Session from ..models.player import Player from .base_service import BaseService class PlayerService(BaseService): """Service for player-related business logic.""" def __init__(self, session: Session): super().__init__(session) self.logger = logging.getLogger(f'{__name__}.{self.__class__.__name__}') def get_batter_card_url(self, player: Player) -> Optional[str]: """ Get the batting card image URL for a player. Migrated from Player.batter_card_url property. Args: player: Player instance Returns: str: Batting card URL if found, None otherwise """ self._log_operation("get_batter_card_url", f"player {player.name}") if player.image and 'batting' in player.image: return player.image elif player.image2 and 'batting' in player.image2: return player.image2 else: return None def get_pitcher_card_url(self, player: Player) -> Optional[str]: """ Get the pitching card image URL for a player. Migrated from Player.pitcher_card_url property. Args: player: Player instance Returns: str: Pitching card URL if found, None otherwise """ self._log_operation("get_pitcher_card_url", f"player {player.name}") if player.image and 'pitching' in player.image: return player.image elif player.image2 and 'pitching' in player.image2: return player.image2 else: return None def generate_name_card_link(self, player: Player, card_type: Literal['pitching', 'batting']) -> str: """ Generate a markdown link with player name and card URL. Migrated from Player.name_card_link() method. Args: player: Player instance card_type: Type of card ('pitching' or 'batting') Returns: str: Markdown formatted link Raises: ValueError: If card URL is not available for the specified type """ self._log_operation("generate_name_card_link", f"player {player.name}, type {card_type}") if card_type == 'pitching': url = self.get_pitcher_card_url(player) else: url = self.get_batter_card_url(player) if url is None: raise ValueError(f"No {card_type} card URL available for player {player.name}") return f'[{player.name}]({url})' def get_formatted_name_with_description(self, player: Player) -> str: """ Get formatted player name with description. Migrated from Player.name_with_desc property. Args: player: Player instance Returns: str: Formatted name with description """ self._log_operation("get_formatted_name_with_description", f"player {player.name}") return f'{player.description} {player.name}' def get_player_description( self, player: Optional[Player] = None, player_dict: Optional[Dict[str, Union[str, int]]] = None ) -> str: """ Get full player description from Player object or dictionary. Migrated from standalone player_description() function. Args: player: Player instance (optional) player_dict: Dictionary with player data (optional) Returns: str: Full player description Raises: TypeError: If neither player nor player_dict is provided KeyError: If required keys are missing from player_dict """ if player is None and player_dict is None: err = 'One of "player" or "player_dict" must be included to get full description' self._log_error("get_player_description", err) raise TypeError(err) if player is not None: self._log_operation("get_player_description", f"from Player object: {player.name}") return f'{player.description} {player.name}' # Handle dictionary case if 'description' not in player_dict: err = 'player_dict must contain "description" key' self._log_error("get_player_description", err) raise KeyError(err) r_val = f'{player_dict["description"]}' if 'name' in player_dict: r_val += f' {player_dict["name"]}' elif 'p_name' in player_dict: r_val += f' {player_dict["p_name"]}' self._log_operation("get_player_description", f"from dict: {r_val}") return r_val