"""Channel API routes."""

from __future__ import annotations

import asyncio
from concurrent.futures import ThreadPoolExecutor

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel

from api.deps import get_admin_user

from core import youtube, cache

_executor = ThreadPoolExecutor(max_workers=4)

router = APIRouter()


class ChannelCreate(BaseModel):
    channel_id: str
    channel_name: str
    title_filter: str | None = None


@router.get("")
def list_channels():
    key = cache.make_key("channels")
    cached = cache.get(key)
    if cached is not None:
        return cached
    result = youtube.get_active_channels()
    cache.set(key, result)
    return result


@router.post("", status_code=201)
def create_channel(body: ChannelCreate, _admin: dict = Depends(get_admin_user)):
    try:
        row_id = youtube.add_channel(body.channel_id, body.channel_name, body.title_filter)
        cache.flush()
        return {"id": row_id, "channel_id": body.channel_id}
    except Exception as e:
        if "UQ_CHANNELS_CID" in str(e).upper():
            raise HTTPException(409, "Channel already exists")
        raise


def _do_scan(channel_id: str, full: bool):
    """Sync scan logic, runs in thread pool."""
    channels = youtube.get_active_channels()
    ch = next((c for c in channels if c["channel_id"] == channel_id), None)
    if not ch:
        return None

    after = None if full else youtube.get_latest_video_date(ch["id"])
    title_filter = ch.get("title_filter")
    existing_vids = youtube.get_existing_video_ids(ch["id"])

    candidates = []
    total_fetched = 0
    for videos_page in youtube.fetch_channel_videos_iter(channel_id, published_after=after):
        total_fetched += len(videos_page)
        new_in_page = 0
        for v in videos_page:
            if title_filter and title_filter not in v["title"]:
                continue
            if v["video_id"] in existing_vids:
                continue
            candidates.append(v)
            new_in_page += 1
        if not full and new_in_page == 0 and total_fetched > 50:
            break

    filtered = total_fetched - len(candidates) - len([v for v in candidates if v["video_id"] in existing_vids])
    new_count = youtube.save_videos_batch(ch["id"], candidates)
    if new_count > 0:
        cache.flush()
    return {"total_fetched": total_fetched, "new_videos": new_count, "filtered": filtered if title_filter else 0}


@router.post("/{channel_id}/scan")
async def scan_channel(channel_id: str, full: bool = False, _admin: dict = Depends(get_admin_user)):
    """Trigger a scan for new videos from this channel (non-blocking)."""
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(_executor, _do_scan, channel_id, full)
    if result is None:
        raise HTTPException(404, "Channel not found")
    return result


@router.delete("/{channel_id:path}")
def delete_channel(channel_id: str, _admin: dict = Depends(get_admin_user)):
    """Deactivate a channel. Accepts channel_id or DB id."""
    deleted = youtube.deactivate_channel(channel_id)
    if not deleted:
        # Try by DB id
        deleted = youtube.deactivate_channel_by_db_id(channel_id)
    if not deleted:
        raise HTTPException(404, "Channel not found")
    cache.flush()
    return {"ok": True}
