#!/usr/bin/env python3
"""IDS Phase 3 — Mobile Prototype Renderer.

Open a device frame HTML, inject the chosen scenario into the .screen-content
placeholder, and capture a viewport-sized PNG.

Usage:
    python3 render_prototype.py \\
        --device iphone15pro \\
        --mode light \\
        --scenario dashboard \\
        --output /abs/path/output.png
"""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

SKILL_ROOT = Path(__file__).resolve().parent.parent
FRAMES_DIR = SKILL_ROOT / "frames"
SCENARIOS_DIR = SKILL_ROOT / "scenarios"

DEVICE_VIEWPORTS: dict[str, tuple[int, int]] = {
    "iphone15pro": (393, 852),
    "pixel9pro": (412, 915),
}

VALID_DEVICES = {"iphone15pro", "pixel9pro"}
VALID_MODES = {"light", "dark"}
VALID_SCENARIOS = {
    "signup_step1",
    "signup_step2",
    "signup_step3",
    "dashboard",
    "insurance_compare",
    "cardnews_publish",
    "ai_analysis",
}


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Mobile prototype renderer")
    parser.add_argument("--device", required=True, choices=sorted(VALID_DEVICES))
    parser.add_argument("--mode", required=True, choices=sorted(VALID_MODES))
    parser.add_argument("--scenario", required=True, choices=sorted(VALID_SCENARIOS))
    parser.add_argument("--output", required=True, help="Absolute output PNG path")
    return parser.parse_args()


def load_scenario_body(scenario: str) -> str:
    path = SCENARIOS_DIR / f"{scenario}.html"
    if not path.is_file():
        raise FileNotFoundError(f"Scenario not found: {path}")
    raw = path.read_text(encoding="utf-8")
    # Extract <body> contents to inject; keep <style> too.
    lower = raw.lower()
    style_start = lower.find("<style")
    style_end = lower.find("</style>")
    style_block = ""
    if style_start != -1 and style_end != -1:
        style_block = raw[style_start : style_end + len("</style>")]
    body_start = lower.find("<body")
    body_open_end = raw.find(">", body_start) if body_start != -1 else -1
    body_close = lower.find("</body>")
    body_inner = ""
    if body_open_end != -1 and body_close != -1:
        body_inner = raw[body_open_end + 1 : body_close]
    return style_block + body_inner


def render(device: str, mode: str, scenario: str, output: str) -> None:
    try:
        from playwright.sync_api import sync_playwright
    except ImportError as exc:
        print(f"Playwright not available: {exc}", file=sys.stderr)
        sys.exit(2)

    frame_path = FRAMES_DIR / f"{device}_{mode}.html"
    if not frame_path.is_file():
        raise FileNotFoundError(f"Frame not found: {frame_path}")

    width, height = DEVICE_VIEWPORTS[device]
    scenario_html = load_scenario_body(scenario)

    output_path = Path(output)
    output_path.parent.mkdir(parents=True, exist_ok=True)

    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=True)
        context = browser.new_context(
            viewport={"width": width, "height": height},
            device_scale_factor=2,
        )
        page = context.new_page()
        page.goto(frame_path.as_uri(), wait_until="load")

        # Inject scenario HTML into the .screen-content placeholder.
        page.evaluate(
            """(html) => {
                const el = document.querySelector('.screen-content');
                if (el) {
                    el.innerHTML = html;
                }
            }""",
            scenario_html,
        )
        page.wait_for_timeout(300)
        page.screenshot(path=str(output_path), full_page=False, omit_background=False)

        browser.close()

    if not output_path.is_file():
        raise RuntimeError(f"Screenshot was not written to {output_path}")


def main() -> int:
    args = parse_args()
    try:
        render(args.device, args.mode, args.scenario, args.output)
    except Exception as exc:  # noqa: BLE001
        print(f"render failed: {exc}", file=sys.stderr)
        return 1
    print(f"OK: {args.output}")
    return 0


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