from __future__ import annotations

from pathlib import Path
from typing import Any

from jinja2 import Template

from aegisrt.compliance.owasp import (
    OWASP_LLM_TOP_10,
    generate_compliance_report,
    get_coverage_gaps,
)
from aegisrt.core.result import RunReport

_COMPLIANCE_HTML_TEMPLATE = Template("""\
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OWASP LLM Top 10 Compliance Report &mdash; {{ run_id }}</title>
<style>
  :root{--pass:
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;padding:2rem}
  .container{max-width:1200px;margin:0 auto}
  header{background:linear-gradient(135deg,
  header h1{font-size:1.5rem;margin-bottom:.5rem}
  header .meta{font-size:.9rem;opacity:.85}
  .summary-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1rem;margin-bottom:2rem}
  .scard{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:1.2rem;text-align:center}
  .scard .number{font-size:2rem;font-weight:700}
  .scard .label{font-size:.8rem;color:
  .scard.pass .number{color:var(--pass)}
  .scard.fail .number{color:var(--fail)}
  .scard.not-tested .number{color:var(--not-tested)}
  .scard.coverage .number{color:
  .category{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:1.5rem;margin-bottom:1rem;border-left:5px solid var(--border)}
  .category.status-passed{border-left-color:var(--pass)}
  .category.status-failed{border-left-color:var(--fail)}
  .category.status-not_tested{border-left-color:var(--not-tested)}
  .category.status-audit_findings_only{border-left-color:var(--warn)}
  .category-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem}
  .category-header h3{font-size:1.1rem}
  .badge{display:inline-block;padding:3px 12px;border-radius:12px;font-size:.8rem;font-weight:600;color:
  .badge.passed{background:var(--pass)}
  .badge.failed{background:var(--fail)}
  .badge.not_tested{background:var(--not-tested)}
  .badge.audit_findings_only{background:var(--warn)}
  .sev{display:inline-block;padding:2px 10px;border-radius:12px;font-size:.75rem;font-weight:600;color:
  .sev.critical{background:var(--fail)}.sev.high{background:
  .category-desc{color:
  .category-stats{font-size:.85rem;color:
  .gaps{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:1.5rem;margin-top:2rem}
  .gaps h2{margin-bottom:1rem;font-size:1.2rem;color:var(--fail)}
  .gap-item{padding:.75rem 0;border-bottom:1px solid var(--border)}
  .gap-item:last-child{border-bottom:none}
  .gap-item .rec{color:
  footer{text-align:center;color:
</style>
</head>
<body>
<div class="container">
  <header>
    <h1>OWASP LLM Top 10 Compliance Report</h1>
    <div class="meta">
      Run ID: {{ run_id }} &bull; Timestamp: {{ timestamp }}
    </div>
  </header>

  <div class="summary-cards">
    <div class="scard coverage"><div class="number">{{ summary.coverage_pct }}%</div><div class="label">Coverage</div></div>
    <div class="scard"><div class="number">{{ summary.total_categories }}</div><div class="label">Categories</div></div>
    <div class="scard pass"><div class="number">{{ summary.passed }}</div><div class="label">Passed</div></div>
    <div class="scard fail"><div class="number">{{ summary.failed }}</div><div class="label">Failed</div></div>
    <div class="scard not-tested"><div class="number">{{ summary.not_tested }}</div><div class="label">Not Tested</div></div>
  </div>

  <h2 style="margin-bottom:1rem;">Categories</h2>
  {% for owasp_id, cat in categories.items() %}
  <div class="category status-{{ cat.status }}">
    <div class="category-header">
      <h3>{{ cat.id }}: {{ cat.name }} <span class="sev {{ cat.severity }}">{{ cat.severity | upper }}</span></h3>
      <span class="badge {{ cat.status }}">{{ cat.status | replace("_", " ") | upper }}</span>
    </div>
    <div class="category-desc">{{ owasp_descriptions[owasp_id] }}</div>
    {% if cat.total > 0 %}
    <div class="category-stats">
      Tests: {{ cat.total }} &bull; Passed: {{ cat.passed }} &bull; Failed: {{ cat.failed }}
    </div>
    {% endif %}
  </div>
  {% endfor %}

  {% if gaps %}
  <div class="gaps">
    <h2>Coverage Gaps &amp; Recommendations</h2>
    {% for gap in gaps %}
    <div class="gap-item">
      <strong>{{ gap.id }}: {{ gap.name }}</strong> <span class="sev {{ gap.severity }}">{{ gap.severity | upper }}</span>
      <div class="rec">{{ gap.recommendation }}</div>
    </div>
    {% endfor %}
  </div>
  {% endif %}

  <footer>Generated by AegisRT</footer>
</div>
</body>
</html>
""")


class ComplianceReportWriter:

    def write(
        self,
        report: RunReport,
        path: str | Path,
        audit_findings: list[dict[str, Any]] | None = None,
    ) -> Path:
        out = Path(path)
        out.parent.mkdir(parents=True, exist_ok=True)

        compliance = generate_compliance_report(
            report.results, audit_findings=audit_findings
        )

        owasp_descriptions = {
            oid: entry["description"] for oid, entry in OWASP_LLM_TOP_10.items()
        }

        html = _COMPLIANCE_HTML_TEMPLATE.render(
            run_id=report.run_id,
            timestamp=report.timestamp,
            categories=compliance["categories"],
            summary=compliance["summary"],
            gaps=compliance["gaps"],
            owasp_descriptions=owasp_descriptions,
        )
        out.write_text(html, encoding="utf-8")
        return out.resolve()
