"""Tests for compliance report generator (HTML and PDF)."""

import tempfile
from datetime import datetime, timezone
from pathlib import Path

from apiposture_pro.enterprise.compliance.compliance_score import calculate_score
from apiposture_pro.enterprise.compliance.report_generator import (
    ComplianceReport,
    ReportFinding,
    ReportSummary,
    build_report,
    generate_html,
    generate_pdf,
)

# ── Fixtures ──────────────────────────────────────────────────────────────────


def make_minimal_report(
    framework: str = "soc2",
    findings: list[dict] | None = None,
    operator: str | None = "Test Operator",
) -> ComplianceReport:
    """Build a minimal ComplianceReport using build_report()."""
    raw_findings = findings if findings is not None else []
    score = calculate_score(0, 0, 0, 0)
    return build_report(
        scan_id="test-001",
        timestamp=datetime(2026, 4, 1, 12, 0, 0, tzinfo=timezone.utc),
        scanned_path="/tmp/test-api",
        raw_findings=raw_findings,
        total_endpoints=10,
        compliance_score=score,
        framework=framework,
        operator=operator,
        git_commit="abc1234",
    )


def make_report_with_findings() -> ComplianceReport:
    findings = [
        {"rule_id": "AP001", "severity": "high", "message": "No auth", "location": "api.py:10"},
        {"rule_id": "AP101", "severity": "critical", "message": "BAC", "location": "users.py:42"},
    ]
    score = calculate_score(critical=1, high=1, medium=0, low=0)
    return build_report(
        scan_id="test-002",
        timestamp=datetime(2026, 4, 1, 12, 0, 0, tzinfo=timezone.utc),
        scanned_path="/tmp/test-api",
        raw_findings=findings,
        total_endpoints=20,
        compliance_score=score,
        framework="all",
        operator="CI",
    )


# ── build_report tests ────────────────────────────────────────────────────────


def test_build_report_returns_compliance_report():
    report = make_minimal_report()
    assert isinstance(report, ComplianceReport)


def test_build_report_has_checksum():
    report = make_minimal_report()
    assert report.checksum
    assert len(report.checksum) == 64


def test_build_report_checksum_is_deterministic():
    r1 = make_minimal_report()
    r2 = make_minimal_report()
    assert r1.checksum == r2.checksum


def test_build_report_enriches_findings():
    report = make_report_with_findings()
    assert len(report.findings) == 2
    for f in report.findings:
        assert isinstance(f, ReportFinding)


def test_build_report_ap001_enriched_with_controls():
    report = make_report_with_findings()
    ap001 = next(f for f in report.findings if f.rule_id == "AP001")
    assert ap001.framework_controls  # non-empty list


def test_build_report_summary_populated():
    report = make_minimal_report()
    assert isinstance(report.summary, ReportSummary)
    assert report.summary.scanned_path == "/tmp/test-api"
    assert report.summary.total_endpoints == 10


def test_build_report_stores_operator():
    report = make_minimal_report(operator="Security Team")
    assert report.operator == "Security Team"


def test_build_report_stores_framework():
    report = make_minimal_report(framework="iso27001")
    assert report.framework == "iso27001"


# ── generate_html tests ───────────────────────────────────────────────────────


def test_generate_html_creates_file():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        report = make_minimal_report()
        generate_html(report, out)
        assert out.exists()


def test_generate_html_not_empty():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        generate_html(make_minimal_report(), out)
        assert out.stat().st_size > 500


def test_generate_html_contains_scope_disclaimer():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        generate_html(make_minimal_report(), out)
        content = out.read_text()
        assert "subset" in content.lower() or "scope" in content.lower()


def test_generate_html_contains_score():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        generate_html(make_minimal_report(), out)
        content = out.read_text()
        assert "100" in content  # perfect score


def test_generate_html_contains_checksum():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        report = make_minimal_report()
        generate_html(report, out)
        content = out.read_text()
        assert report.checksum[:16] in content


def test_generate_html_with_findings():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        generate_html(make_report_with_findings(), out)
        content = out.read_text()
        assert "AP001" in content
        assert "AP101" in content


def test_generate_html_soc2_framework_display():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.html"
        generate_html(make_minimal_report(framework="soc2"), out)
        content = out.read_text()
        assert "SOC 2" in content


# ── generate_pdf tests ────────────────────────────────────────────────────────


def test_generate_pdf_creates_file():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.pdf"
        generate_pdf(make_minimal_report(), out)
        assert out.exists()


def test_generate_pdf_is_nonempty():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.pdf"
        generate_pdf(make_minimal_report(), out)
        assert out.stat().st_size > 1024


def test_generate_pdf_with_findings():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.pdf"
        generate_pdf(make_report_with_findings(), out)
        assert out.exists()
        assert out.stat().st_size > 1024


def test_generate_pdf_starts_with_pdf_magic():
    with tempfile.TemporaryDirectory() as tmp:
        out = Path(tmp) / "report.pdf"
        generate_pdf(make_minimal_report(), out)
        header = out.read_bytes()[:4]
        assert header == b"%PDF"
