"""Shorts generation API endpoints.

Trigger short generation from approved highlights, list generated shorts,
and get presigned download URLs.
"""

from __future__ import annotations

import logging
from datetime import datetime

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

from database import get_session
from models import (
    FormatPreset,
    GeneratedShort,
    HighlightCandidate,
    HighlightStatus,
    ShortStatus,
)

logger = logging.getLogger("chrysopedia.shorts")

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


# ── Response schemas ─────────────────────────────────────────────────────────


class GeneratedShortResponse(BaseModel):
    id: str
    highlight_candidate_id: str
    format_preset: str
    status: str
    error_message: str | None = None
    file_size_bytes: int | None = None
    duration_secs: float | None = None
    width: int
    height: int
    share_token: str | None = None
    created_at: datetime

    model_config = {"from_attributes": True}


class ShortsListResponse(BaseModel):
    shorts: list[GeneratedShortResponse]


class GenerateResponse(BaseModel):
    status: str
    message: str


# ── Endpoints ────────────────────────────────────────────────────────────────


@router.post("/generate/{highlight_id}", response_model=GenerateResponse, status_code=202)
async def generate_shorts(
    highlight_id: str,
    captions: bool = True,
    db: AsyncSession = Depends(get_session),
):
    """Dispatch shorts generation for an approved highlight candidate.

    Creates pending GeneratedShort rows for each format preset and dispatches
    the Celery task. Returns 202 Accepted with status.

    Args:
        highlight_id: UUID of the approved highlight candidate.
        captions: Whether to burn in Whisper-generated subtitles (default True).
    """
    # Validate highlight exists and is approved
    stmt = select(HighlightCandidate).where(HighlightCandidate.id == highlight_id)
    result = await db.execute(stmt)
    highlight = result.scalar_one_or_none()

    if highlight is None:
        raise HTTPException(status_code=404, detail=f"Highlight not found: {highlight_id}")

    if highlight.status != HighlightStatus.approved:
        raise HTTPException(
            status_code=400,
            detail=f"Highlight must be approved before generating shorts (current: {highlight.status.value})",
        )

    # Check if shorts are already processing
    existing_stmt = (
        select(GeneratedShort)
        .where(
            GeneratedShort.highlight_candidate_id == highlight_id,
            GeneratedShort.status.in_([ShortStatus.pending, ShortStatus.processing]),
        )
    )
    existing_result = await db.execute(existing_stmt)
    in_progress = existing_result.scalars().all()

    if in_progress:
        raise HTTPException(
            status_code=409,
            detail="Shorts generation already in progress for this highlight",
        )

    # Dispatch Celery task
    from pipeline.stages import stage_generate_shorts

    try:
        task = stage_generate_shorts.delay(highlight_id, captions=captions)
        logger.info(
            "Shorts generation dispatched highlight_id=%s task_id=%s",
            highlight_id,
            task.id,
        )
    except Exception as exc:
        logger.warning(
            "Failed to dispatch shorts generation for highlight_id=%s: %s",
            highlight_id,
            exc,
        )
        raise HTTPException(
            status_code=503,
            detail="Shorts generation dispatch failed — Celery/Redis may be unavailable",
        ) from exc

    return GenerateResponse(
        status="dispatched",
        message=f"Shorts generation dispatched for highlight {highlight_id}",
    )


@router.get("/{highlight_id}", response_model=ShortsListResponse)
async def list_shorts(
    highlight_id: str,
    db: AsyncSession = Depends(get_session),
):
    """List all generated shorts for a highlight candidate."""
    # Verify highlight exists
    hl_stmt = select(HighlightCandidate.id).where(HighlightCandidate.id == highlight_id)
    hl_result = await db.execute(hl_stmt)
    if hl_result.scalar_one_or_none() is None:
        raise HTTPException(status_code=404, detail=f"Highlight not found: {highlight_id}")

    stmt = (
        select(GeneratedShort)
        .where(GeneratedShort.highlight_candidate_id == highlight_id)
        .order_by(GeneratedShort.format_preset)
    )
    result = await db.execute(stmt)
    shorts = result.scalars().all()

    return ShortsListResponse(
        shorts=[
            GeneratedShortResponse(
                id=str(s.id),
                highlight_candidate_id=str(s.highlight_candidate_id),
                format_preset=s.format_preset.value,
                status=s.status.value,
                error_message=s.error_message,
                file_size_bytes=s.file_size_bytes,
                duration_secs=s.duration_secs,
                width=s.width,
                height=s.height,
                share_token=s.share_token,
                created_at=s.created_at,
            )
            for s in shorts
        ]
    )


@router.get("/download/{short_id}")
async def download_short(
    short_id: str,
    db: AsyncSession = Depends(get_session),
):
    """Get a presigned download URL for a completed short."""
    stmt = select(GeneratedShort).where(GeneratedShort.id == short_id)
    result = await db.execute(stmt)
    short = result.scalar_one_or_none()

    if short is None:
        raise HTTPException(status_code=404, detail=f"Short not found: {short_id}")

    if short.status != ShortStatus.complete:
        raise HTTPException(
            status_code=400,
            detail=f"Short is not complete (current: {short.status.value})",
        )

    if not short.minio_object_key:
        raise HTTPException(
            status_code=500,
            detail="Short marked complete but has no storage key",
        )

    from minio_client import generate_download_url

    try:
        url = generate_download_url(short.minio_object_key)
    except Exception as exc:
        logger.error("Failed to generate download URL for short_id=%s: %s", short_id, exc)
        raise HTTPException(
            status_code=503,
            detail="Failed to generate download URL — MinIO may be unavailable",
        ) from exc

    return {"download_url": url, "format_preset": short.format_preset.value}
