"""Queue management endpoints."""

from __future__ import annotations

import uuid
from datetime import datetime
from typing import List

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select, func, delete, and_
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.deps import get_user_id, get_db_session
from app.models import Episode, Show, QueueItem, Progress, PlaybackEvent

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


# ── Schemas ──

class QueueAddRequest(BaseModel):
    episode_id: str


class QueueReorderRequest(BaseModel):
    episode_ids: List[str]


# ── Endpoints ──

@router.get("")
async def get_queue(
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Get user's queue ordered by sort_order, with episode and show info."""
    stmt = (
        select(QueueItem, Episode, Show)
        .join(Episode, Episode.id == QueueItem.episode_id)
        .join(Show, Show.id == Episode.show_id)
        .where(QueueItem.user_id == user_id)
        .order_by(QueueItem.sort_order)
    )
    result = await db.execute(stmt)
    rows = result.all()

    return [
        {
            "queue_id": str(qi.id),
            "sort_order": qi.sort_order,
            "added_at": qi.added_at.isoformat() if qi.added_at else None,
            "episode": {
                "id": str(ep.id),
                "title": ep.title,
                "audio_url": ep.audio_url,
                "duration_seconds": ep.duration_seconds,
                "artwork_url": ep.artwork_url or show.artwork_url,
                "published_at": ep.published_at.isoformat() if ep.published_at else None,
            },
            "show": {
                "id": str(show.id),
                "title": show.title,
                "author": show.author,
                "artwork_url": show.artwork_url,
            },
        }
        for qi, ep, show in rows
    ]


@router.post("/add", status_code=201)
async def add_to_queue(
    body: QueueAddRequest,
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Add episode to end of queue."""
    eid = uuid.UUID(body.episode_id)
    ep = await db.get(Episode, eid)
    if not ep or ep.user_id != user_id:
        raise HTTPException(404, "Episode not found")

    # Check if already in queue
    existing = await db.execute(
        select(QueueItem).where(QueueItem.user_id == user_id, QueueItem.episode_id == eid)
    )
    if existing.scalar_one_or_none():
        raise HTTPException(409, "Episode already in queue")

    # Get max sort_order
    max_order = await db.scalar(
        select(func.coalesce(func.max(QueueItem.sort_order), -1)).where(QueueItem.user_id == user_id)
    )

    qi = QueueItem(
        user_id=user_id,
        episode_id=eid,
        sort_order=max_order + 1,
    )
    db.add(qi)
    await db.commit()
    return {"status": "added", "sort_order": qi.sort_order}


@router.post("/play-next", status_code=201)
async def play_next(
    body: QueueAddRequest,
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Insert episode at position 1 (after currently playing)."""
    eid = uuid.UUID(body.episode_id)
    ep = await db.get(Episode, eid)
    if not ep or ep.user_id != user_id:
        raise HTTPException(404, "Episode not found")

    # Remove if already in queue
    await db.execute(
        delete(QueueItem).where(QueueItem.user_id == user_id, QueueItem.episode_id == eid)
    )

    # Shift all items at position >= 1 up by 1
    stmt = (
        select(QueueItem)
        .where(QueueItem.user_id == user_id, QueueItem.sort_order >= 1)
        .order_by(QueueItem.sort_order.desc())
    )
    items = (await db.execute(stmt)).scalars().all()
    for item in items:
        item.sort_order += 1

    qi = QueueItem(user_id=user_id, episode_id=eid, sort_order=1)
    db.add(qi)
    await db.commit()
    return {"status": "added", "sort_order": 1}


@router.post("/play-now", status_code=201)
async def play_now(
    body: QueueAddRequest,
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Insert at position 0 and start playing."""
    eid = uuid.UUID(body.episode_id)
    ep = await db.get(Episode, eid)
    if not ep or ep.user_id != user_id:
        raise HTTPException(404, "Episode not found")

    # Remove if already in queue
    await db.execute(
        delete(QueueItem).where(QueueItem.user_id == user_id, QueueItem.episode_id == eid)
    )

    # Shift everything up
    stmt = (
        select(QueueItem)
        .where(QueueItem.user_id == user_id)
        .order_by(QueueItem.sort_order.desc())
    )
    items = (await db.execute(stmt)).scalars().all()
    for item in items:
        item.sort_order += 1

    qi = QueueItem(user_id=user_id, episode_id=eid, sort_order=0)
    db.add(qi)

    # Also create/update progress and log play event
    prog_stmt = select(Progress).where(Progress.user_id == user_id, Progress.episode_id == eid)
    prog = (await db.execute(prog_stmt)).scalar_one_or_none()
    if not prog:
        prog = Progress(
            user_id=user_id,
            episode_id=eid,
            duration_seconds=ep.duration_seconds,
        )
        db.add(prog)
    prog.last_played_at = datetime.utcnow()
    prog.is_completed = False

    db.add(PlaybackEvent(
        user_id=user_id,
        episode_id=eid,
        event_type="play",
        position_seconds=prog.position_seconds or 0,
        playback_speed=prog.playback_speed,
    ))

    await db.commit()
    return {"status": "playing", "sort_order": 0}


@router.delete("/{episode_id}", status_code=204)
async def remove_from_queue(
    episode_id: str,
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Remove episode from queue."""
    eid = uuid.UUID(episode_id)
    result = await db.execute(
        delete(QueueItem).where(QueueItem.user_id == user_id, QueueItem.episode_id == eid)
    )
    if result.rowcount == 0:
        raise HTTPException(404, "Episode not in queue")
    await db.commit()


@router.post("/reorder")
async def reorder_queue(
    body: QueueReorderRequest,
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Reorder queue by providing episode IDs in desired order."""
    for i, eid_str in enumerate(body.episode_ids):
        eid = uuid.UUID(eid_str)
        stmt = select(QueueItem).where(QueueItem.user_id == user_id, QueueItem.episode_id == eid)
        qi = (await db.execute(stmt)).scalar_one_or_none()
        if qi:
            qi.sort_order = i

    await db.commit()
    return {"status": "reordered", "count": len(body.episode_ids)}


@router.delete("")
async def clear_queue(
    user_id: str = Depends(get_user_id),
    db: AsyncSession = Depends(get_db_session),
):
    """Clear entire queue."""
    await db.execute(delete(QueueItem).where(QueueItem.user_id == user_id))
    await db.commit()
    return {"status": "cleared"}
