"""Tests for reporting/html_report.py — HTML renderer."""

from __future__ import annotations

from complyform.reporting.html_report import render_html_report
from complyform.reporting.report_data import (
    CostImpactSection,
    CrossMappingSection,
    CrossValidationSection,
    ReportData,
    ReportFinding,
    ReportMetadata,
    ReportSummary,
)


def _metadata(**overrides: object) -> ReportMetadata:
    defaults = {
        "tool_version": "0.1.0",
        "generated_at": "2026-03-16T00:00:00+00:00",
        "cloud": "gcp",
        "scan_source": "state",
        "state_hash": "sha256:abc123def456",
        "frameworks": ["soc2"],
        "tier": "pro",
        "project_id": "my-project",
    }
    defaults.update(overrides)
    return ReportMetadata(**defaults)  # type: ignore[arg-type]


def _summary(**overrides: object) -> ReportSummary:
    defaults = {
        "total_controls": 10,
        "passed": 7,
        "failed": 2,
        "manual_review": 1,
        "not_assessed": 0,
        "score": 85.0,
        "severity_counts": {"critical": 1, "high": 1, "medium": 0, "low": 0},
        "resource_count": 5,
        "assessment_duration_ms": 500,
    }
    defaults.update(overrides)
    return ReportSummary(**defaults)  # type: ignore[arg-type]


def _finding(
    *,
    control_id: str = "CC6.1",
    framework: str = "soc2",
    severity: str = "HIGH",
    confidence: str = "verified",
    cross_mappings: list[dict[str, str]] | None = None,
) -> ReportFinding:
    return ReportFinding(
        control_id=control_id,
        framework=framework,
        framework_name="SOC 2 Type II",
        resource_address="google_sql_database_instance.main",
        resource_type="google_sql_database_instance",
        status="FAIL",
        severity=severity,
        title="SSL not enforced",
        description="SSL not enforced on database",
        remediation="Enable require_ssl",
        remediation_available=True,
        cross_mappings=cross_mappings or [],
        checkov_id="CKV_GCP_6",
        native_ids=None,
        confidence=confidence,
    )


def _cross_mapping_section(
    *, overlap_matrix: list[dict[str, object]] | None = None
) -> CrossMappingSection:
    return CrossMappingSection(
        total_shared=0,
        by_category={},
        overlap_matrix=overlap_matrix,
    )


def _report_data(
    *,
    findings: list[ReportFinding] | None = None,
    metadata: ReportMetadata | None = None,
    summary: ReportSummary | None = None,
    cross_validation: CrossValidationSection | None = None,
    cost_impact: CostImpactSection | None = None,
    upgrade_cta: dict[str, str] | None = None,
    cross_mappings: CrossMappingSection | None = None,
    frameworks_detail: list[dict[str, object]] | None = None,
) -> ReportData:
    return ReportData(
        metadata=metadata or _metadata(),
        summary=summary or _summary(),
        findings=findings or [],
        not_assessed_groups=[],
        cross_mappings=cross_mappings or _cross_mapping_section(),
        cost_impact=cost_impact,
        cross_validation=cross_validation,
        frameworks_detail=frameworks_detail
        or [
            {
                "id": "soc2",
                "name": "SOC 2 Type II",
                "version": "2017",
                "tier": "community",
                "control_count": 10,
                "pass_count": 7,
                "fail_count": 2,
                "score": 85.0,
            }
        ],
        upgrade_cta=upgrade_cta,
    )


class TestRenderHtmlReport:
    """Tests for render_html_report()."""

    def test_basic(self) -> None:
        """Output is valid HTML with all section headings."""
        rd = _report_data(findings=[_finding()])
        html = render_html_report(rd)
        assert "<!DOCTYPE html>" in html
        assert "Executive Summary" in html
        assert "Findings" in html

    def test_self_contained(self) -> None:
        """No external URLs: no <link>, no <script src=."""
        rd = _report_data(findings=[_finding()])
        html = render_html_report(rd)
        assert '<link rel="stylesheet"' not in html
        assert "<script src=" not in html

    def test_score_donut(self) -> None:
        """SVG circle with stroke-dasharray present."""
        rd = _report_data()
        html = render_html_report(rd)
        assert "<circle" in html
        assert "stroke-dasharray" in html

    def test_severity_colors(self) -> None:
        """CSS custom properties for severity colors present."""
        rd = _report_data()
        html = render_html_report(rd)
        assert "--cf-critical" in html
        assert "--cf-high" in html
        assert "--cf-medium" in html
        assert "--cf-low" in html

    def test_cross_mapping_conditional_single(self) -> None:
        """Single framework: cross-mapping section absent."""
        rd = _report_data(metadata=_metadata(frameworks=["soc2"]))
        html = render_html_report(rd)
        assert "Cross-Framework Mapping" not in html

    def test_cross_mapping_conditional_multi(self) -> None:
        """Two frameworks: cross-mapping section present."""
        rd = _report_data(
            metadata=_metadata(frameworks=["soc2", "hipaa"]),
            cross_mappings=_cross_mapping_section(
                overlap_matrix=[
                    {
                        "fw_a": "soc2",
                        "fw_b": "hipaa",
                        "shared_count": 5,
                        "overlap_pct": 30.0,
                    }
                ]
            ),
        )
        html = render_html_report(rd)
        assert "Cross-Framework Mapping" in html

    def test_cross_validation_conditional_absent(self) -> None:
        """Pro tier (no cross_validation): section absent."""
        rd = _report_data(cross_validation=None)
        html = render_html_report(rd)
        assert "Cross-Validation" not in html

    def test_cross_validation_conditional_present(self) -> None:
        """Team tier with cross_validation: section present."""
        cv = CrossValidationSection(
            score=92.0,
            confirmed=40,
            complyform_only=3,
            native_only=2,
            native_tool="AWS Security Hub",
        )
        rd = _report_data(
            metadata=_metadata(tier="team"),
            cross_validation=cv,
        )
        html = render_html_report(rd)
        assert "Cross-Validation" in html

    def test_cost_impact_conditional_absent(self) -> None:
        """Pro tier: cost impact section absent."""
        rd = _report_data(cost_impact=None)
        html = render_html_report(rd)
        assert "Cost Impact" not in html

    def test_cost_impact_conditional_present(self) -> None:
        """Team tier with cost_impact: section present."""
        ci = CostImpactSection(
            total_monthly_delta=150.0,
            total_annual_delta=1800.0,
            breakdown=[{"description": "KMS keys", "monthly": 50.0, "annual": 600.0}],
            confidence="high",
        )
        rd = _report_data(
            metadata=_metadata(tier="team"),
            cost_impact=ci,
        )
        html = render_html_report(rd)
        assert "Cost Impact" in html

    def test_upgrade_cta_pro(self) -> None:
        """Pro tier: footer has upgrade CTA."""
        rd = _report_data(
            upgrade_cta={
                "message": "Unlock trending",
                "url": "https://complyform.dev/pricing",
            }
        )
        html = render_html_report(rd)
        assert "Unlock trending" in html
        assert "complyform.dev/pricing" in html

    def test_upgrade_cta_team(self) -> None:
        """Team tier: no CTA."""
        rd = _report_data(
            metadata=_metadata(tier="team"),
            upgrade_cta=None,
        )
        html = render_html_report(rd)
        assert "Unlock trending" not in html

    def test_finding_cards(self) -> None:
        """3 findings: 3 cards with correct control_ids."""
        findings = [
            _finding(control_id="CC6.1"),
            _finding(control_id="CC7.2", severity="CRITICAL"),
            _finding(control_id="CC8.3", severity="MEDIUM"),
        ]
        rd = _report_data(findings=findings)
        html = render_html_report(rd)
        assert "CC6.1" in html
        assert "CC7.2" in html
        assert "CC8.3" in html
        assert html.count("finding-card") >= 3

    def test_cross_mapping_chips(self) -> None:
        """Finding with 6 cross-mappings: 3 shown, +3 more."""
        mappings = [
            {"framework": f"fw{i}", "control_id": f"C{i}", "framework_name": f"FW {i}"}
            for i in range(6)
        ]
        f = _finding(cross_mappings=mappings)
        rd = _report_data(findings=[f])
        html = render_html_report(rd)
        assert "+3 more" in html

    def test_inferred_findings(self) -> None:
        """Mix of verified and inferred: separate subsection."""
        findings = [
            _finding(confidence="verified", control_id="CC6.1"),
            _finding(confidence="inferred", control_id="CC7.1"),
        ]
        rd = _report_data(findings=findings)
        html = render_html_report(rd)
        assert "Low-Confidence Mappings" in html
        assert "single crosswalk source" in html

    def test_print_stylesheet(self) -> None:
        """@media print block present."""
        rd = _report_data()
        html = render_html_report(rd)
        assert "@media print" in html

    def test_autoescape(self) -> None:
        """XSS in finding title is escaped."""
        f = ReportFinding(
            control_id="XSS1",
            framework="soc2",
            framework_name="SOC 2",
            resource_address="res.xss",
            resource_type="test",
            status="FAIL",
            severity="HIGH",
            title="<script>alert(1)</script>",
            description="<script>alert(1)</script>",
            remediation="fix it",
            remediation_available=True,
            cross_mappings=[],
            checkov_id=None,
            native_ids=None,
            confidence="verified",
        )
        rd = _report_data(findings=[f])
        html = render_html_report(rd)
        assert "<script>alert(1)</script>" not in html
        assert "&lt;script&gt;" in html

    def test_empty_findings(self) -> None:
        """0 findings: renders without error, shows no-findings message."""
        rd = _report_data(findings=[])
        html = render_html_report(rd)
        assert "No compliance gaps found" in html
