from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from ..database import get_db
from ..db_models import Opening, OpeningPoster
from ..schemas import (
    OpeningCreate,
    OpeningUpdate,
    OpeningResponse,
    OpeningListResponse,
    OpeningPosterResponse,
    AddPosterRequest,
)

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


@router.get("", response_model=OpeningListResponse)
async def list_openings(
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=500),
    search: Optional[str] = None,
    db: AsyncSession = Depends(get_db),
):
    """List all openings with pagination and search."""
    query = select(Opening).options(selectinload(Opening.posters))

    if search:
        query = query.where(Opening.anime_name.ilike(f"%{search}%"))

    # Count total
    count_query = select(func.count(Opening.id))
    if search:
        count_query = count_query.where(Opening.anime_name.ilike(f"%{search}%"))
    total_result = await db.execute(count_query)
    total = total_result.scalar()

    # Get items
    query = query.order_by(Opening.anime_name, Opening.op_number)
    query = query.offset(skip).limit(limit)
    result = await db.execute(query)
    openings = result.scalars().all()

    return OpeningListResponse(openings=openings, total=total)


@router.get("/{opening_id}", response_model=OpeningResponse)
async def get_opening(opening_id: int, db: AsyncSession = Depends(get_db)):
    """Get a single opening by ID."""
    query = select(Opening).options(selectinload(Opening.posters)).where(Opening.id == opening_id)
    result = await db.execute(query)
    opening = result.scalar_one_or_none()

    if not opening:
        raise HTTPException(status_code=404, detail="Opening not found")

    return opening


@router.post("", response_model=OpeningResponse, status_code=201)
async def create_opening(data: OpeningCreate, db: AsyncSession = Depends(get_db)):
    """Create a new opening."""
    opening = Opening(
        anime_name=data.anime_name,
        op_number=data.op_number,
        song_name=data.song_name,
        audio_file=data.audio_file,
    )

    # Add posters
    for i, poster_file in enumerate(data.poster_files):
        poster = OpeningPoster(
            poster_file=poster_file,
            is_default=(i == 0)  # First poster is default
        )
        opening.posters.append(poster)

    db.add(opening)
    await db.commit()
    await db.refresh(opening)

    # Reload with posters
    query = select(Opening).options(selectinload(Opening.posters)).where(Opening.id == opening.id)
    result = await db.execute(query)
    return result.scalar_one()


@router.put("/{opening_id}", response_model=OpeningResponse)
async def update_opening(
    opening_id: int,
    data: OpeningUpdate,
    db: AsyncSession = Depends(get_db),
):
    """Update an opening."""
    query = select(Opening).options(selectinload(Opening.posters)).where(Opening.id == opening_id)
    result = await db.execute(query)
    opening = result.scalar_one_or_none()

    if not opening:
        raise HTTPException(status_code=404, detail="Opening not found")

    # Update fields
    if data.anime_name is not None:
        opening.anime_name = data.anime_name
    if data.op_number is not None:
        opening.op_number = data.op_number
    if data.song_name is not None:
        opening.song_name = data.song_name
    if data.audio_file is not None:
        opening.audio_file = data.audio_file

    await db.commit()
    await db.refresh(opening)

    return opening


@router.delete("/{opening_id}", status_code=204)
async def delete_opening(opening_id: int, db: AsyncSession = Depends(get_db)):
    """Delete an opening."""
    query = select(Opening).where(Opening.id == opening_id)
    result = await db.execute(query)
    opening = result.scalar_one_or_none()

    if not opening:
        raise HTTPException(status_code=404, detail="Opening not found")

    await db.delete(opening)
    await db.commit()


# ============== Poster Management ==============

@router.post("/{opening_id}/posters", response_model=OpeningPosterResponse, status_code=201)
async def add_poster(
    opening_id: int,
    data: AddPosterRequest,
    db: AsyncSession = Depends(get_db),
):
    """Add a poster to an opening."""
    query = select(Opening).where(Opening.id == opening_id)
    result = await db.execute(query)
    opening = result.scalar_one_or_none()

    if not opening:
        raise HTTPException(status_code=404, detail="Opening not found")

    poster = OpeningPoster(
        opening_id=opening_id,
        poster_file=data.poster_file,
        is_default=data.is_default,
    )

    # If this is set as default, unset others
    if data.is_default:
        await db.execute(
            select(OpeningPoster)
            .where(OpeningPoster.opening_id == opening_id)
        )
        posters_result = await db.execute(
            select(OpeningPoster).where(OpeningPoster.opening_id == opening_id)
        )
        for p in posters_result.scalars():
            p.is_default = False

    db.add(poster)
    await db.commit()
    await db.refresh(poster)

    return poster


@router.delete("/{opening_id}/posters/{poster_id}", status_code=204)
async def remove_poster(
    opening_id: int,
    poster_id: int,
    db: AsyncSession = Depends(get_db),
):
    """Remove a poster from an opening."""
    query = select(OpeningPoster).where(
        OpeningPoster.id == poster_id,
        OpeningPoster.opening_id == opening_id,
    )
    result = await db.execute(query)
    poster = result.scalar_one_or_none()

    if not poster:
        raise HTTPException(status_code=404, detail="Poster not found")

    await db.delete(poster)
    await db.commit()


@router.post("/{opening_id}/posters/{poster_id}/set-default", response_model=OpeningPosterResponse)
async def set_default_poster(
    opening_id: int,
    poster_id: int,
    db: AsyncSession = Depends(get_db),
):
    """Set a poster as the default for an opening."""
    # Get all posters for this opening
    query = select(OpeningPoster).where(OpeningPoster.opening_id == opening_id)
    result = await db.execute(query)
    posters = result.scalars().all()

    target_poster = None
    for poster in posters:
        if poster.id == poster_id:
            poster.is_default = True
            target_poster = poster
        else:
            poster.is_default = False

    if not target_poster:
        raise HTTPException(status_code=404, detail="Poster not found")

    await db.commit()
    await db.refresh(target_poster)

    return target_poster
