#!/usr/bin/env python3
"""
Smoke / E2E test for application-form PDF export (docxtpl + LibreOffice).

  Direct (no HTTP): exercises merge + conversion on this machine / container.
    cd be0 && python tools/e2e_application_form_pdf_export.py --direct --out /tmp/e2e-mau.pdf

  HTTP: needs FastAPI listening (--url is the API origin, no /api prefix in path).
    python tools/e2e_application_form_pdf_export.py --http http://127.0.0.1:4402 --out /tmp/e2e-mau.pdf

  Pure curl + jq (no Python on host; official JSON must be wrapped):
    cd /path/to/repo && jq -n --slurpfile o fe0/public/assets/bieu_mau_sang_kien_template.json \
      '{officialBieuMau: $o[0]}' | curl -sfS -X POST http://127.0.0.1:4402/api/v1/docx/preview-application-form-pdf \
      -H 'Content-Type: application/json' -o /tmp/e2e-mau.pdf && file /tmp/e2e-mau.pdf

  If the API returns HTTP 501, rebuild/run be0 with LibreOffice (see be0/Dockerfile: libreoffice-writer-nogui).

Docker (stack up):
    docker compose exec be0 python tools/e2e_application_form_pdf_export.py --direct --out /tmp/e2e-mau.pdf

Refresh bundled sample after template changes:
    cp ../fe0/public/assets/bieu_mau_sang_kien_template.json tools/e2e_sample_official_bieu_mau.json

Exit 0 on success; non-zero on failure.

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path
from typing import Any, Dict

BE0_ROOT = Path(__file__).resolve().parent.parent
if str(BE0_ROOT) not in sys.path:
    sys.path.insert(0, str(BE0_ROOT))


def _repo_root() -> Path:
    return BE0_ROOT.parent


def load_sample_official() -> Dict[str, Any]:
    """officialBieuMau-shaped JSON (same as Review « Xem lại »)."""
    candidates = [
        Path(__file__).resolve().parent / "e2e_sample_official_bieu_mau.json",
        _repo_root() / "fe0/public/assets/bieu_mau_sang_kien_template.json",
    ]
    for p in candidates:
        if p.is_file():
            with open(p, encoding="utf-8") as f:
                data = json.load(f)
            break
    else:
        raise FileNotFoundError(
            "No sample official JSON found. Expected tools/e2e_sample_official_bieu_mau.json "
            "or fe0/public/assets/bieu_mau_sang_kien_template.json next to be0/."
        )

    # Visible markers in generated PDF/DOCX
    if isinstance(data.get("TRANG BÌA"), dict):
        data["TRANG BÌA"]["Tên sáng kiến (Tiếng Việt)"] = "E2E PDF export — tên sáng kiến kiểm thử"
        data["TRANG BÌA"]["Năm"] = "2026"
    return data


def run_direct(out_path: Path | None) -> bytes:
    from src.be01.docx_to_pdf import convert_docx_bytes_to_pdf
    from src.be01.fill_application_form import fill_application_form_docx
    from src.be01.official_to_data_blank import official_to_data_blank

    official = load_sample_official()
    ctx = official_to_data_blank(official)
    docx = fill_application_form_docx(ctx)
    pdf = convert_docx_bytes_to_pdf(docx)
    if not pdf.startswith(b"%PDF"):
        raise RuntimeError("Output is not a PDF (missing %PDF header).")
    if out_path:
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_bytes(pdf)
        print(f"Wrote {len(pdf)} bytes → {out_path}")
    else:
        print(f"OK: generated PDF, {len(pdf)} bytes (no --out)")
    return pdf


def run_http(base_url: str, out_path: Path | None) -> bytes:
    import urllib.error
    import urllib.request

    official = load_sample_official()
    url = base_url.rstrip("/") + "/api/v1/docx/preview-application-form-pdf"
    body = json.dumps({"officialBieuMau": official}).encode("utf-8")
    req = urllib.request.Request(
        url,
        data=body,
        method="POST",
        headers={"Content-Type": "application/json", "Accept": "application/pdf"},
    )
    try:
        with urllib.request.urlopen(req, timeout=180) as resp:
            raw = resp.read()
    except urllib.error.HTTPError as e:
        detail = e.read().decode("utf-8", errors="replace")
        raise SystemExit(f"HTTP {e.code}: {detail}") from e

    if not raw.startswith(b"%PDF"):
        raise SystemExit(f"Expected PDF, got {len(raw)} bytes, head={raw[:64]!r}")
    if out_path:
        out_path.parent.mkdir(parents=True, exist_ok=True)
        out_path.write_bytes(raw)
        print(f"Wrote {len(raw)} bytes → {out_path}")
    else:
        print(f"OK: HTTP PDF, {len(raw)} bytes")
    return raw


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__)
    g = ap.add_mutually_exclusive_group(required=True)
    g.add_argument("--direct", action="store_true", help="Run docxtpl + LibreOffice in-process")
    g.add_argument("--http", metavar="BASE_URL", help="POST to FastAPI (e.g. http://127.0.0.1:4402)")
    ap.add_argument("--out", type=Path, metavar="FILE.pdf", help="Write PDF to this path")
    args = ap.parse_args()

    try:
        if args.direct:
            run_direct(args.out)
        else:
            run_http(args.http, args.out)
    except FileNotFoundError as e:
        print(f"FAIL: {e}", file=sys.stderr)
        sys.exit(2)
    except Exception as e:
        print(f"FAIL: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()
