from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_
from typing import List
from datetime import datetime
from decimal import Decimal

from app.database import get_db
from app.models import User, SportEvent, SpreadBet, AdminSettings, EventStatus, SpreadBetStatus, TeamSide
from app.schemas.sport_event import SportEvent as SportEventSchema, SportEventWithBets
from app.schemas.spread_bet import SpreadBet as SpreadBetSchema, SpreadBetCreate, SpreadBetTake, SpreadBetDetail
from app.routers.auth import get_current_user

router = APIRouter(prefix="/api/v1/sport-events", tags=["sport-events"])


def generate_spread_grid(min_spread: float, max_spread: float, increment: float = 0.5) -> List[float]:
    """Generate list of spread values from min to max with given increment"""
    spreads = []
    current = min_spread
    while current <= max_spread:
        spreads.append(round(current, 1))
        current += increment
    return spreads


@router.get("", response_model=List[SportEventSchema])
async def get_upcoming_events(
    skip: int = 0,
    limit: int = 20,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Get upcoming sport events available for betting"""
    query = (
        select(SportEvent)
        .where(
            and_(
                SportEvent.status == EventStatus.UPCOMING,
                SportEvent.game_time > datetime.utcnow()
            )
        )
        .order_by(SportEvent.game_time.asc())
        .offset(skip)
        .limit(limit)
    )

    result = await db.execute(query)
    events = result.scalars().all()

    return events


@router.get("/{event_id}", response_model=SportEventWithBets)
async def get_event_with_spread_grid(
    event_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """Get event with spread grid showing available/occupied bets"""
    # Get event
    result = await db.execute(select(SportEvent).where(SportEvent.id == event_id))
    event = result.scalar_one_or_none()

    if not event:
        raise HTTPException(status_code=404, detail="Event not found")

    # Get admin settings for spread increment
    settings_result = await db.execute(select(AdminSettings).limit(1))
    settings = settings_result.scalar_one_or_none()
    spread_increment = settings.spread_increment if settings else 0.5

    # Generate spread grid
    spreads = generate_spread_grid(event.min_spread, event.max_spread, spread_increment)

    # Get all open and matched bets for this event
    bets_result = await db.execute(
        select(SpreadBet)
        .where(
            and_(
                SpreadBet.event_id == event_id,
                SpreadBet.status.in_([SpreadBetStatus.OPEN, SpreadBetStatus.MATCHED])
            )
        )
    )
    bets = bets_result.scalars().all()

    # Build spread grid
    spread_grid = {}
    for spread in spreads:
        # Find bet at this spread (home team perspective)
        bet_at_spread = next(
            (b for b in bets if b.spread == spread and b.team == TeamSide.HOME),
            None
        )
        # Also check negative spread for away team
        opposite_spread = -spread
        bet_at_opposite = next(
            (b for b in bets if b.spread == opposite_spread and b.team == TeamSide.AWAY),
            None
        )

        if bet_at_spread:
            # Get creator info
            creator_result = await db.execute(select(User).where(User.id == bet_at_spread.creator_id))
            creator = creator_result.scalar_one()

            spread_grid[str(spread)] = {
                "bet_id": bet_at_spread.id,
                "creator_id": bet_at_spread.creator_id,
                "creator_username": creator.username,
                "stake": float(bet_at_spread.stake_amount),
                "status": bet_at_spread.status.value,
                "team": bet_at_spread.team.value,
                "can_take": bet_at_spread.status == SpreadBetStatus.OPEN and bet_at_spread.creator_id != current_user.id
            }
        elif bet_at_opposite:
            # There's a bet on the opposite side
            creator_result = await db.execute(select(User).where(User.id == bet_at_opposite.creator_id))
            creator = creator_result.scalar_one()

            spread_grid[str(spread)] = {
                "bet_id": bet_at_opposite.id,
                "creator_id": bet_at_opposite.creator_id,
                "creator_username": creator.username,
                "stake": float(bet_at_opposite.stake_amount),
                "status": bet_at_opposite.status.value,
                "team": bet_at_opposite.team.value,
                "can_take": bet_at_opposite.status == SpreadBetStatus.OPEN and bet_at_opposite.creator_id != current_user.id
            }
        else:
            # No bet at this spread
            spread_grid[str(spread)] = None

    # Convert event to dict and add spread_grid
    event_dict = {
        "id": event.id,
        "sport": event.sport,
        "home_team": event.home_team,
        "away_team": event.away_team,
        "official_spread": event.official_spread,
        "game_time": event.game_time,
        "venue": event.venue,
        "league": event.league,
        "min_spread": event.min_spread,
        "max_spread": event.max_spread,
        "min_bet_amount": event.min_bet_amount,
        "max_bet_amount": event.max_bet_amount,
        "status": event.status,
        "final_score_home": event.final_score_home,
        "final_score_away": event.final_score_away,
        "created_by": event.created_by,
        "created_at": event.created_at,
        "updated_at": event.updated_at,
        "spread_grid": spread_grid
    }

    return event_dict
