"""Tests for docs/census.html — validates structure and security."""

from __future__ import annotations

import re
from html.parser import HTMLParser
from pathlib import Path

import pytest

CENSUS_HTML = Path(__file__).resolve().parent.parent / "docs" / "census.html"


class _StructureParser(HTMLParser):
    """Lightweight HTML parser that collects structure info."""

    def __init__(self):
        super().__init__()
        self.ids: list[str] = []
        self.toc_hrefs: list[str] = []
        self.hrefs: list[str] = []
        self.errors: list[str] = []
        self._in_toc = False
        self._tag_stack: list[str] = []

    def handle_starttag(self, tag, attrs):
        self._tag_stack.append(tag)
        attr_dict = dict(attrs)
        if "id" in attr_dict:
            self.ids.append(attr_dict["id"])
        if tag == "nav" and attr_dict.get("class", "") == "toc":
            self._in_toc = True
        if tag == "a" and "href" in attr_dict:
            href = attr_dict["href"]
            self.hrefs.append(href)
            if self._in_toc and href.startswith("#"):
                self.toc_hrefs.append(href[1:])

    def handle_endtag(self, tag):
        if tag == "nav" and self._in_toc:
            self._in_toc = False
        if self._tag_stack and self._tag_stack[-1] == tag:
            self._tag_stack.pop()


@pytest.fixture(scope="module")
def html_content() -> str:
    assert CENSUS_HTML.exists(), f"docs/census.html not found at {CENSUS_HTML}"
    return CENSUS_HTML.read_text(encoding="utf-8")


@pytest.fixture(scope="module")
def parsed(html_content: str) -> _StructureParser:
    parser = _StructureParser()
    parser.feed(html_content)
    return parser


class TestCensusHtmlStructure:
    """Validate census.html is well-formed and complete."""

    def test_is_valid_html(self, html_content: str) -> None:
        assert "<!doctype html>" in html_content.lower()
        assert "<html" in html_content
        assert "</html>" in html_content

    def test_has_title(self, html_content: str) -> None:
        assert "<title>" in html_content
        assert "Census" in html_content

    def test_has_meta_charset(self, html_content: str) -> None:
        assert 'charset="utf-8"' in html_content

    def test_has_viewport_meta(self, html_content: str) -> None:
        assert 'name="viewport"' in html_content

    def test_has_canonical_url(self, html_content: str) -> None:
        assert "developers.certisigma.ch/census" in html_content

    def test_section_ids_present(self, parsed: _StructureParser) -> None:
        expected_sections = {
            "how-it-works", "installation", "quick-start",
            "github-action", "commands", "output-formats",
            "forensic-features", "cooperation", "ci-cd-integration",
            "configuration", "security-model", "compliance",
            "architecture", "global-options",
        }
        actual_ids = set(parsed.ids)
        missing = expected_sections - actual_ids
        assert not missing, f"Missing section IDs: {missing}"

    def test_nav_has_census_active(self, html_content: str) -> None:
        assert 'class="nav-link active"' in html_content
        active_idx = html_content.index('class="nav-link active"')
        context = html_content[max(0, active_idx - 100):active_idx + 100]
        assert "Census" in context or "census" in context

    def test_has_dark_light_toggle(self, html_content: str) -> None:
        assert "theme-toggle" in html_content
        assert "toggleTheme" in html_content

    def test_has_command_palette(self, html_content: str) -> None:
        assert "cmd-overlay" in html_content
        assert "cmd-input" in html_content

    def test_has_sidebar_toc(self, html_content: str) -> None:
        assert 'id="toc"' in html_content
        assert "buildToc" in html_content

    def test_has_install_command(self, html_content: str) -> None:
        assert "pip install certisigma-census" in html_content

    def test_has_copy_buttons(self, html_content: str) -> None:
        assert "copyCode" in html_content
        assert "copy-btn" in html_content

    def test_has_footer(self, html_content: str) -> None:
        assert "sdk-footer" in html_content
        assert "Ten Sigma Sagl" in html_content


class TestCensusHtmlSecurity:
    """Verify no XSS vectors in the static HTML."""

    def test_no_javascript_hrefs(self, parsed: _StructureParser) -> None:
        js_hrefs = [h for h in parsed.hrefs if h.startswith("javascript:")]
        assert not js_hrefs, f"javascript: hrefs found: {js_hrefs}"

    def test_no_data_hrefs(self, parsed: _StructureParser) -> None:
        data_hrefs = [h for h in parsed.hrefs if h.startswith("data:")]
        assert not data_hrefs, f"data: hrefs found: {data_hrefs}"

    def test_no_inline_event_handlers(self, html_content: str) -> None:
        dangerous = re.findall(
            r'\bon(error|load|mouseover|focus|blur)\s*=',
            html_content, re.IGNORECASE,
        )
        assert not dangerous, f"Inline event handlers found: {dangerous}"

    def test_no_eval_calls(self, html_content: str) -> None:
        assert "eval(" not in html_content

    def test_no_document_write(self, html_content: str) -> None:
        assert "document.write" not in html_content

    def test_external_links_have_noopener(self, html_content: str) -> None:
        external_links = re.findall(
            r'<a[^>]+target="_blank"[^>]*>',
            html_content,
        )
        for link in external_links:
            assert "noopener" in link, f"External link missing noopener: {link[:80]}"
