import os
import asyncio
import yt_dlp
import logging
import glob
from typing import Tuple, Union, Any, List
from youtubesearchpython import VideosSearch

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

BASE_PATH = os.path.dirname(os.path.abspath(__file__))
DOWNLOAD_DIR = os.path.join(BASE_PATH, "downloads")
COOKIES_FILE_PATH = os.path.join(BASE_PATH, "cookies.txt")

if not os.path.exists(DOWNLOAD_DIR):
    os.makedirs(DOWNLOAD_DIR)

def ytsearch(query: str) -> Union[List[Any], int]:
    try:
        search = VideosSearch(query, limit=1).result()
        if not search["result"]:
            return 0
        data = search["result"][0]
        return [
            data["title"],
            data["link"],
            data["duration"],
            data["thumbnails"][0]["url"],
            data["id"],
            data["channel"]["name"]
        ]
    except Exception as e:
        logger.error(f"Search Error: {e}")
        return 0

async def ytdl(url: str, video_mode: bool = False, mode: str = None) -> Tuple[int, str]:
    loop = asyncio.get_running_loop()

    def download_sync():
        selected_mode = mode or ("video" if video_mode else "audio")
        
        opts = {
            "quiet": True,
            "no_warnings": True,
            "geo_bypass": True,
            "nocheckcertificate": True,
            "cookiefile": COOKIES_FILE_PATH if os.path.exists(COOKIES_FILE_PATH) else None,
            "outtmpl": os.path.join(DOWNLOAD_DIR, "%(id)s.%(ext)s"),
        }

        if selected_mode == "video":
            opts["format"] = "bestvideo[height<=?720][ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]"
            opts["merge_output_format"] = "mp4"
        elif selected_mode == "m4a":
            opts["format"] = "bestaudio[ext=m4a]/best"
        elif selected_mode == "song_video":
            opts["format"] = "bestvideo+bestaudio/best"
            opts["merge_output_format"] = "mp4"
        elif selected_mode == "song_audio":
            opts["format"] = "bestaudio/best"
            opts["postprocessors"] = [{
                "key": "FFmpegExtractAudio",
                "preferredcodec": "mp3",
                "preferredquality": "128",
            }]
        else:
            opts["format"] = "bestaudio/best"
            opts["postprocessors"] = [{
                "key": "FFmpegExtractAudio",
                "preferredcodec": "m4a",
                "preferredquality": "128",
            }]

        with yt_dlp.YoutubeDL(opts) as ydl:
            info = ydl.extract_info(url, download=False)
            video_id = info['id']
            
            existing_files = glob.glob(os.path.join(DOWNLOAD_DIR, f"{video_id}.*"))
            if existing_files:
                return existing_files[0]

            downloaded_info = ydl.extract_info(url, download=True)
            final_path = ydl.prepare_filename(downloaded_info)
            
            if "postprocessors" in opts:
                ext = opts["postprocessors"][0]["preferredcodec"]
                final_path = os.path.splitext(final_path)[0] + f".{ext}"
            
            return final_path

    try:
        result_path = await loop.run_in_executor(None, download_sync)
        if result_path and os.path.exists(result_path):
            return 1, result_path
        return 0, "File download failed"
    except Exception as e:
        logger.error(f"Download Error: {e}")
        return 0, str(e)

async def cleanup_file(filepath: str, delay: int = 1800):
    await asyncio.sleep(delay)
    try:
        if os.path.exists(filepath):
            os.remove(filepath)
    except:
        pass

async def get_playlist_ids(link, limit):
    command_args = ["yt-dlp", "-i", "--get-id", "--flat-playlist", "--playlist-end", str(limit), "--js-runtime", "node", "--skip-download", link]
    if os.path.exists(COOKIES_FILE_PATH):
        command_args.extend(["--cookies", COOKIES_FILE_PATH])
    
    process = await asyncio.create_subprocess_exec(
        *command_args,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE
    )
    stdout, _ = await process.communicate()
    try:
        return [key for key in stdout.decode().split("\n") if key.strip() != ""]
    except:
        return []
            
