from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import and_, case, func, select
from sqlalchemy.ext.asyncio import AsyncSession

from api.deps import get_current_superuser
from database.models import Seat, Ticket, TicketStatus, Tournament, User
from database.session import get_db
from schemas.tournament import SeatGenerateRequest, SeatResponse, TournamentCreate, TournamentResponse

router = APIRouter(prefix="/api/tournaments", tags=["tournaments"])


@router.get("/{tournament_id}/seats", response_model=list[SeatResponse])
async def get_tournament_seats(
    tournament_id: int,
    db: AsyncSession = Depends(get_db),
) -> list[SeatResponse]:
    """
    Публичный эндпоинт. Возвращает все места турнира с флагом is_available.

    Место недоступно (is_available=False), если связанный Ticket
    находится в статусе LOCKED или PAID.
    Используется LEFT OUTER JOIN + CASE для вычисления флага одним запросом.
    """
    # 1. Вычисляем is_available через CASE на стороне БД
    is_available_expr = case(
        (
            and_(
                Ticket.id.is_not(None),
                Ticket.status.in_([TicketStatus.LOCKED, TicketStatus.PAID]),
            ),
            False,
        ),
        else_=True,
    ).label("is_available")

    # 2. LEFT JOIN: берём все места турнира, присоединяем Ticket (если есть)
    stmt = (
        select(Seat, is_available_expr)
        .outerjoin(Ticket, Ticket.seat_id == Seat.id)
        .where(Seat.tournament_id == tournament_id)
        .order_by(Seat.sector, Seat.row, Seat.number)
    )

    # 3. Выполняем запрос и формируем ответ
    result = await db.execute(stmt)
    rows = result.all()

    return [
        SeatResponse(
            id=seat.id,
            sector=seat.sector,
            row=seat.row,
            number=seat.number,
            price=seat.price,
            is_available=bool(is_available),
        )
        for seat, is_available in rows
    ]


@router.post("", response_model=TournamentResponse, status_code=status.HTTP_201_CREATED)
async def create_tournament(
    body: TournamentCreate,
    current_user: User = Depends(get_current_superuser),
    db: AsyncSession = Depends(get_db),
) -> Tournament:
    tournament = Tournament(
        title=body.title,
        description=body.description,
        event_date=body.event_date,
    )
    db.add(tournament)
    await db.commit()
    await db.refresh(tournament)
    return tournament


@router.post(
    "/{tournament_id}/generate-seats",
    status_code=status.HTTP_200_OK,
)
async def generate_seats(
    tournament_id: int,
    request: SeatGenerateRequest,
    current_user: User = Depends(get_current_superuser),
    db: AsyncSession = Depends(get_db),
) -> dict[str, str]:
    # 1. Проверяем существование турнира
    result = await db.execute(select(Tournament).where(Tournament.id == tournament_id))
    tournament: Tournament | None = result.scalar_one_or_none()
    if tournament is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Tournament not found")

    # 2. Проверяем, что места ещё не генерировались (защита от дублей)
    count_result = await db.execute(
        select(func.count()).where(Seat.tournament_id == tournament_id)
    )
    existing_count: int = count_result.scalar_one()
    if existing_count > 0:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Места уже сгенерированы",
        )

    # 3. Генерируем места для каждого сектора
    seats: list[Seat] = []
    for sector_cfg in request.sectors:
        for row in range(1, sector_cfg.rows + 1):
            for number in range(1, sector_cfg.seats_per_row + 1):
                seats.append(
                    Seat(
                        tournament_id=tournament_id,
                        sector=sector_cfg.sector_name,
                        row=row,
                        number=number,
                        price=sector_cfg.price,
                    )
                )

    # 4. Массовая вставка
    db.add_all(seats)
    await db.commit()

    return {"message": f"Generated {len(seats)} seats successfully"}
