"""Video duration probe — separated from render_video.py.

screen-walkthrough 这种"按 TTS 时间轴 + 视频素材池"的模板需要知道远端视频的
真实时长才能选出正确的 adaptStrategy（fit-exact / trim-and-speed / freeze-tail
/ static-fallback）。这里给出三条策略，按速度排序：

  1. 通过 mediaId（从 CDN URL 中切出）查 ab-api /file/get
  2. HEAD 请求按 Content-Length 估算（粗略）
  3. 下载前 2 MB 用 ffprobe 解析（精确但贵）

公共入口只有一个：probe_video_duration(url) -> Optional[float]。
"""
from __future__ import annotations

import builtins
import json
import os
import subprocess
import sys
import tempfile
import urllib.error
import urllib.request
from datetime import datetime
from typing import Optional


def _log(msg: str) -> None:
    now = datetime.now()
    stamp = now.strftime("%Y%m%d %H%M%S") + f":{now.microsecond // 1000:03d}"
    builtins.print(f"[{stamp}] {msg}", file=sys.stderr)


def _extract_media_id_from_url(url: str) -> Optional[str]:
    """Extract mediaId (vodVideoId) from CDN URL.

    Supported formats:
      - http://cdn.aibearer.com/{mediaId}/{hash}-ld.mp4
      - https://cdn.aibearer.com/{mediaId}/...
    """
    try:
        from urllib.parse import urlparse
        parsed = urlparse(url)
        parts = [p for p in parsed.path.split("/") if p]
        if len(parts) >= 2:
            candidate = parts[0]
            if len(candidate) >= 16 and all(c in "0123456789abcdef" for c in candidate):
                return candidate
    except Exception:
        pass
    return None


def _query_duration_from_api(url: str) -> Optional[float]:
    """Query ab-api /file/get by mediaId to get the precise duration from database.

    Returns duration in seconds, or None if query fails or duration not available.
    """
    media_id = _extract_media_id_from_url(url)
    if not media_id:
        return None

    api_base = os.environ.get(
        "MM_API_BASE_URL",
        os.environ.get("MM_BACKEND_API_URL", "https://api.remixmate.ai/api"),
    ).rstrip("/")
    if not api_base:
        return None

    priv_token = os.environ.get("PRIV_TOKEN", "").strip()
    if not priv_token:
        return None

    try:
        payload = json.dumps({"mediaId": media_id}).encode("utf-8")
        req = urllib.request.Request(
            f"{api_base}/file/get",
            data=payload,
            headers={
                "Content-Type": "application/json",
                "X-Priv-Token": priv_token,
            },
            method="POST",
        )
        with urllib.request.urlopen(req, timeout=5) as resp:
            result = json.loads(resp.read().decode("utf-8"))

        if result.get("code") != 0:
            return None

        data = result.get("data") or {}
        duration = data.get("duration")
        if duration is not None and duration > 0:
            _log(f"   📡 视频时长（API查询）: {duration:.1f}s (mediaId={media_id[:12]}...)")
            return float(duration)
    except Exception:
        pass

    return None


def probe_video_duration(url: str) -> Optional[float]:
    """Probe the duration (in seconds) of a remote video URL.

    Strategy (ordered by priority):
      1. Query ab-api /file/get by mediaId extracted from CDN URL (fastest, most accurate).
      2. HEAD request to estimate from Content-Length.
      3. Download first 2MB + ffprobe (if available).

    Returns duration in seconds, or None on failure.
    """
    api_duration = _query_duration_from_api(url)
    if api_duration is not None:
        return api_duration

    content_length_estimate: Optional[float] = None
    try:
        req_head = urllib.request.Request(url, method="HEAD", headers={
            "User-Agent": "Mozilla/5.0 (compatible; render-video/1.0)",
        })
        with urllib.request.urlopen(req_head, timeout=10) as resp:
            content_length = int(resp.headers.get("Content-Length", 0))
        if content_length > 0:
            content_length_estimate = content_length / 62500.0
    except Exception:
        pass

    tmp_path = None
    try:
        req = urllib.request.Request(url, headers={
            "User-Agent": "Mozilla/5.0 (compatible; render-video/1.0)",
            "Range": "bytes=0-2097151",
        })
        try:
            with urllib.request.urlopen(req, timeout=15) as resp:
                data = resp.read()
        except urllib.error.HTTPError as e:
            if e.code == 416:
                req2 = urllib.request.Request(url, headers={
                    "User-Agent": "Mozilla/5.0 (compatible; render-video/1.0)",
                })
                with urllib.request.urlopen(req2, timeout=15) as resp:
                    data = resp.read()
            else:
                raise

        fd, tmp_path = tempfile.mkstemp(suffix=".mp4", prefix="probe-")
        os.close(fd)
        with open(tmp_path, "wb") as f:
            f.write(data)

        try:
            result = subprocess.run(
                ["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", tmp_path],
                capture_output=True, text=True, timeout=10,
            )
            if result.returncode == 0:
                info = json.loads(result.stdout)
                dur = info.get("format", {}).get("duration")
                if dur:
                    return float(dur)
        except (FileNotFoundError, OSError, subprocess.TimeoutExpired, json.JSONDecodeError, ValueError):
            pass

    except Exception as e:
        _log(f"   ⚠️  视频时长探测失败: {e}")
    finally:
        if tmp_path and os.path.exists(tmp_path):
            try:
                os.unlink(tmp_path)
            except OSError:
                pass

    if content_length_estimate is not None:
        _log(f"   📐 视频时长估算（基于文件大小）: {content_length_estimate:.1f}s")
        return content_length_estimate

    return None
