import logging
from uuid import UUID, uuid4

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field, field_validator

from app.core.game_engine import game_engine
from app.core.state_manager import state_manager
from app.database.operations import DatabaseOperations
from app.services.lineup_service import lineup_service

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

router = APIRouter()


class GameListItem(BaseModel):
    """Game list item model"""

    game_id: str
    league_id: str
    status: str
    home_team_id: int
    away_team_id: int


class CreateGameRequest(BaseModel):
    """Request model for creating a new game"""

    name: str = Field(..., description="Game name")
    home_team_id: int = Field(..., description="Home team ID")
    away_team_id: int = Field(..., description="Away team ID")
    is_ai_opponent: bool = Field(default=False, description="Is AI opponent")
    season: int = Field(default=3, description="Season number")
    league_id: str = Field(default="sba", description="League ID (sba or pd)")


class CreateGameResponse(BaseModel):
    """Response model for game creation"""

    game_id: str
    message: str
    status: str


class LineupPlayerRequest(BaseModel):
    """Single player in lineup request"""

    player_id: int = Field(..., description="SBA player ID")
    position: str = Field(..., description="Defensive position (P, C, 1B, etc.)")
    batting_order: int | None = Field(
        None, ge=1, le=9, description="Batting order (1-9), null for pitcher in DH lineup"
    )

    @field_validator("position")
    @classmethod
    def validate_position(cls, v: str) -> str:
        """Ensure position is valid"""
        valid = ["P", "C", "1B", "2B", "3B", "SS", "LF", "CF", "RF", "DH"]
        if v not in valid:
            raise ValueError(f"Position must be one of {valid}")
        return v


class SubmitLineupsRequest(BaseModel):
    """
    Request model for submitting lineups for both teams.

    Supports both 9-player (pitcher bats) and 10-player (DH) configurations:
    - 9 players: All have batting orders 1-9
    - 10 players: Pitcher has batting_order=null, others have 1-9
    """

    home_lineup: list[LineupPlayerRequest] = Field(
        ..., min_length=9, max_length=10, description="Home team starting lineup (9-10 players)"
    )
    away_lineup: list[LineupPlayerRequest] = Field(
        ..., min_length=9, max_length=10, description="Away team starting lineup (9-10 players)"
    )

    @field_validator("home_lineup", "away_lineup")
    @classmethod
    def validate_lineup(cls, v: list[LineupPlayerRequest]) -> list[LineupPlayerRequest]:
        """
        Validate lineup structure for 9-player or 10-player (DH) configurations.

        Rules:
        - 9 players: All must have batting orders 1-9
        - 10 players: Exactly 9 have batting orders 1-9, pitcher has null
        """
        lineup_size = len(v)

        # Check batting orders
        batters = [p for p in v if p.batting_order is not None]
        batting_orders = [p.batting_order for p in batters]

        if len(batting_orders) != 9:
            raise ValueError(f"Must have exactly 9 batters with batting orders, got {len(batting_orders)}")

        if set(batting_orders) != {1, 2, 3, 4, 5, 6, 7, 8, 9}:
            raise ValueError("Batting orders must be exactly 1-9 with no duplicates")

        # Check positions
        positions = [p.position for p in v]
        required_positions = ["P", "C", "1B", "2B", "3B", "SS", "LF", "CF", "RF"]

        for req_pos in required_positions:
            if req_pos not in positions:
                raise ValueError(f"Missing required position: {req_pos}")

        # For 10-player lineup, must have DH and pitcher must not bat
        if lineup_size == 10:
            if "DH" not in positions:
                raise ValueError("10-player lineup must include DH position")

            pitchers = [p for p in v if p.position == "P"]
            if len(pitchers) != 1:
                raise ValueError("Must have exactly 1 pitcher")

            if pitchers[0].batting_order is not None:
                raise ValueError("Pitcher cannot have batting order in DH lineup")

        # For 9-player lineup, pitcher must bat (no DH)
        elif lineup_size == 9:
            if "DH" in positions:
                raise ValueError("9-player lineup cannot include DH")

            pitchers = [p for p in v if p.position == "P"]
            if len(pitchers) != 1:
                raise ValueError("Must have exactly 1 pitcher")

            if pitchers[0].batting_order is None:
                raise ValueError("Pitcher must have batting order when no DH")

        # Check player uniqueness
        player_ids = [p.player_id for p in v]
        if len(set(player_ids)) != len(player_ids):
            raise ValueError("Players cannot be duplicated in lineup")

        return v


class SubmitLineupsResponse(BaseModel):
    """Response model for lineup submission"""

    game_id: str
    message: str
    home_lineup_count: int
    away_lineup_count: int


@router.get("/", response_model=list[GameListItem])
async def list_games():
    """
    List all games from the database

    Returns basic game information for all games in the system.
    TODO: Add user filtering, pagination, and more sophisticated queries
    """
    try:
        logger.info("Fetching games list from database")

        db_ops = DatabaseOperations()

        # Get all games from database (for now - later we can add filters)
        from app.database.session import AsyncSessionLocal
        from app.models.db_models import Game

        async with AsyncSessionLocal() as session:
            from sqlalchemy import select
            result = await session.execute(
                select(Game).order_by(Game.created_at.desc())
            )
            games = result.scalars().all()

            # Convert to response model
            game_list = [
                GameListItem(
                    game_id=str(game.id),
                    league_id=game.league_id,
                    status=game.status,
                    home_team_id=game.home_team_id,
                    away_team_id=game.away_team_id,
                )
                for game in games
            ]

            logger.info(f"Retrieved {len(game_list)} games from database")
            return game_list

    except Exception as e:
        logger.exception(f"Failed to list games: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to list games: {str(e)}")


@router.get("/{game_id}")
async def get_game(game_id: str):
    """
    Get game details including team IDs and status.

    Args:
        game_id: Game identifier

    Returns:
        Game information including home/away team IDs

    Raises:
        400: Invalid game_id format
        404: Game not found
    """
    try:
        # Validate game_id format
        try:
            game_uuid = UUID(game_id)
        except ValueError:
            raise HTTPException(status_code=400, detail="Invalid game_id format")

        logger.info(f"Fetching game details for {game_id}")

        # Get game from state manager
        if game_uuid not in state_manager._states:
            raise HTTPException(status_code=404, detail=f"Game {game_id} not found")

        state = state_manager._states[game_uuid]

        return {
            "game_id": game_id,
            "status": state.status,
            "home_team_id": state.home_team_id,
            "away_team_id": state.away_team_id,
            "league_id": state.league_id,
        }

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"Failed to fetch game {game_id}: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to fetch game: {str(e)}")


@router.post("/", response_model=CreateGameResponse)
async def create_game(request: CreateGameRequest):
    """
    Create new game

    Creates a new game in the state manager and database.
    Note: Lineups must be added separately before the game can be started.
    """
    try:
        # Generate game ID
        game_id = uuid4()
        logger.info(
            f"Creating game {game_id}: {request.home_team_id} vs {request.away_team_id}"
        )

        # Validate teams are different
        if request.home_team_id == request.away_team_id:
            raise HTTPException(
                status_code=400, detail="Home and away teams must be different"
            )

        # Create game in state manager (in-memory)
        state = await state_manager.create_game(
            game_id=game_id,
            league_id=request.league_id,
            home_team_id=request.home_team_id,
            away_team_id=request.away_team_id,
        )

        # Save to database
        db_ops = DatabaseOperations()
        await db_ops.create_game(
            game_id=game_id,
            league_id=request.league_id,
            home_team_id=request.home_team_id,
            away_team_id=request.away_team_id,
            game_mode="friendly" if not request.is_ai_opponent else "ai",
            visibility="public",
        )

        logger.info(
            f"Game {game_id} created successfully - status: {state.status}"
        )

        return CreateGameResponse(
            game_id=str(game_id),
            message=f"Game '{request.name}' created successfully. Add lineups to start the game.",
            status=state.status,
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"Failed to create game: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to create game: {str(e)}")


@router.post("/quick-create", response_model=CreateGameResponse)
async def quick_create_game():
    """
    Quick-create endpoint for testing - creates a game with pre-configured lineups.

    Uses the lineup configuration from the most recent game (Team 35 vs Team 38).
    This eliminates the 2-minute lineup configuration process during testing.

    Returns:
        CreateGameResponse with game_id
    """
    try:
        # Generate game ID
        game_id = uuid4()

        # Use real team data from most recent game
        home_team_id = 35
        away_team_id = 38
        league_id = "sba"

        logger.info(
            f"Quick-creating game {game_id}: {home_team_id} vs {away_team_id}"
        )

        # Create game in state manager
        state = await state_manager.create_game(
            game_id=game_id,
            league_id=league_id,
            home_team_id=home_team_id,
            away_team_id=away_team_id,
        )

        # Save to database
        db_ops = DatabaseOperations()
        await db_ops.create_game(
            game_id=game_id,
            league_id=league_id,
            home_team_id=home_team_id,
            away_team_id=away_team_id,
            game_mode="friendly",
            visibility="public",
        )

        # Submit home lineup (Team 35)
        home_lineup_data = [
            {"player_id": 1417, "position": "C", "batting_order": 1},
            {"player_id": 1186, "position": "1B", "batting_order": 2},
            {"player_id": 1381, "position": "2B", "batting_order": 3},
            {"player_id": 1576, "position": "3B", "batting_order": 4},
            {"player_id": 1242, "position": "SS", "batting_order": 5},
            {"player_id": 1600, "position": "LF", "batting_order": 6},
            {"player_id": 1675, "position": "CF", "batting_order": 7},
            {"player_id": 1700, "position": "RF", "batting_order": 8},
            {"player_id": 1759, "position": "DH", "batting_order": 9},
            {"player_id": 1948, "position": "P", "batting_order": None},
        ]

        for player in home_lineup_data:
            await lineup_service.add_sba_player_to_lineup(
                game_id=game_id,
                team_id=home_team_id,
                player_id=player["player_id"],
                position=player["position"],
                batting_order=player["batting_order"],
                is_starter=True,
            )

        # Submit away lineup (Team 38)
        away_lineup_data = [
            {"player_id": 1080, "position": "C", "batting_order": 1},
            {"player_id": 1148, "position": "1B", "batting_order": 2},
            {"player_id": 1166, "position": "2B", "batting_order": 3},
            {"player_id": 1513, "position": "3B", "batting_order": 4},
            {"player_id": 1209, "position": "SS", "batting_order": 5},
            {"player_id": 1735, "position": "LF", "batting_order": 6},
            {"player_id": 1665, "position": "CF", "batting_order": 7},
            {"player_id": 1961, "position": "RF", "batting_order": 8},
            {"player_id": 1980, "position": "DH", "batting_order": 9},
            {"player_id": 2005, "position": "P", "batting_order": None},
        ]

        for player in away_lineup_data:
            await lineup_service.add_sba_player_to_lineup(
                game_id=game_id,
                team_id=away_team_id,
                player_id=player["player_id"],
                position=player["position"],
                batting_order=player["batting_order"],
                is_starter=True,
            )

        # Start the game
        await game_engine.start_game(game_id)

        logger.info(f"Quick-created game {game_id} and started successfully")

        return CreateGameResponse(
            game_id=str(game_id),
            message=f"Game quick-created with Team {home_team_id} vs Team {away_team_id}. Ready to play!",
            status="active",
        )

    except Exception as e:
        logger.exception(f"Failed to quick-create game: {e}")
        raise HTTPException(status_code=500, detail=f"Failed to quick-create game: {str(e)}")


@router.post("/{game_id}/lineups", response_model=SubmitLineupsResponse)
async def submit_lineups(game_id: str, request: SubmitLineupsRequest):
    """
    Submit lineups for both teams.

    Accepts complete lineups for home and away teams. Supports both:
    - 9-player lineups (pitcher bats, no DH)
    - 10-player lineups (universal DH, pitcher doesn't bat)

    Args:
        game_id: Game identifier
        request: Lineup data for both teams

    Returns:
        Confirmation with lineup counts

    Raises:
        400: Invalid lineup structure or validation error
        404: Game not found
        500: Database or API error
    """
    try:
        # Validate game_id format
        try:
            game_uuid = UUID(game_id)
        except ValueError:
            raise HTTPException(status_code=400, detail="Invalid game_id format")

        logger.info(f"Submitting lineups for game {game_id}")

        # Get game state from memory or load basic info from database
        state = state_manager.get_state(game_uuid)
        if not state:
            logger.info(f"Game {game_id} not in memory, loading from database")

            # Load basic game info from database
            db_ops = DatabaseOperations()
            game_data = await db_ops.load_game_state(game_uuid)

            if not game_data:
                raise HTTPException(status_code=404, detail=f"Game {game_id} not found")

            game_info = game_data['game']

            # Recreate game state in memory (without lineups - we're about to add them)
            state = await state_manager.create_game(
                game_id=game_uuid,
                league_id=game_info['league_id'],
                home_team_id=game_info['home_team_id'],
                away_team_id=game_info['away_team_id'],
                home_team_is_ai=game_info.get('home_team_is_ai', False),
                away_team_is_ai=game_info.get('away_team_is_ai', False),
                auto_mode=game_info.get('auto_mode', False)
            )
            logger.info(f"Recreated game {game_id} in memory from database")

        # Process home team lineup
        home_count = 0
        for player in request.home_lineup:
            await lineup_service.add_sba_player_to_lineup(
                game_id=game_uuid,
                team_id=state.home_team_id,
                player_id=player.player_id,
                position=player.position,
                batting_order=player.batting_order,
                is_starter=True,
            )
            home_count += 1

        logger.info(f"Added {home_count} players to home team lineup")

        # Process away team lineup
        away_count = 0
        for player in request.away_lineup:
            await lineup_service.add_sba_player_to_lineup(
                game_id=game_uuid,
                team_id=state.away_team_id,
                player_id=player.player_id,
                position=player.position,
                batting_order=player.batting_order,
                is_starter=True,
            )
            away_count += 1

        logger.info(f"Added {away_count} players to away team lineup")

        # Automatically start the game after lineups are submitted
        from app.core.game_engine import game_engine
        try:
            await game_engine.start_game(game_uuid)
            logger.info(f"Game {game_id} started successfully after lineup submission")
        except Exception as e:
            logger.warning(f"Failed to auto-start game {game_id}: {e}")
            # Don't fail the lineup submission if game start fails
            # User can manually start if needed

        return SubmitLineupsResponse(
            game_id=game_id,
            message=f"Lineups submitted successfully. Home: {home_count} players, Away: {away_count} players.",
            home_lineup_count=home_count,
            away_lineup_count=away_count,
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.exception(f"Failed to submit lineups for game {game_id}: {e}")
        raise HTTPException(
            status_code=500, detail=f"Failed to submit lineups: {str(e)}"
        )
