"""Shared download utilities."""
from __future__ import annotations
import asyncio, logging, os, tempfile, time as time_module
from pathlib import Path
import httpx

logger = logging.getLogger(__name__)
TEMP_DIR = Path(tempfile.gettempdir()) / "bobi_dl"
TEMP_DIR.mkdir(exist_ok=True)

HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}

try:
    from bot.config import PROXY_URL
except ImportError:
    PROXY_URL = os.getenv("PROXY_URL", "")

def get_http_client(**kwargs) -> httpx.AsyncClient:
    kwargs.setdefault("timeout", 30.0)
    kwargs.setdefault("follow_redirects", True)
    kwargs.setdefault("headers", HEADERS)
    if PROXY_URL:
        kwargs["transport"] = httpx.AsyncHTTPTransport(proxy=PROXY_URL)
    return httpx.AsyncClient(**kwargs)

_cache: dict[str, tuple[float, object]] = {}
CACHE_TTL = 300

def cache_get(key: str) -> object | None:
    val = _cache.get(key)
    if val and time_module.monotonic() - val[0] < CACHE_TTL:
        return val[1]
    return None

def cache_set(key: str, data: object) -> None:
    _cache[key] = (time_module.monotonic(), data)

def format_size(s: int | float) -> str:
    if s < 1024: return f"{s}B"
    elif s < 1024**2: return f"{s/1024:.0f}KB"
    elif s < 1024**3: return f"{s/1024**2:.1f}MB"
    else: return f"{s/1024**3:.1f}GB"

def escape_md(text: str) -> str:
    for ch in r"_*[]()~`>#+-=|{}.!":
        text = text.replace(ch, "\\" + ch)
    return text

def best_quality_img(url: str) -> str:
    if "pbs.twimg.com" in url and "name=" not in url:
        sep = "&" if "?" in url else "?"
        return f"{url}{sep}format=jpg&name=orig"
    return url

async def download_file(url: str, filename: str) -> Path | None:
    path = TEMP_DIR / filename
    try:
        async with get_http_client(timeout=120.0) as c:
            r = await c.get(url)
            if r.status_code == 200:
                path.write_bytes(r.content)
                return path
    except Exception as e:
        logger.debug("Download failed %s: %s", url, e)
    return None

async def dl_via_ytdlp(url: str, output_filename: str, format_spec: str = "best[ext=mp4]/best", **extra) -> Path | None:
    import yt_dlp
    output = TEMP_DIR / output_filename
    opts = {"outtmpl": str(output), "quiet": True, "no_warnings": True, "format": format_spec}
    if PROXY_URL:
        opts["proxy"] = PROXY_URL
    if "bestaudio" in format_spec:
        opts.setdefault("postprocessors", [])
        if not any(pp.get("key") == "FFmpegExtractAudio" for pp in opts["postprocessors"]):
            opts["postprocessors"].append({"key": "FFmpegExtractAudio", "preferredcodec": "mp3", "preferredquality": "192"})
    opts.update(extra)
    loop = asyncio.get_event_loop()
    try:
        await loop.run_in_executor(None, lambda: yt_dlp.YoutubeDL(opts).download([url]))
        if "bestaudio" in format_spec:
            mp3 = output.with_suffix(".mp3")
            if mp3.exists() and mp3.stat().st_size > 0:
                if output.exists(): output.unlink(missing_ok=True)
                return mp3
        if output.exists() and output.stat().st_size > 0:
            return output
    except Exception as e:
        logger.debug("yt-dlp failed: %s", e)
    return None

async def extract_info_ytdlp(url: str, **extra) -> dict | None:
    import yt_dlp
    cached = cache_get(f"info:{url}")
    if cached:
        return cached
    loop = asyncio.get_event_loop()
    try:
        opts = {"quiet": True, "no_warnings": True}
        if PROXY_URL: opts["proxy"] = PROXY_URL
        opts.update(extra)
        info = await loop.run_in_executor(None, lambda: yt_dlp.YoutubeDL(opts).extract_info(url, download=False))
        if info:
            cache_set(f"info:{url}", info)
        return info
    except Exception as e:
        logger.debug("extract_info failed: %s", e)
    return None
