#!/usr/bin/env python3
"""한국어 tts_script.json을 영어로 번역해 translation.json을 만든다.

1차 번역기: claude CLI (haiku). 실패 시 동일 계약으로 재시도, 최종 폴백은 ollama gemma4:31b.
출력: <out_dir>/work/<DAY>/translation.json
  {"title": str, "description": str, "link": str|None,
   "segments": [{"id","slide","speaker","text"}, ...]}
"""
import argparse
import json
import re
import subprocess
import sys
from pathlib import Path

HANGUL = re.compile(r"[가-힣]")

PROMPT_TEMPLATE = """You are translating a Korean two-person radio show into natural spoken American English.
Host is a warm, calm female presenter. Guest is a friendly male questioner. Keep that dynamic.

Rules:
- Translate every segment. Never merge, split, drop, or reorder segments. Keep the exact same "id" values.
- Conversational radio English, contractions welcome. No literal translationese.
- Keep numbers, company names, and product names accurate. Spell out acronyms only when the Korean did.
- Keep all URLs exactly as they are, character for character.
- Romanize the host's name as "Kyungjin Kim" (e.g. "lawyer Kyungjin Kim").
- The episode title should read like an English news-podcast episode title, not a literal translation.
- Translate the episode description fully into English (URLs and hashtags stay as-is; translate hashtag words into English hashtags).
- Output STRICT JSON only, no markdown fences, no commentary, exactly this shape:
{"title": "...", "description": "...", "segments": [{"id": "S001", "text": "..."}, ...]}

Episode title (Korean): {title}

Episode description (Korean):
{description}

Segments (JSON):
{segments}
"""


def run_claude(prompt: str, timeout: int = 420) -> str:
    proc = subprocess.run(
        ["claude", "--model", "haiku", "-p", prompt],
        text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=timeout,
    )
    if proc.returncode != 0:
        raise RuntimeError(f"claude exit {proc.returncode}: {proc.stdout[:500]}")
    return proc.stdout


def run_ollama(prompt: str, timeout: int = 1800) -> str:
    proc = subprocess.run(
        ["ollama", "run", "gemma4:31b", prompt],
        text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=timeout,
    )
    if proc.returncode != 0:
        raise RuntimeError(f"ollama exit {proc.returncode}: {proc.stdout[:500]}")
    return proc.stdout


def extract_json(raw: str) -> dict:
    raw = raw.strip()
    if raw.startswith("```"):
        raw = re.sub(r"^```[a-zA-Z]*\n?", "", raw)
        raw = re.sub(r"\n?```\s*$", "", raw)
    start, end = raw.find("{"), raw.rfind("}")
    if start < 0 or end <= start:
        raise ValueError("no JSON object in output")
    return json.loads(raw[start:end + 1])


def hangul_free(text: str) -> bool:
    cleaned = re.sub(r"https?://\S+", "", text or "")
    return not HANGUL.search(cleaned)


def validate(result: dict, source_segments: list[dict]) -> list[str]:
    problems = []
    segs = result.get("segments") or []
    want = [s["id"] for s in source_segments]
    got = [s.get("id") for s in segs]
    if want != got:
        problems.append(f"segment ids mismatch: want {len(want)}, got {len(got)}")
    for seg in segs:
        text = (seg.get("text") or "").strip()
        if not text:
            problems.append(f"{seg.get('id')}: empty")
        elif not hangul_free(text):
            problems.append(f"{seg.get('id')}: Korean remains")
    if not (result.get("title") or "").strip():
        problems.append("title empty")
    elif not hangul_free(result["title"]):
        problems.append("title: Korean remains")
    if not hangul_free(result.get("description") or ""):
        problems.append("description: Korean remains")
    return problems


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--run-root", required=True)
    parser.add_argument("--date", required=True)
    parser.add_argument("--out-dir", required=True)
    args = parser.parse_args()

    run_dir = Path(args.run_root) / "runs" / args.date
    script_path = run_dir / "script" / "tts_script.json"
    data = json.loads(script_path.read_text(encoding="utf-8"))
    source_segments = [
        {"id": s["id"], "slide": int(s["slide"]), "speaker": s["speaker"], "text": s["text"]}
        for s in data["segments"]
    ]

    title, description, link = "", "", None
    try:
        snip = json.loads((run_dir / "reports" / "youtube_upload_result.json").read_text(encoding="utf-8"))["raw"]["snippet"]
        title = snip.get("title") or ""
        description = snip.get("description") or ""
    except Exception:
        pass
    try:
        post = json.loads((run_dir / "reports" / "kimkj_post_result.json").read_text(encoding="utf-8"))
        link = post.get("post_verification", {}).get("url") or post.get("url")
    except Exception:
        pass

    payload = json.dumps(
        [{"id": s["id"], "speaker": s["speaker"], "text": s["text"]} for s in source_segments],
        ensure_ascii=False, indent=0,
    )
    prompt = PROMPT_TEMPLATE.replace("{title}", title or "(none)") \
                            .replace("{description}", description or "(none)") \
                            .replace("{segments}", payload)

    attempts = [("claude", run_claude), ("claude", run_claude), ("ollama", run_ollama)]
    result, errors = None, []
    for name, runner in attempts:
        try:
            candidate = extract_json(runner(prompt))
            problems = validate(candidate, source_segments)
            if not problems:
                result = candidate
                break
            errors.append(f"{name}: {problems[:3]}")
        except Exception as exc:
            errors.append(f"{name}: {type(exc).__name__}: {str(exc)[:300]}")
    if result is None:
        print("TRANSLATION FAILED:", " | ".join(errors), file=sys.stderr)
        return 1

    by_id = {s["id"]: s for s in source_segments}
    merged = [
        {"id": seg["id"], "slide": by_id[seg["id"]]["slide"],
         "speaker": by_id[seg["id"]]["speaker"], "text": seg["text"].strip()}
        for seg in result["segments"]
    ]
    out = {
        "title": result["title"].strip(),
        "description": (result.get("description") or result["title"]).strip(),
        "link": link,
        "segments": merged,
    }
    work_dir = Path(args.out_dir) / "work" / args.date.replace("-", "")
    work_dir.mkdir(parents=True, exist_ok=True)
    out_path = work_dir / "translation.json"
    out_path.write_text(json.dumps(out, ensure_ascii=False, indent=1), encoding="utf-8")
    print(f"OK translation: {out_path} ({len(merged)} segments)")
    return 0


if __name__ == "__main__":
    sys.exit(main())
