"""HTML report for pulumi hybrid lab suite (pulumi-vsphere + REST + SOAP)."""

from __future__ import annotations

import html
from datetime import UTC, datetime
from pathlib import Path
from typing import Any


def _esc(value: Any) -> str:
    return html.escape(str(value), quote=True)


def _section_rest(summary: dict[str, Any]) -> str:
    rest = summary.get("rest") or {}
    majors = rest.get("majors") or []
    by_verb = rest.get("by_verb") or {}
    failures = rest.get("failures") or []
    coverage = rest.get("coverage_line") or f"{(rest.get('probed') or 0) - (rest.get('critical') or 0)}/{rest.get('declared') or rest.get('total') or 0}"
    critical = rest.get("critical", rest.get("failed", 0))

    major_rows = []
    for m in majors:
        buckets = m.get("buckets") or {}
        deep = m.get("deep_vs_stub") or {}
        major_rows.append(
            "<tr>"
            f"<td>{_esc(m.get('major'))}</td>"
            f"<td>{_esc(m.get('version'))}</td>"
            f"<td>{_esc(m.get('declared'))}</td>"
            f"<td>{_esc(m.get('probed'))}</td>"
            f"<td>{_esc(m.get('coverage_line') or '—')}</td>"
            f"<td>{_esc(m.get('critical', m.get('failed')))}</td>"
            f"<td>{_esc(buckets.get('success_2xx', 0))}</td>"
            f"<td>{_esc(buckets.get('client_4xx', 0))}</td>"
            f"<td>{_esc(buckets.get('server_5xx', 0))}</td>"
            f"<td>{_esc(deep.get('deep', 0))}/{_esc(deep.get('stub', 0))}</td>"
            "</tr>"
        )

    verb_bits = " · ".join(f"{_esc(k)}={_esc(v)}" for k, v in sorted(by_verb.items()))
    fail_rows = []
    for f in failures[:40]:
        fail_rows.append(
            "<tr>"
            f"<td>{_esc(f.get('major'))}</td>"
            f"<td>{_esc(f.get('verb'))}</td>"
            f"<td><code>{_esc(f.get('path'))}</code></td>"
            f"<td>{_esc(f.get('kind'))}</td>"
            f"<td>{_esc(f.get('status'))}</td>"
            f"<td class='err'>{_esc((f.get('body') or f.get('expected') or '')[:180])}</td>"
            "</tr>"
        )

    return f"""
    <h2>REST HTTP contract matrix (Layer A)</h2>
    <p class="meta"><strong>coverage {_esc(coverage)}</strong>
      · critical={_esc(critical)}
      · probed={_esc(rest.get("probed") or rest.get("total"))}
      · declared={_esc(rest.get("declared"))}
      · verbs: {verb_bits or "—"}
      <br/>100% = HTTP matrix (IMPLEMENTED × majors + HEAD), not pulumi-vsphere resource count.</p>
    <table>
      <thead><tr><th>Major</th><th>Version</th><th>Declared</th><th>Probed</th><th>Coverage</th>
        <th>Critical</th><th>2xx</th><th>4xx</th><th>5xx</th><th>deep/stub</th></tr></thead>
      <tbody>{"".join(major_rows) or '<tr><td colspan="10">—</td></tr>'}</tbody>
    </table>
    <h3>REST critical failures (sample)</h3>
    <table>
      <thead><tr><th>Major</th><th>Verb</th><th>Path</th><th>Kind</th><th>Status</th><th>Detail</th></tr></thead>
      <tbody>{"".join(fail_rows) or '<tr><td colspan="6">none</td></tr>'}</tbody>
    </table>
    """

def _section_crud(summary: dict[str, Any]) -> str:
    crud = summary.get("crud") or {}
    flows = crud.get("flows") or []
    rows = []
    for f in flows:
        rows.append(
            f"<tr class='{_esc(f.get('status'))}'>"
            f"<td>{_esc(f.get('flow'))}</td>"
            f"<td>{_esc(f.get('step'))}</td>"
            f"<td>{_esc(f.get('status'))}</td>"
            f"<td class='err'>{_esc(f.get('error') or '—')}</td>"
            f"</tr>"
        )
    return f"""
    <h2>Deep REST CRUD</h2>
    <p class="meta">total={_esc(crud.get("total"))} · failed={_esc(crud.get("failed"))}</p>
    <table>
      <thead><tr><th>Flow</th><th>Step</th><th>Status</th><th>Detail</th></tr></thead>
      <tbody>{"".join(rows) or '<tr><td colspan="4">— (smoke skips CRUD)</td></tr>'}</tbody>
    </table>
    """


def _section_soap(summary: dict[str, Any]) -> str:
    soap = summary.get("soap") or {}
    ops = soap.get("ops") or []
    rows = []
    for op in ops:
        status = "passed" if op.get("ok") else "failed"
        rows.append(
            f"<tr class='{_esc(status)}'>"
            f"<td><code>{_esc(op.get('op'))}</code></td>"
            f"<td>{_esc(op.get('status'))}</td>"
            f"<td>{_esc(status)}</td>"
            f"<td class='err'>{_esc(op.get('error') or '—')}</td>"
            f"</tr>"
        )
    return f"""
    <h2>SOAP WSDL ops</h2>
    <p class="meta">total={_esc(soap.get("total"))} · failed={_esc(soap.get("failed"))}</p>
    <table>
      <thead><tr><th>Operation</th><th>HTTP</th><th>Status</th><th>Detail</th></tr></thead>
      <tbody>{"".join(rows) or '<tr><td colspan="4">— (smoke skips SOAP)</td></tr>'}</tbody>
    </table>
    """


def render_html(summary: dict[str, Any]) -> str:
    generated = summary.get("generated_at") or datetime.now(UTC).isoformat()
    cases = summary.get("cases") or []
    total = len(cases)
    passed = sum(1 for c in cases if c.get("status") == "passed")
    failed = sum(1 for c in cases if c.get("status") == "failed")
    skipped = sum(1 for c in cases if c.get("status") == "skipped")
    rest = summary.get("rest") or {}
    crud = summary.get("crud") or {}
    soap = summary.get("soap") or {}

    rows = []
    for case in cases:
        status = case.get("status") or ""
        outs = case.get("outputs") or {}
        out_html = "<br/>".join(f"<code>{_esc(k)}</code>={_esc(v)}" for k, v in outs.items())
        err = _esc(case.get("error") or "")
        rows.append(
            f"<tr class='{_esc(status)}'>"
            f"<td>{_esc(case.get('id'))}</td>"
            f"<td>{_esc(case.get('title'))}</td>"
            f"<td>{_esc(status)}</td>"
            f"<td class='outs'>{out_html or '—'}</td>"
            f"<td class='err'>{err or '—'}</td>"
            f"</tr>"
        )

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8"/>
  <title>pulumi hybrid lab report</title>
  <style>
    :root {{
      --bg:#0f1419; --panel:#1a222c; --text:#e7eef7; --muted:#9aa8b8;
      --ok:#3dd68c; --fail:#ff6b6b; --skip:#f0c14a; --line:#2a3542; --accent:#5b9fd4;
    }}
    body {{ margin:0; font-family:"IBM Plex Sans","Segoe UI",sans-serif; background:var(--bg); color:var(--text); }}
    header, main {{ max-width:1200px; margin:0 auto; padding:1.5rem; }}
    h1 {{ margin:0 0 .4rem; }}
    h2 {{ margin:1.75rem 0 .6rem; color:var(--accent); }}
    h3 {{ margin:1rem 0 .4rem; font-size:1rem; color:var(--muted); }}
    .meta {{ color:var(--muted); }}
    .summary {{ display:grid; grid-template-columns:repeat(4,1fr); gap:.75rem; margin:1rem 0 1.5rem; }}
    .stat {{ background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:1rem; }}
    .stat strong {{ display:block; font-size:1.5rem; margin-top:.25rem; }}
    .ok strong {{ color:var(--ok); }} .fail strong {{ color:var(--fail); }} .skip strong {{ color:var(--skip); }}
    table {{ width:100%; border-collapse:collapse; background:var(--panel); border:1px solid var(--line);
      border-radius:12px; overflow:hidden; margin-bottom:1rem; }}
    th, td {{ padding:.55rem .65rem; border-bottom:1px solid var(--line); text-align:left; vertical-align:top; font-size:.9rem; }}
    th {{ color:var(--accent); }}
    tr.failed td:nth-child(3) {{ color:var(--fail); font-weight:600; }}
    tr.passed td:nth-child(3) {{ color:var(--ok); }}
    tr.skipped td:nth-child(3) {{ color:var(--skip); }}
    code {{ font-family:ui-monospace,Menlo,monospace; font-size:.8rem; }}
    .outs, .err {{ word-break:break-word; }}
    .metrics {{ display:grid; grid-template-columns:repeat(3,1fr); gap:.75rem; margin-bottom:1rem; }}
  </style>
</head>
<body>
  <header>
    <h1>pulumi hybrid lab suite</h1>
    <div class="meta">Generated {_esc(generated)} · server {_esc(summary.get("vsphere_server"))}
      · base {_esc(summary.get("vsphere_base"))}
      · smoke={_esc(summary.get("smoke"))}</div>
  </header>
  <main>
    <section class="summary">
      <div class="stat"><span>Cases</span><strong>{total}</strong></div>
      <div class="stat ok"><span>Passed</span><strong>{passed}</strong></div>
      <div class="stat fail"><span>Failed</span><strong>{failed}</strong></div>
      <div class="stat skip"><span>Skipped</span><strong>{skipped}</strong></div>
    </section>
    <section class="metrics">
      <div class="stat"><span>REST failed</span><strong>{_esc(rest.get("failed", 0))}</strong>
        <span class="meta"> / {_esc(rest.get("total", 0))} probes</span></div>
      <div class="stat"><span>CRUD failed</span><strong>{_esc(crud.get("failed", 0))}</strong>
        <span class="meta"> / {_esc(crud.get("total", 0))} flows</span></div>
      <div class="stat"><span>SOAP failed</span><strong>{_esc(soap.get("failed", 0))}</strong>
        <span class="meta"> / {_esc(soap.get("total", 0))} ops</span></div>
    </section>
    <h2>Suite cases</h2>
    <table>
      <thead><tr><th>ID</th><th>Title</th><th>Status</th><th>Outputs</th><th>Error</th></tr></thead>
      <tbody>{"".join(rows)}</tbody>
    </table>
    {_section_rest(summary)}
    {_section_crud(summary)}
    {_section_soap(summary)}
  </main>
</body>
</html>
"""


def write_report(summary: dict[str, Any], path: Path) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(render_html(summary), encoding="utf-8")
