from __future__ import annotations

import re
from urllib.parse import parse_qs, urlparse, urlunparse

from app.errors import VaaniError

_HOSTS = {
    "youtube.com",
    "m.youtube.com",
    "music.youtube.com",
    "youtube-nocookie.com",
    "youtu.be",
}
_VIDEO_ID = re.compile(r"^[A-Za-z0-9_-]{11}$")
_PLAYLIST_ID = re.compile(r"^[A-Za-z0-9_-]{8,80}$")
_CHANNEL_TABS = ("/videos", "/shorts", "/streams", "/playlists", "/featured", "/about", "/community")


def is_video_id(value: str) -> bool:
    return bool(_VIDEO_ID.fullmatch(value or ""))


def classify_link(raw: str) -> dict[str, str]:
    text = (raw or "").strip()
    if not text:
        raise VaaniError("Paste a YouTube link.")
    if len(text) > 2000:
        raise VaaniError("That link is too long.")
    if not re.match(r"^https?://", text, flags=re.I):
        if text.startswith(("youtube.com", "www.youtube.com", "youtu.be", "m.youtube.com")):
            text = "https://" + text
        else:
            raise VaaniError("Paste a full YouTube link, starting with https://.")
    parsed = urlparse(text)
    if parsed.username or parsed.password:
        raise VaaniError("Use a YouTube link without a username or password in it.")
    host = (parsed.hostname or "").lower()
    if host.startswith("www."):
        host = host[4:]
    if host not in _HOSTS:
        raise VaaniError("Use a youtube.com or youtu.be link.")
    path = parsed.path or "/"
    query = parse_qs(parsed.query)

    if host == "youtu.be":
        video_id = path.strip("/").split("/")[0]
        if not is_video_id(video_id):
            raise VaaniError("That short link does not contain a video.")
        return {"kind": "video", "url": _watch(video_id), "video_id": video_id}

    parts = [part for part in path.split("/") if part]
    head = parts[0] if parts else ""

    if head in {"watch", "embed", "shorts", "live", "v"}:
        video_id = ""
        if head == "watch":
            video_id = (query.get("v") or [""])[0]
        elif len(parts) > 1:
            video_id = parts[1]
        if is_video_id(video_id):
            return {"kind": "video", "url": _watch(video_id), "video_id": video_id}
        playlist = (query.get("list") or [""])[0]
        if head == "watch" and _PLAYLIST_ID.fullmatch(playlist or ""):
            return {
                "kind": "collection",
                "collection": "playlist",
                "url": f"https://www.youtube.com/playlist?list={playlist}",
            }
        raise VaaniError("That link does not contain a video.")

    if head == "playlist":
        playlist = (query.get("list") or [""])[0]
        if not _PLAYLIST_ID.fullmatch(playlist or ""):
            raise VaaniError("That playlist link is missing its id.")
        return {
            "kind": "collection",
            "collection": "playlist",
            "url": f"https://www.youtube.com/playlist?list={playlist}",
        }

    if head.startswith("@") or head in {"channel", "c", "user"}:
        return {
            "kind": "collection",
            "collection": "channel",
            "url": _videos_url(parsed),
        }

    raise VaaniError("Paste a video link, a channel link, or a playlist link.")


def _watch(video_id: str) -> str:
    return f"https://www.youtube.com/watch?v={video_id}"


def _videos_url(parsed) -> str:
    path = parsed.path.rstrip("/")
    for suffix in _CHANNEL_TABS:
        if path.endswith(suffix):
            path = path[: -len(suffix)]
            break
    if not path or path == "/":
        raise VaaniError("That channel link is missing the channel name.")
    return urlunparse(("https", "www.youtube.com", path + "/videos", "", "", ""))
