"""
Generated Videos – list, detail, download, delete.
Download uses the Authorization header (passed as query param for browser links).
"""
from typing import Optional
from fastapi import APIRouter, Depends, Query, HTTPException, Request, Header
from fastapi.responses import FileResponse, StreamingResponse
import os
import re
import mimetypes
from app.middleware.auth import require_auth
from app.repository.store import videos_store
from app.utils.response import ok, err
from app.config import cfg
from app.utils.jwt import verify_token

router = APIRouter()


def _auth_from_query_or_header(token: Optional[str], authorization: Optional[str]) -> str:
    """
    Validate auth for media endpoints used directly by <video>/<img> tags, which
    cannot send an Authorization header. Accepts ?token=<jwt> OR Bearer header.
    """
    raw = token
    if not raw and authorization and authorization.lower().startswith("bearer "):
        raw = authorization.split(" ", 1)[1]
    if not raw:
        raise HTTPException(status_code=401, detail="Missing token")
    return verify_token(raw)


_RANGE_RE = re.compile(r"bytes=(\d*)-(\d*)")


def _ranged_file(path: str, range_header: Optional[str], media_type: str):
    """Return a StreamingResponse honoring an HTTP Range request (seek/scrub)."""
    file_size = os.path.getsize(path)
    start, end = 0, file_size - 1
    status_code = 200
    headers = {
        "Accept-Ranges": "bytes",
        "Content-Type": media_type,
        "Cache-Control": "no-cache",
    }

    if range_header:
        m = _RANGE_RE.match(range_header)
        if m:
            g1, g2 = m.group(1), m.group(2)
            if g1:
                start = int(g1)
            if g2:
                end = int(g2)
            if g1 == "" and g2:  # suffix bytes=-N
                start = max(0, file_size - int(g2))
                end = file_size - 1
            start = max(0, start)
            end = min(end, file_size - 1)
            status_code = 206
            headers["Content-Range"] = f"bytes {start}-{end}/{file_size}"

    length = end - start + 1
    headers["Content-Length"] = str(length)

    def _iter(chunk=1024 * 512):
        remaining = length
        with open(path, "rb") as f:
            f.seek(start)
            while remaining > 0:
                data = f.read(min(chunk, remaining))
                if not data:
                    break
                remaining -= len(data)
                yield data

    return StreamingResponse(_iter(), status_code=status_code,
                             headers=headers, media_type=media_type)


@router.get("/")
async def list_videos(
    page: int = Query(1, ge=1),
    per_page: int = Query(12, ge=1, le=100),
    search: Optional[str] = Query(None),
    status: Optional[str] = Query(None),
    _: str = Depends(require_auth),
):
    result = videos_store.list(
        filters={"status": status} if status else None,
        search=search, search_fields=["title"],
        page=page, per_page=per_page,
    )
    return ok(result)


@router.get("/{vid}")
async def get_video(vid: str, _: str = Depends(require_auth)):
    v = videos_store.get(vid)
    return ok(v) if v else err("Not found", 404)


@router.delete("/{vid}")
async def delete_video(vid: str, _: str = Depends(require_auth)):
    v = videos_store.get(vid)
    if not v:
        return err("Not found", 404)
    # Remove file from disk
    file_path = os.path.join(cfg.OUTPUT_DIR, v.get("filename", ""))
    if os.path.exists(file_path):
        try:
            os.remove(file_path)
        except Exception:
            pass
    return ok(None, "Deleted") if videos_store.delete(vid) else err("Not found", 404)


@router.get("/{vid}/download")
async def download(
    vid: str,
    token: Optional[str] = Query(None),  # allows browser download links
    _: str = Depends(require_auth),
):
    """
    Download the generated MP4.
    Auth via Bearer header OR ?token=<jwt> query param (for direct browser links).
    """
    v = videos_store.get(vid)
    if not v:
        raise HTTPException(status_code=404, detail="Video not found")

    filename = v.get("filename", "")
    file_path = os.path.join(cfg.OUTPUT_DIR, filename)

    if not filename or not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="Video file not found on disk")

    return FileResponse(
        path=file_path,
        media_type="video/mp4",
        filename=filename,
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


@router.get("/{vid}/stream")
async def stream(
    vid: str,
    request: Request,
    token: Optional[str] = Query(None),
    authorization: Optional[str] = Header(None),
):
    """
    Stream the MP4 with HTTP Range support so the in-app player can play,
    pause, scrub and replay without downloading the whole file.
    """
    _auth_from_query_or_header(token, authorization)
    v = videos_store.get(vid)
    if not v:
        raise HTTPException(status_code=404, detail="Video not found")
    file_path = os.path.join(cfg.OUTPUT_DIR, v.get("filename", ""))
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="Video file not found on disk")
    return _ranged_file(file_path, request.headers.get("range"), "video/mp4")


@router.get("/{vid}/thumbnail")
async def thumbnail(
    vid: str,
    token: Optional[str] = Query(None),
    authorization: Optional[str] = Header(None),
):
    """Return the auto-generated poster frame (JPG) for the video."""
    _auth_from_query_or_header(token, authorization)
    v = videos_store.get(vid)
    if not v:
        raise HTTPException(status_code=404, detail="Video not found")
    thumb = v.get("thumbnail")
    if not thumb:
        raise HTTPException(status_code=404, detail="No thumbnail")
    thumb_path = os.path.join(cfg.OUTPUT_DIR, thumb)
    if not os.path.exists(thumb_path):
        raise HTTPException(status_code=404, detail="Thumbnail file not found")
    return FileResponse(thumb_path, media_type=mimetypes.guess_type(thumb_path)[0] or "image/jpeg")
