"""Unit tests for HistoryHtmlGenerator."""

import pytest

from tools.view_history.html_generator import HistoryHtmlGenerator


@pytest.fixture
def sample_audits() -> list[dict]:
    """Sample audit data."""
    return [
        {
            "dir_name": "2026-01-29_14-30-45_security",
            "timestamp": "2026-01-29T14:30:45",
            "lens": "security",
            "total_findings": 5,
            "files_examined": 42,
            "by_severity": {"critical": 0, "high": 2, "medium": 2, "low": 1, "info": 0},
            "findings": [
                {
                    "severity": "high",
                    "category": "SQL Injection",
                    "description": "Unsafe query in db.py",
                    "affected_files": ["src/db.py"],
                }
            ],
        },
        {
            "dir_name": "2026-01-28_10-00-00_a11y",
            "timestamp": "2026-01-28T10:00:00",
            "lens": "a11y",
            "total_findings": 3,
            "files_examined": 15,
            "by_severity": {"critical": 1, "high": 0, "medium": 2, "low": 0, "info": 0},
            "findings": [],
        },
    ]


class TestHistoryHtmlGeneratorInit:
    def test_init_stores_project_name(self):
        generator = HistoryHtmlGenerator("my-project", [])
        assert generator.project_name == "my-project"

    def test_init_stores_audits(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        assert len(generator.audits) == 2


class TestTemplateLoading:
    def test_template_dir_exists(self):
        assert HistoryHtmlGenerator.TEMPLATE_DIR.exists()

    def test_static_dir_exists(self):
        assert HistoryHtmlGenerator.STATIC_DIR.exists()

    def test_template_file_exists(self):
        template_path = HistoryHtmlGenerator.TEMPLATE_DIR / "history.html"
        assert template_path.exists()

    def test_css_file_exists(self):
        css_path = HistoryHtmlGenerator.STATIC_DIR / "css" / "history.css"
        assert css_path.exists()

    def test_js_file_exists(self):
        js_path = HistoryHtmlGenerator.STATIC_DIR / "js" / "history.js"
        assert js_path.exists()

    def test_read_template(self):
        generator = HistoryHtmlGenerator("my-project", [])
        template = generator._read_template("history.html")

        assert "{{PROJECT_NAME}}" in template
        assert "{{INLINE_CSS}}" in template
        assert "{{INLINE_JS}}" in template
        assert "{{SIDEBAR}}" in template
        assert "{{HEADER}}" in template
        assert "{{AUDIT_LIST}}" in template
        assert "{{COMPARISON_OVERLAY}}" in template
        assert "{{AUDIT_DATA}}" in template

    def test_read_static_css(self):
        generator = HistoryHtmlGenerator("my-project", [])
        css = generator._read_static("css/history.css")

        assert "--color-bg:" in css
        assert "--color-accent:" in css
        assert ".sidebar" in css

    def test_read_static_js(self):
        generator = HistoryHtmlGenerator("my-project", [])
        js = generator._read_static("js/history.js")

        assert "function toggleCard" in js
        assert "function exportJSON" in js
        assert "function exportCSV" in js
        assert "function exportMarkdown" in js


class TestGenerate:
    def test_generates_valid_html(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "<!DOCTYPE html>" in html
        assert "<html" in html
        assert "</html>" in html

    def test_handles_nested_summary_structure(self):
        """Test that audits with nested summary object display correctly."""
        audits = [
            {
                "dir_name": "2026-01-29_14-30-45_security",
                "timestamp": "2026-01-29T14:30:45",
                "lens": "security",
                "summary": {
                    "total_findings": 5,
                    "files_examined": 42,
                    "by_severity": {"critical": 1, "high": 2, "medium": 2, "low": 0},
                },
                "findings": [],
            }
        ]

        generator = HistoryHtmlGenerator("my-project", audits)
        html = generator.generate()

        assert "5 findings" in html
        assert "42 files" in html
        assert "1 critical" in html
        assert "2 high" in html

    def test_includes_project_name_in_title(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "<title>Optix Audit History - my-project</title>" in html

    def test_includes_css_styles(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "<style>" in html
        assert "--color-bg:" in html
        assert "#0a0f0d" in html

    def test_includes_audit_cards(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "audit-card" in html
        assert "security" in html.lower()
        assert "a11y" in html.lower()

    def test_placeholders_replaced(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "{{PROJECT_NAME}}" not in html
        assert "{{INLINE_CSS}}" not in html
        assert "{{INLINE_JS}}" not in html
        assert "{{SIDEBAR}}" not in html
        assert "{{HEADER}}" not in html
        assert "{{AUDIT_LIST}}" not in html
        assert "{{COMPARISON_OVERLAY}}" not in html
        assert "{{AUDIT_DATA}}" not in html


class TestExportButtons:
    def test_includes_export_buttons(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "export-buttons" in html
        assert "exportJSON()" in html
        assert "exportCSV()" in html
        assert "exportMarkdown()" in html

    def test_export_button_styles_included(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert ".export-btn" in html
        assert ".export-buttons" in html


class TestEmptyState:
    def test_shows_empty_state_when_no_audits(self):
        generator = HistoryHtmlGenerator("my-project", [])
        html = generator.generate()

        assert "No Audit History" in html
        assert "empty-state" in html


class TestSeverityPills:
    def test_generates_severity_pills(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "severity-pill" in html
        assert "2 high" in html
        assert "2 medium" in html

    def test_shows_clean_when_no_findings(self):
        audits = [
            {
                "dir_name": "2026-01-29_14-30-45_security",
                "timestamp": "2026-01-29T14:30:45",
                "lens": "security",
                "total_findings": 0,
                "files_examined": 10,
                "by_severity": {
                    "critical": 0,
                    "high": 0,
                    "medium": 0,
                    "low": 0,
                    "info": 0,
                },
                "findings": [],
            }
        ]

        generator = HistoryHtmlGenerator("my-project", audits)
        html = generator.generate()

        assert "Clean" in html


class TestFindingsDetail:
    def test_includes_finding_details(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "SQL Injection" in html
        assert "Unsafe query" in html
        assert "src/db.py" in html

    def test_handles_dict_affected_files(self):
        """Test that affected_files as list of dicts works (principal audit format)."""
        audits = [
            {
                "dir_name": "2026-01-29_14-30-45_principal",
                "timestamp": "2026-01-29T14:30:45",
                "lens": "principal",
                "total_findings": 1,
                "files_examined": 5,
                "by_severity": {"high": 1},
                "findings": [
                    {
                        "severity": "high",
                        "category": "Complexity",
                        "description": "High cyclomatic complexity",
                        "affected_files": [
                            {"file_path": "src/complex.py", "line_start": 10, "line_end": 50},
                            {"file_path": "src/utils.py", "line_start": 100},
                        ],
                    }
                ],
            }
        ]

        generator = HistoryHtmlGenerator("my-project", audits)
        html = generator.generate()

        assert "src/complex.py" in html
        assert "src/utils.py" in html

    def test_handles_missing_findings(self):
        audits = [
            {
                "dir_name": "2026-01-29_14-30-45_security",
                "timestamp": "2026-01-29T14:30:45",
                "lens": "security",
                "total_findings": 0,
                "files_examined": 10,
                "by_severity": {},
            }
        ]

        generator = HistoryHtmlGenerator("my-project", audits)
        html = generator.generate()

        assert "No findings recorded" in html


class TestTimestampFormatting:
    def test_formats_timestamp(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "2026-01-29 14:30:45" in html


class TestHtmlEscaping:
    def test_escapes_special_characters_in_category(self):
        audits = [
            {
                "dir_name": "2026-01-29_14-30-45_security",
                "timestamp": "2026-01-29T14:30:45",
                "lens": "security",
                "total_findings": 1,
                "files_examined": 1,
                "by_severity": {"high": 1},
                "findings": [
                    {
                        "severity": "high",
                        "category": "<script>alert('xss')</script>",
                        "description": "Test <b>html</b> & entities",
                        "affected_files": ["file.py"],
                    }
                ],
            }
        ]

        generator = HistoryHtmlGenerator("my<>project", audits)
        html = generator.generate()

        assert "&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;" in html
        assert "&lt;b&gt;html&lt;/b&gt;" in html
        assert "&amp; entities" in html
        assert "my&lt;&gt;project" in html


class TestSidebar:
    def test_includes_sidebar(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert '<aside class="sidebar">' in html
        assert "sidebar-header" in html
        assert "lens-groups" in html

    def test_groups_audits_by_lens(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert 'data-lens="security"' in html
        assert 'data-lens="a11y"' in html

    def test_sidebar_shows_timeline_items(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "timeline-item" in html
        assert "timeline-date" in html
        assert "timeline-finding-count" in html

    def test_sidebar_shows_compare_controls(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "compare-controls" in html
        assert "compare-btn" in html

    def test_main_wrapper_has_correct_structure(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "main-wrapper" in html
        assert "--sidebar-width" in html


class TestGroupAuditsByLens:
    def test_groups_by_lens_type(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        groups = generator._group_audits_by_lens()

        assert "security" in groups
        assert "a11y" in groups
        assert len(groups["security"]) == 1
        assert len(groups["a11y"]) == 1

    def test_handles_multiple_audits_same_lens(self):
        audits = [
            {"dir_name": "audit-1", "lens": "security", "timestamp": "2026-01-29T10:00:00"},
            {"dir_name": "audit-2", "lens": "security", "timestamp": "2026-01-30T10:00:00"},
            {"dir_name": "audit-3", "lens": "a11y", "timestamp": "2026-01-31T10:00:00"},
        ]
        generator = HistoryHtmlGenerator("my-project", audits)
        groups = generator._group_audits_by_lens()

        assert len(groups["security"]) == 2
        assert len(groups["a11y"]) == 1

    def test_includes_index_in_grouped_audits(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        groups = generator._group_audits_by_lens()

        for lens_audits in groups.values():
            for audit in lens_audits:
                assert "_index" in audit


class TestComparisonOverlay:
    def test_includes_comparison_overlay(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "comparison-overlay" in html
        assert "comparison-header" in html
        assert "comparison-content" in html

    def test_includes_comparison_trend_section(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "comparison-trend" in html
        assert "trend-indicator" in html
        assert "trend-label" in html

    def test_includes_severity_delta_grid(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "severity-delta-grid" in html

    def test_includes_breakdown_tabs(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "breakdown-tabs" in html
        assert 'data-tab="resolved"' in html
        assert 'data-tab="new"' in html
        assert 'data-tab="persisting"' in html
        assert 'data-tab="improved"' in html
        assert 'data-tab="worsened"' in html


class TestAuditDataScript:
    def test_includes_audit_data_script(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "const auditData = " in html

    def test_audit_data_contains_findings(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert '"findings":' in html
        assert '"SQL Injection"' in html

    def test_audit_data_contains_confidence(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        data = generator._get_audit_data()

        for audit_data in data.values():
            assert "confidence" in audit_data


class TestShortDateFormatting:
    def test_formats_short_date(self):
        from tools.view_history.utils import format_timestamp

        assert format_timestamp("2026-01-29T14:30:45", "short") == "Jan 29"
        assert format_timestamp("2026-12-05T10:00:00", "short") == "Dec 5"

    def test_handles_invalid_timestamp(self):
        from tools.view_history.utils import format_timestamp

        result = format_timestamp("", "short")
        assert result == "Unknown"

        result = format_timestamp("invalid", "short")
        assert isinstance(result, str)


class TestSeverityDots:
    def test_generates_severity_dots(self):
        generator = HistoryHtmlGenerator("my-project", [])
        by_severity = {"critical": 2, "high": 1, "medium": 0, "low": 1}

        dots_html = generator._generate_severity_dots(by_severity)

        assert dots_html.count("severity-dot") == 4
        assert "#ef4444" in dots_html
        assert "#f97316" in dots_html

    def test_limits_dots_per_severity(self):
        generator = HistoryHtmlGenerator("my-project", [])
        by_severity = {"critical": 10}

        dots_html = generator._generate_severity_dots(by_severity)

        assert dots_html.count("severity-dot") == 3

    def test_empty_when_no_findings(self):
        generator = HistoryHtmlGenerator("my-project", [])

        dots_html = generator._generate_severity_dots({})

        assert dots_html == ""


class TestComparisonJavaScript:
    def test_includes_comparison_functions(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "function compareAudits" in html
        assert "function compareFindingsDetailed" in html
        assert "function renderComparison" in html
        assert "function showBreakdownTab" in html

    def test_includes_sidebar_functions(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "function toggleLensGroup" in html
        assert "function selectAudit" in html
        assert "function toggleCompareSelection" in html
        assert "function cancelCompare" in html
        assert "function runComparison" in html

    def test_includes_export_functions(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "function exportJSON" in html
        assert "function exportCSV" in html
        assert "function exportMarkdown" in html
        assert "function downloadFile" in html
        assert "function escapeCSV" in html
        assert "function normalizeAffectedFiles" in html

    def test_includes_toast_functions(self, sample_audits):
        generator = HistoryHtmlGenerator("my-project", sample_audits)
        html = generator.generate()

        assert "function showToast" in html
        assert "function closeToast" in html
        assert "TOAST_ICONS" in html
        assert "toast-container" in html
