"""Pydantic models for roster link type safety Provides league-specific type-safe models for roster operations: - PdRosterLinkData: PD league card-based rosters - SbaRosterLinkData: SBA league player-based rosters """ from abc import ABC, abstractmethod from typing import Optional from uuid import UUID from pydantic import BaseModel, ConfigDict, field_validator class BaseRosterLinkData(BaseModel, ABC): """Abstract base for roster link data Common fields shared across all leagues """ model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True) id: Optional[int] = None # Database ID (populated after save) game_id: UUID team_id: int @abstractmethod def get_entity_id(self) -> int: """Get the entity ID (card_id or player_id)""" pass @abstractmethod def get_entity_type(self) -> str: """Get entity type identifier ('card' or 'player')""" pass class PdRosterLinkData(BaseRosterLinkData): """PD league roster link - tracks cards Used for Paper Dynasty league games where rosters are composed of cards. Each card represents a player with detailed scouting data. """ card_id: int @field_validator("card_id") @classmethod def validate_card_id(cls, v: int) -> int: if v <= 0: raise ValueError("card_id must be positive") return v def get_entity_id(self) -> int: return self.card_id def get_entity_type(self) -> str: return "card" class SbaRosterLinkData(BaseRosterLinkData): """SBA league roster link - tracks players Used for SBA league games where rosters are composed of players. Players are identified directly by player_id without a card system. """ player_id: int @field_validator("player_id") @classmethod def validate_player_id(cls, v: int) -> int: if v <= 0: raise ValueError("player_id must be positive") return v def get_entity_id(self) -> int: return self.player_id def get_entity_type(self) -> str: return "player" class RosterLinkCreate(BaseModel): """Request model for creating a roster link""" game_id: UUID team_id: int card_id: Optional[int] = None player_id: Optional[int] = None @field_validator("team_id") @classmethod def validate_team_id(cls, v: int) -> int: if v <= 0: raise ValueError("team_id must be positive") return v def model_post_init(self, __context) -> None: """Validate that exactly one ID is populated""" has_card = self.card_id is not None has_player = self.player_id is not None if has_card == has_player: # XOR check (both True or both False = invalid) raise ValueError("Exactly one of card_id or player_id must be provided") def to_pd_data(self) -> PdRosterLinkData: """Convert to PD roster data (validates card_id is present)""" if self.card_id is None: raise ValueError("card_id required for PD roster") return PdRosterLinkData( game_id=self.game_id, team_id=self.team_id, card_id=self.card_id ) def to_sba_data(self) -> SbaRosterLinkData: """Convert to SBA roster data (validates player_id is present)""" if self.player_id is None: raise ValueError("player_id required for SBA roster") return SbaRosterLinkData( game_id=self.game_id, team_id=self.team_id, player_id=self.player_id )