#!/usr/bin/env python3
"""Fetch a public product page into an isolated, read-only UI preview snapshot.

This tool performs a single HTTP GET. It never sends form data and never writes to
MinIO, R2, D1, or any production service. The saved HTML is evidence/reference;
template changes should still be made in product_detail_template.html.
"""

from __future__ import annotations

import argparse
import hashlib
import json
import re
from datetime import datetime, timezone
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen


DEFAULT_BASE_URL = "https://parts.jp.inotoday.com"
DEFAULT_OUTPUT_ROOT = Path(r"F:\ui-agent-runtime\product-snapshots")
MAX_BYTES = 8 * 1024 * 1024


def slug_for_mpn(mpn: str) -> str:
    slug = re.sub(r"[^A-Za-z0-9._-]+", "-", mpn.strip()).strip("-").lower()
    if not slug:
        raise ValueError("mpn must contain at least one alphanumeric character")
    return slug


def build_url(mpn: str | None, url: str | None, base_url: str) -> str:
    if url:
        target = url
    elif mpn:
        target = f"{base_url.rstrip('/')}/items/{slug_for_mpn(mpn)}/"
    else:
        raise ValueError("provide --mpn or --url")
    if not target.startswith(("https://", "http://")):
        raise ValueError("target must be an http(s) URL")
    return target


def fetch_snapshot(url: str, output_root: Path, timeout: int = 20) -> dict[str, str | int]:
    request = Request(url, headers={"User-Agent": "Inotoday-UI-Preview/1.0"}, method="GET")
    try:
        with urlopen(request, timeout=timeout) as response:
            content_type = response.headers.get_content_type()
            if content_type not in {"text/html", "application/xhtml+xml"}:
                raise ValueError(f"expected HTML response, got {content_type}")
            body = response.read(MAX_BYTES + 1)
            if len(body) > MAX_BYTES:
                raise ValueError(f"response exceeds {MAX_BYTES} byte limit")
            status = int(response.status)
    except (HTTPError, URLError) as exc:
        raise RuntimeError(f"failed to fetch {url}: {exc}") from exc

    digest = hashlib.sha256(body).hexdigest()
    stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
    target_dir = output_root / f"{stamp}-{digest[:12]}"
    target_dir.mkdir(parents=True, exist_ok=False)
    html_path = target_dir / "baseline.html"
    meta_path = target_dir / "metadata.json"
    html_path.write_bytes(body)
    metadata = {
        "source_url": url,
        "fetched_at": datetime.now(timezone.utc).isoformat(),
        "http_status": status,
        "sha256": digest,
        "bytes": len(body),
        "mode": "public-read-only",
    }
    meta_path.write_text(json.dumps(metadata, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    return {"html": str(html_path), "metadata": str(meta_path), "bytes": len(body), "sha256": digest}


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--mpn")
    parser.add_argument("--url")
    parser.add_argument("--base-url", default=DEFAULT_BASE_URL)
    parser.add_argument("--output-root", type=Path, default=DEFAULT_OUTPUT_ROOT)
    args = parser.parse_args()
    url = build_url(args.mpn, args.url, args.base_url)
    print(json.dumps(fetch_snapshot(url, args.output_root), ensure_ascii=False))
    return 0


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

