#!/usr/bin/env python3
from __future__ import annotations

import argparse
import html
import json
import subprocess
import time
from pathlib import Path


CHROME = Path("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome")


def main() -> int:
    parser = argparse.ArgumentParser(description="Render an exact local fallback infographic from a frozen SKU manifest.")
    parser.add_argument("--manifest", required=True, type=Path)
    parser.add_argument("--source-dir", required=True, type=Path)
    parser.add_argument("--output", required=True, type=Path)
    parser.add_argument("--method", default="local-controlled-fallback")
    parser.add_argument("--reason", default="NotebookLM infographic creation rate limit persisted after documented retries")
    args = parser.parse_args()
    if not CHROME.exists():
        raise FileNotFoundError(CHROME)
    data = json.loads(args.manifest.read_text(encoding="utf-8"))
    flow = data["main_flow"]
    count = len(flow)
    cards = []
    for index, step in enumerate(flow, 1):
        cards.append(
            f'<article class="step"><div class="num">{index:02d}</div>'
            f'<div class="icon"><span>{index}</span></div><h2>{html.escape(step)}</h2>'
            f'<p>标准主流程 · STEP {index:02d}</p></article>'
        )
    values = "".join(f'<span>{html.escape(value)}</span>' for value in data["customer_values"])
    page = f'''<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><style>
*{{box-sizing:border-box}}html,body{{margin:0;width:2752px;height:1536px;overflow:hidden}}body{{font-family:"PingFang SC","Microsoft YaHei",sans-serif;color:#271b12;background:radial-gradient(circle at 88% 8%,#fff0bd 0,transparent 25%),linear-gradient(135deg,#fffdfa,#fff8eb)}}
.page{{height:100%;padding:108px 112px 82px;display:flex;flex-direction:column}}header{{display:flex;justify-content:space-between;align-items:flex-start;gap:60px}}.kicker{{font-size:42px;font-weight:950;letter-spacing:.12em;color:#d97706}}h1{{font-size:78px;line-height:1.08;margin:16px 0 14px;font-weight:950;color:#ed6c00}}.lede{{font-size:34px;color:#6f5746;margin:0;max-width:1800px}}.badge{{padding:16px 24px;border:2px solid #f4c66c;border-radius:999px;background:#fff;font-size:25px;font-weight:900;color:#a64b00;white-space:nowrap}}.flow{{position:relative;display:grid;grid-template-columns:repeat({count},1fr);gap:28px;margin-top:74px;flex:1;align-items:stretch}}.step{{position:relative;z-index:1;border:3px solid #f3b54d;background:rgba(255,255,255,.92);border-radius:34px;padding:38px 28px 30px;text-align:center;box-shadow:0 24px 50px rgba(174,83,0,.10);display:flex;flex-direction:column;align-items:center;justify-content:center;min-width:0}}.step:not(:last-child)::after{{content:"→";position:absolute;z-index:4;right:-44px;top:50%;transform:translateY(-50%);width:58px;height:58px;border-radius:50%;display:grid;place-items:center;background:#fff;color:#ed6c00;border:2px solid #ffd18a;font-size:39px;font-weight:950;box-shadow:0 8px 18px rgba(174,83,0,.16)}}.step:nth-child(even){{background:linear-gradient(160deg,#ffb438,#ff7a1a);color:#fff;border-color:#ff8b22}}.num{{position:absolute;top:20px;left:24px;font-size:24px;font-weight:950;opacity:.7}}.icon{{width:124px;height:124px;border-radius:36px;display:grid;place-items:center;background:linear-gradient(135deg,#fff1c7,#ffd165);box-shadow:inset 0 0 0 3px rgba(237,108,0,.25);margin-bottom:28px}}.step:nth-child(even) .icon{{background:rgba(255,255,255,.92)}}.icon span{{font-size:56px;font-weight:950;color:#ed6c00}}h2{{font-size:{44 if count <= 5 else 38}px;line-height:1.2;margin:0;max-width:100%;font-weight:950}}.step p{{margin:24px 0 0;font-size:19px;letter-spacing:.08em;opacity:.68;font-weight:800}}footer{{margin-top:48px;display:flex;align-items:center;justify-content:flex-start;gap:30px}}.values{{display:flex;gap:18px;flex-wrap:wrap}}.values span{{padding:13px 22px;border-radius:999px;background:#fff;border:2px solid #f2d89f;color:#8a4b00;font-size:23px;font-weight:900}}
</style></head><body><main class="page"><header><div><div class="kicker">CPT</div><h1>{html.escape(data.get('release_name', data['sku'] + '-' + data['name']))}主流程</h1><p class="lede">{html.escape(data['one_liner'])}</p></div><div class="badge">{html.escape(data.get('release_code', data['sku']))} · {count} 步标准闭环</div></header><section class="flow">{''.join(cards)}</section><footer><div class="values">{values}</div></footer></main></body></html>'''
    draft = args.source_dir / "04-生成成果" / f"{data['sku']}-主流程图-本地受控渲染.html"
    draft.parent.mkdir(parents=True, exist_ok=True)
    draft.write_text(page, encoding="utf-8")
    args.output.parent.mkdir(parents=True, exist_ok=True)
    profile = args.source_dir / "04-生成成果" / "chrome-profile"
    process = subprocess.Popen([
        str(CHROME), "--headless=new", "--disable-gpu", "--hide-scrollbars", "--no-first-run",
        "--disable-background-networking", "--run-all-compositor-stages-before-draw", "--virtual-time-budget=1200",
        f"--user-data-dir={profile}", "--window-size=2752,1536", "--force-device-scale-factor=1",
        f"--screenshot={args.output}", draft.resolve().as_uri(),
    ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    deadline = time.time() + 20
    while time.time() < deadline:
        if args.output.exists() and args.output.stat().st_size > 10000:
            break
        if process.poll() is not None:
            break
        time.sleep(0.25)
    if process.poll() is None:
        process.terminate()
        try:
            process.wait(timeout=3)
        except subprocess.TimeoutExpired:
            process.kill()
            process.wait(timeout=3)
    if not args.output.exists() or args.output.stat().st_size <= 10000:
        stdout, stderr = process.communicate()
        raise RuntimeError(f"Chrome did not create a valid screenshot: {stderr or stdout}")
    receipt = {
        "sku": data["sku"], "generation_method": args.method,
        "reason": args.reason,
        "output": str(args.output), "html_source": str(draft), "main_flow": flow,
    }
    (args.source_dir / "local-fallback-result.json").write_text(json.dumps(receipt, ensure_ascii=False, indent=2), encoding="utf-8")
    print(json.dumps(receipt, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
