"""
Video streaming routes for Ohm Stream Downloader API.
"""

import os
import re
from pathlib import Path

from fastapi import APIRouter, HTTPException, Request
from fastapi.responses import Response, StreamingResponse

from app.models import DownloadStatus

router = APIRouter(tags=["player"])


def get_download_manager():
    from main import download_manager

    return download_manager


from app.downloaders import get_downloader

@router.get("/api/player/embed")
async def get_player_embed(request: Request, url: str):
    """
    Get an embedded video player for a given episode URL.
    This route extracts the direct video link and returns an HTML fragment.
    """
    from main import templates
    
    try:
        # 1. Get the downloader for the anime site (e.g. Anime-Sama)
        downloader = get_downloader(url)
        if not downloader:
            raise HTTPException(status_code=400, detail="No downloader found for this URL")
            
        # 2. Get the video player URL (embed URL like VidMoly, DoodStream, etc.)
        video_url, _ = await downloader.get_download_link(url)
        
        # 3. Get the direct video file link from the player
        player_handler = get_downloader(video_url)
        if not player_handler:
            # If no direct extractor, we might have to use an iframe
            return templates.TemplateResponse(
                "components/player_embed.html",
                {
                    "request": request,
                    "video_url": video_url,
                    "is_iframe": True
                }
            )
            
        direct_url, filename = await player_handler.get_download_link(video_url)
        
        return templates.TemplateResponse(
            "components/player_embed.html",
            {
                "request": request,
                "video_url": direct_url,
                "filename": filename,
                "is_iframe": False
            }
        )
    except Exception as e:
        import logging
        logging.getLogger(__name__).error(f"Embed error: {e}", exc_info=True)
        return f"<div class='error-msg'>Erreur lors de l'extraction de la vidéo : {str(e)}</div>"


@router.get("/video/{task_id}")
async def stream_video(task_id: str, request: Request):
    """Stream a video file with Range support for seeking"""
    download_manager = get_download_manager()
    task = download_manager.get_task(task_id)

    if not task:
        raise HTTPException(status_code=404, detail="Task not found")

    if task.status != DownloadStatus.COMPLETED:
        raise HTTPException(status_code=400, detail="Download not completed")

    if not task.file_path or not os.path.exists(task.file_path):
        raise HTTPException(status_code=404, detail="File not found")

    file_path = Path(task.file_path)
    file_size = file_path.stat().st_size

    range_header = request.headers.get("range")
    headers = {
        "Accept-Ranges": "bytes",
        "Content-Type": "video/mp4",
    }

    if range_header:
        try:
            range_match = re.match(r"bytes=(\d+)-(\d*)", range_header)
            start = int(range_match.group(1))
            end = int(range_match.group(2)) if range_match.group(2) else file_size - 1

            if start >= file_size or end >= file_size or start > end:
                headers["Content-Range"] = f"bytes */{file_size}"
                return Response(
                    status_code=416,
                    headers=headers,
                    content="Requested Range Not Satisfiable",
                )

            content_length = end - start + 1
            headers["Content-Range"] = f"bytes {start}-{end}/{file_size}"
            headers["Content-Length"] = str(content_length)

            def video_range_reader():
                with open(file_path, "rb") as f:
                    f.seek(start)
                    remaining = content_length
                    while remaining > 0:
                        chunk_size = min(1024 * 1024, remaining)
                        data = f.read(chunk_size)
                        if not data:
                            break
                        remaining -= len(data)
                        yield data

            return Response(
                content=video_range_reader(), status_code=206, headers=headers
            )
        except Exception as e:
            raise HTTPException(status_code=400, detail=f"Invalid Range header: {e}")
    else:

        def video_reader():
            with open(file_path, "rb") as f:
                while True:
                    data = f.read(1024 * 1024)
                    if not data:
                        break
                    yield data

        headers["Content-Length"] = str(file_size)
        return Response(content=video_reader(), headers=headers)


@router.get("/stream/{filename}")
async def stream_video_by_filename(filename: str, request: Request):
    """Stream a video file by filename with Range support"""
    filename = os.path.basename(filename)
    file_path = Path("downloads") / filename

    if not file_path.exists():
        raise HTTPException(status_code=404, detail="File not found")

    file_size = file_path.stat().st_size
    range_header = request.headers.get("range")

    if range_header:
        try:
            range_match = re.match(r"bytes=(\d+)-(\d*)", range_header)
            start = int(range_match.group(1))
            end = int(range_match.group(2)) if range_match.group(2) else file_size - 1

            if start >= file_size or end >= file_size or start > end:
                return Response(
                    status_code=416,
                    headers={
                        "Content-Range": f"bytes */{file_size}",
                        "Accept-Ranges": "bytes",
                    },
                    content="Requested Range Not Satisfiable",
                )

            content_length = end - start + 1

            def video_range_reader():
                with open(file_path, "rb") as f:
                    f.seek(start)
                    remaining = content_length
                    while remaining > 0:
                        chunk_size = min(1024 * 1024, remaining)
                        data = f.read(chunk_size)
                        if not data:
                            break
                        remaining -= len(data)
                        yield data

            return StreamingResponse(
                video_range_reader(),
                status_code=206,
                headers={
                    "Content-Range": f"bytes {start}-{end}/{file_size}",
                    "Content-Length": str(content_length),
                    "Accept-Ranges": "bytes",
                    "Content-Type": "video/mp4",
                },
            )
        except Exception as e:
            raise HTTPException(status_code=400, detail=f"Invalid Range header: {e}")
    else:

        def video_reader():
            with open(file_path, "rb") as f:
                while True:
                    data = f.read(1024 * 1024)
                    if not data:
                        break
                    yield data

        return StreamingResponse(
            video_reader(),
            headers={
                "Content-Length": str(file_size),
                "Accept-Ranges": "bytes",
                "Content-Type": "video/mp4",
            },
        )


@router.get("/player/{task_id}")
async def video_player(request: Request, task_id: str):
    """Video player page for watching downloaded anime"""
    from main import download_manager, templates

    task = download_manager.get_task(task_id)
    if not task:
        raise HTTPException(status_code=404, detail="Task not found")

    if task.status != DownloadStatus.COMPLETED:
        raise HTTPException(status_code=400, detail="Download not completed")

    if not task.file_path or not os.path.exists(task.file_path):
        raise HTTPException(status_code=404, detail="File not found")

    file_path = Path(task.file_path)
    file_size = file_path.stat().st_size
    estimated_duration_seconds = int(file_size / (1.5 * 1024 * 1024))

    return templates.TemplateResponse(
        "player.html",
        {
            "request": request,
            "task_id": task_id,
            "filename": task.filename,
            "file_size": file_size,
            "estimated_duration": estimated_duration_seconds,
        },
    )


@router.get("/watch/{filename}")
async def video_player_by_filename(request: Request, filename: str):
    """Video player page for watching downloaded anime by filename"""
    from main import templates
    from app.utils import is_safe_filename, sanitize_filename

    filename = sanitize_filename(filename)

    if not is_safe_filename(filename):
        raise HTTPException(
            status_code=400,
            detail="Invalid filename. Path traversal attempts are not allowed.",
        )

    file_path = Path("downloads") / filename

    if not file_path.exists():
        raise HTTPException(status_code=404, detail="File not found")

    file_size = file_path.stat().st_size
    estimated_duration_seconds = int(file_size / (1.5 * 1024 * 1024))

    return templates.TemplateResponse(
        "player.html",
        {
            "request": request,
            "task_id": filename,
            "filename": filename,
            "file_size": file_size,
            "estimated_duration": estimated_duration_seconds,
        },
    )
