import re
import asyncio
import inspect
from YouTubeMusic.Search import Search
from YouTubeMusic.Stream import get_stream, get_video_stream
from YouTubeMusic.Playlist import get_playlist_songs
from AbhiCalls.settings import settings

PLAYLIST_REGEX = re.compile(r"(list=)")
YOUTUBE_REGEX = re.compile(r"(youtube\.com|youtu\.be|music\.youtube\.com)")


# ==============================
# HELPERS
# ==============================

def sec_to_mmss(sec):
    try:
        sec = int(sec)
        return f"{sec // 60}:{sec % 60:02d}"
    except Exception:
        return "0:00"


def yt_thumbnail(url: str):
    try:
        if "watch?v=" in url:
            vid = url.split("watch?v=")[1].split("&")[0]
        elif "youtu.be/" in url:
            vid = url.split("youtu.be/")[1].split("?")[0]
        else:
            return None
        return f"https://i.ytimg.com/vi/{vid}/hqdefault.jpg"
    except Exception:
        return None


async def safe_extract(extractor, url, cookies):
    """
    Handles both sync and async extractors safely
    """
    if inspect.iscoroutinefunction(extractor):
        return await extractor(url, cookies)
    return await asyncio.to_thread(extractor, url, cookies)


def extract_channel(item):
    channel = item.get("channel")
    if isinstance(channel, dict):
        return channel.get("name", "Unknown")
    if isinstance(channel, str):
        return channel
    return "Unknown"


# ==============================
# MAIN RESOLVER
# ==============================

async def resolve_query(
    query: str,
    cookies: str | None = None,
    video: bool = False
):
    print(f"[Resolver] query={query} | video={video}")

    cookies = cookies or settings.cookies

    if settings.require_cookies and not cookies:
        raise RuntimeError("[Resolver] Cookies required but missing")

    extractor = get_video_stream if video else get_stream

    # ==============================
    # PLAYLIST
    # ==============================
    if PLAYLIST_REGEX.search(query):
        print("[Resolver] mode=playlist")

        playlist = await get_playlist_songs(query)
        songs = []

        for item in playlist:
            url = item.get("url")
            if not url:
                continue

            try:
                stream = await safe_extract(extractor, url, cookies)
            except Exception as e:
                print(f"[Resolver:StreamError] {url} → {e}")
                continue

            if not stream:
                continue

            songs.append({
                "title": item.get("title", "Unknown"),
                "url": url,
                "duration": sec_to_mmss(item.get("duration", 0)),
                "views": item.get("views", "Unknown"),
                "channel": extract_channel(item),
                "thumb": yt_thumbnail(url),
                "stream": stream,
                "is_video": video,
            })

        return songs or None

    # ==============================
    # DIRECT LINK
    # ==============================
    if YOUTUBE_REGEX.search(query):
        print("[Resolver] mode=direct")

        stream = await safe_extract(extractor, query, cookies)

        if not stream:
            raise RuntimeError(f"[Resolver] Stream extraction failed → {query}")

        return [{
            "title": "YouTube Video" if video else "YouTube Audio",
            "url": query,
            "duration": "0:00",
            "views": "Unknown",
            "channel": "YouTube",
            "thumb": yt_thumbnail(query),
            "stream": stream,
            "is_video": video,
        }]

    # ==============================
    # SEARCH
    # ==============================
    print("[Resolver] mode=search")

    res = await Search(query, limit=1)

    if not res or not res.get("main_results"):
        return None

    item = res["main_results"][0]
    url = item.get("url")

    if not url:
        return None

    stream = await safe_extract(extractor, url, cookies)

    if not stream:
        raise RuntimeError(f"[Resolver] Stream extraction failed → {url}")

    return [{
        "title": item.get("title", "Unknown"),
        "url": url,
        "duration": item.get("duration", "0:00"),
        "views": item.get("views", "Unknown"),
        "channel": extract_channel(item),
        "thumb": item.get("thumbnail") or yt_thumbnail(url),
        "stream": stream,
        "is_video": video,
    }]


# ==============================
# FULL TEST FUNCTION
# ==============================

import os

async def _test():
    print("\n========== YT RESOLVER FULL TEST ==========\n")

    query = input("Enter search or YouTube link: ").strip()
    cookie_path = input("Enter cookies.txt path (leave blank if none): ").strip()

    cookies = None
    if cookie_path:
        if os.path.exists(cookie_path):
            cookies = cookie_path
            print("✔ Cookies file loaded")
        else:
            print("❌ Cookies file not found")
            return

    print("\n----------- AUDIO MODE TEST -----------\n")

    try:
        audio_results = await resolve_query(query, cookies=cookies, video=False)

        if audio_results:
            song = audio_results[0]
            print("TITLE   :", song["title"])
            print("CHANNEL :", song["channel"])
            print("VIEWS   :", song["views"])
            print("STREAM  :", str(song["stream"])[:120], "...")
            print("TYPE    :", type(song["stream"]))
        else:
            print("No audio results")

    except Exception as e:
        print("Audio Error:", e)

    print("\n----------- VIDEO MODE TEST -----------\n")

    try:
        video_results = await resolve_query(query, cookies=cookies, video=True)

        if video_results:
            song = video_results[0]
            print("TITLE   :", song["title"])
            print("CHANNEL :", song["channel"])
            print("VIEWS   :", song["views"])
            print("STREAM  :", str(song["stream"])[:120], "...")
            print("TYPE    :", type(song["stream"]))
        else:
            print("No video results")

    except Exception as e:
        print("Video Error:", e)

    print("\n========== TEST COMPLETE ==========\n")


if __name__ == "__main__":
    asyncio.run(_test())
