"""
Lineup Service - High-level lineup operations with player data.

Combines database operations with API calls to provide complete
lineup entries with player data.

Author: Claude
Date: 2025-01-10
"""

import logging
from dataclasses import dataclass
from uuid import UUID

from app.database.operations import DatabaseOperations
from app.models.game_models import LineupPlayerState, TeamLineupState
from app.services.sba_api_client import sba_api_client

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


@dataclass
class LineupEntryWithPlayer:
    """Lineup entry with associated player data."""

    lineup_id: int
    player_id: int
    position: str
    batting_order: int | None
    is_starter: bool
    is_active: bool
    # Player data from API
    player_name: str
    player_image: str  # Card image
    player_headshot: str  # Headshot for UI circles


class LineupService:
    """
    Service for lineup operations that include player data.

    Combines database operations with SBA API calls to provide
    complete lineup entries with player names and images.
    """

    def __init__(self, db_ops: DatabaseOperations | None = None):
        self.db_ops = db_ops or DatabaseOperations()

    async def add_sba_player_to_lineup(
        self,
        game_id: UUID,
        team_id: int,
        player_id: int,
        position: str,
        batting_order: int | None = None,
        is_starter: bool = True,
    ) -> LineupEntryWithPlayer:
        """
        Add SBA player to lineup with player data.

        1. Creates lineup entry in database
        2. Fetches player data from SBA API
        3. Returns combined result

        Args:
            game_id: Game identifier
            team_id: Team identifier
            player_id: SBA player ID
            position: Defensive position
            batting_order: Batting order (1-9) if applicable
            is_starter: Whether player is in starting lineup

        Returns:
            LineupEntryWithPlayer with lineup data + player info

        Raises:
            HTTPError: If SBA API call fails
            SQLAlchemyError: If database operation fails
        """
        # Step 1: Create lineup entry in database
        lineup = await self.db_ops.add_sba_lineup_player(
            game_id=game_id,
            team_id=team_id,
            player_id=player_id,
            position=position,
            batting_order=batting_order,
            is_starter=is_starter,
        )

        # Step 2: Fetch player data from SBA API
        player_name = f"Player #{player_id}"
        player_image = ""
        player_headshot = ""

        try:
            player = await sba_api_client.get_player(player_id)
            player_name = player.name
            player_image = player.get_image_url()
            player_headshot = player.headshot or ""
            logger.info(f"Loaded player data for {player_id}: {player_name}")
        except Exception as e:
            logger.warning(f"Failed to fetch player data for {player_id}: {e}")
            # Continue with defaults - lineup entry is still valid

        # Step 3: Return combined result
        return LineupEntryWithPlayer(
            lineup_id=lineup.id,  # type: ignore[arg-type]
            player_id=player_id,
            position=position,
            batting_order=batting_order,
            is_starter=is_starter,
            is_active=True,
            player_name=player_name,
            player_image=player_image,
            player_headshot=player_headshot,
        )

    async def load_team_lineup_with_player_data(
        self, game_id: UUID, team_id: int, league_id: str
    ) -> TeamLineupState | None:
        """
        Load existing team lineup from database with player data.

        1. Fetches full lineup (active + bench) from database
        2. Tries to get player data from RosterLink cache first
        3. Falls back to SBA API if cache misses (for SBA league)
        4. Returns TeamLineupState with player info populated

        Args:
            game_id: Game identifier
            team_id: Team identifier
            league_id: League identifier ('sba' or 'pd')

        Returns:
            TeamLineupState with player data (including bench), or None if no lineup found
        """
        # Step 1: Get full lineup from database (active + bench)
        lineup_entries = await self.db_ops.get_full_lineup(game_id, team_id)
        if not lineup_entries:
            return None

        # Step 2: Get player data - try RosterLink cache first, then API fallback
        player_data_cache: dict[int, dict] = {}
        api_player_data: dict = {}

        if league_id == "sba":
            player_ids = [p.player_id for p in lineup_entries if p.player_id]  # type: ignore[misc]
            if player_ids:
                # Try RosterLink cache first
                player_data_cache = await self.db_ops.get_roster_player_data(
                    game_id, team_id
                )
                cached_count = len(player_data_cache)

                # Find players missing from cache
                missing_ids = [
                    pid for pid in player_ids if pid not in player_data_cache
                ]

                if missing_ids:
                    # Fall back to SBA API for missing players
                    try:
                        api_player_data = await sba_api_client.get_players_batch(
                            missing_ids
                        )
                        logger.info(
                            f"Loaded {cached_count} players from cache, "
                            f"{len(api_player_data)} from API for team {team_id}"
                        )
                    except Exception as e:
                        logger.warning(
                            f"Failed to fetch player data from API for team {team_id}: {e}"
                        )
                else:
                    logger.info(
                        f"Loaded all {cached_count} players from RosterLink cache "
                        f"for team {team_id} (no API call needed)"
                    )

        # Step 3: Build TeamLineupState with player data
        players = []
        for p in lineup_entries:
            player_name = None
            player_image = None
            player_headshot = None

            if league_id == "sba" and p.player_id:  # type: ignore[arg-type]
                # Check cache first, then API data
                if p.player_id in player_data_cache:  # type: ignore[arg-type]
                    cached = player_data_cache[p.player_id]  # type: ignore[arg-type]
                    player_name = cached.get("name")
                    player_image = cached.get("image")
                    player_headshot = cached.get("headshot")
                elif p.player_id in api_player_data:  # type: ignore[arg-type]
                    player = api_player_data[p.player_id]  # type: ignore[arg-type]
                    player_name = player.name
                    player_image = player.get_image_url()
                    player_headshot = player.headshot

            players.append(
                LineupPlayerState(
                    lineup_id=p.id,  # type: ignore[arg-type]
                    card_id=p.card_id if p.card_id else (p.player_id or 0),  # type: ignore[arg-type]
                    position=p.position,  # type: ignore[arg-type]
                    batting_order=p.batting_order,  # type: ignore[arg-type]
                    is_active=p.is_active,  # type: ignore[arg-type]
                    is_starter=p.is_starter,  # type: ignore[arg-type]
                    player_name=player_name,
                    player_image=player_image,
                    player_headshot=player_headshot,
                )
            )

        return TeamLineupState(team_id=team_id, players=players)

    async def get_sba_player_data(self, player_id: int) -> tuple[str, str]:
        """
        Fetch player data for a single SBA player.

        Args:
            player_id: SBA player ID

        Returns:
            Tuple of (player_name, player_image)
            Returns defaults if API call fails
        """
        player_name = f"Player #{player_id}"
        player_image = ""

        try:
            player = await sba_api_client.get_player(player_id)
            player_name = player.name
            player_image = player.get_image_url()
            logger.info(f"Loaded player data for {player_id}: {player_name}")
        except Exception as e:
            logger.warning(f"Failed to fetch player data for {player_id}: {e}")

        return player_name, player_image


# Singleton instance
lineup_service = LineupService()
