#!/usr/bin/env python3
"""
视频解构脚本 — 通过 ab-render HTTP 接口实现，无需本地 ffmpeg。

调用链：
  POST $RENDER_API_URL/parse        → { taskId }
  POST $RENDER_API_URL/parseStatus  → { status, progress, result?, error? }

必要环境变量（由 ab-agent 自动注入）：
  RENDER_API_URL   ab-render 服务地址（默认 https://api-render.remixmate.ai；指向本地/staging 时覆盖）
  PRIV_TOKEN       ab-api 私有 token

可选环境变量：
  CONVERSATION_ID  对话 ID，用于文件关联
"""

import argparse
import json
import os
import sys
import time
import urllib.error
import urllib.request

# ─── 环境变量 ─────────────────────────────────────────────────────────────────

RENDER_API_URL = (
    os.environ.get("RENDER_API_URL")
    or os.environ.get("REMOTION_RENDER_API_URL")
    or "https://api-render.remixmate.ai"
).rstrip("/")
PRIV_TOKEN = os.environ.get("PRIV_TOKEN", "")
CONVERSATION_ID = os.environ.get("CONVERSATION_ID", "")

# ─── HTTP 工具 ────────────────────────────────────────────────────────────────

def api_post(path: str, body: dict, timeout: int = 30) -> dict:
    """向 ab-render 发送 POST 请求，返回解析后的 JSON。"""
    url = f"{RENDER_API_URL}{path}"
    data = json.dumps(body).encode()

    headers: dict[str, str] = {
        "Content-Type": "application/json",
        "X-Priv-Token": PRIV_TOKEN,
    }
    if CONVERSATION_ID:
        headers["x-conversation-id"] = CONVERSATION_ID

    req = urllib.request.Request(url, data=data, headers=headers, method="POST")
    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body_text = e.read().decode(errors="replace")
        raise RuntimeError(f"HTTP {e.code}: {body_text}") from e


def log(msg: str, silent: bool = False) -> None:
    if not silent:
        print(msg, flush=True)


# ─── 主逻辑 ───────────────────────────────────────────────────────────────────

def main() -> None:
    parser = argparse.ArgumentParser(
        description="Video deconstruction — calls the ab-render /parse endpoint (no local ffmpeg dependency)"
    )
    parser.add_argument("--url", required=True, help="Remote video URL")
    parser.add_argument(
        "--scene-threshold", type=float, default=0.3,
        help="Scene-change sensitivity 0.0-1.0 (default 0.3)",
    )
    parser.add_argument("--skip-asr", action="store_true", help="Skip the ASR step")
    parser.add_argument("--skip-keyframes", action="store_true", help="Skip keyframe extraction")
    parser.add_argument(
        "--json-output", action="store_true",
        help="Pipeline mode: emit only the final JSON to stdout",
    )
    args = parser.parse_args()

    # ── Pre-flight check ─────────────────────────────────────────────────────
    if not RENDER_API_URL:
        print(
            "❌ RENDER_API_URL env var is not configured.\n"
            "   Add render_api_url: \"http://<ab-render-host>:<port>\" to Nacos ab-agent.yaml",
            file=sys.stderr,
        )
        sys.exit(1)

    # ── 1. Submit the deconstruction task ───────────────────────────────────
    log(f"[video-parser] Submitting deconstruction task: {args.url[:80]}", args.json_output)

    resp = api_post("/parse", {
        "videoUrl": args.url,
        "sceneThreshold": args.scene_threshold,
        "skipAsr": args.skip_asr,
        "skipKeyframes": args.skip_keyframes,
    })

    if resp.get("code") != 0:
        print(f"❌ submission failed: {resp.get('msg', 'unknown error')}", file=sys.stderr)
        sys.exit(1)

    task_id: str = resp["data"]["taskId"]
    log(f"[video-parser] task accepted, taskId={task_id}", args.json_output)

    # ── 2. Poll status until completion ─────────────────────────────────────
    max_wait_sec = 600   # Wait up to 10 minutes
    poll_interval = 3    # Poll every 3 seconds
    elapsed = 0

    while elapsed < max_wait_sec:
        time.sleep(poll_interval)
        elapsed += poll_interval

        try:
            status_resp = api_post("/parseStatus", {"taskId": task_id})
        except Exception as e:  # noqa: BLE001
            log(f"[video-parser] polling error (will retry): {e}", args.json_output)
            continue

        if status_resp.get("code") != 0:
            log(f"[video-parser] polling returned an error code (will retry): {status_resp.get('msg')}", args.json_output)
            continue

        task = status_resp["data"]
        status = task.get("status", "unknown")
        progress = task.get("progress", 0)

        log(f"[video-parser] status={status}  progress={int(progress * 100)}%  elapsed={elapsed}s", args.json_output)

        if status == "succeeded":
            result = task.get("result")
            if args.json_output:
                print(json.dumps(result, ensure_ascii=False, indent=2))
            else:
                print("\n✅ Deconstruction complete")
                print(json.dumps(result, ensure_ascii=False, indent=2))
            return

        if status == "failed":
            error = task.get("error", "unknown error")
            print(f"❌ deconstruction failed: {error}", file=sys.stderr)
            sys.exit(1)

    print(f"❌ deconstruction timed out (over {max_wait_sec}s)", file=sys.stderr)
    sys.exit(1)


if __name__ == "__main__":
    main()
