"""
Tests for JavaScript Extraction (REQ-tv-d00003).

Each test function documents which assertion it verifies in its docstring.
The Elspais reporter extracts these references for traceability.
"""

from pathlib import Path

import pytest


class TestJSFileLocation:
    """Tests for JavaScript file extraction location."""

    def test_js_extracted_to_scripts_file(self):
        """
        REQ-tv-d00003-A: All JavaScript code SHALL be extracted from Python
        string literals to a standalone `scripts.js` file located at
        `templates/partials/scripts.js`.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        assert scripts_path.exists(), f"scripts.js must exist at {scripts_path}"
        assert scripts_path.is_file(), "scripts.js must be a file"

        content = scripts_path.read_text()
        assert len(content) > 0, "scripts.js must not be empty"


class TestJSContent:
    """Tests for JavaScript content completeness."""

    def test_js_contains_all_side_panel_functionality(self):
        """
        REQ-tv-d00003-B: The JavaScript file SHALL contain all functionality
        currently generated by `_generate_side_panel_js()` and any other
        JavaScript-generating methods.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # Key functions that should be present
        key_functions = [
            "openReqPanel",
            "closeReqCard",
            "closeAllCards",
            "openCodeViewer",
            "closeCodeViewer",
            "toggleEditMode",
            "addPendingMove",
            "generateMoveScript",
        ]

        for func in key_functions:
            assert func in content, f"Missing function: {func}"


class TestJSValidity:
    """Tests for JavaScript validity and IDE support."""

    def test_js_is_valid_document(self):
        """
        REQ-tv-d00003-C: The JavaScript file SHALL be a valid JavaScript
        document that can be parsed by standard JavaScript tools and linters.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # Basic validity checks
        # Count braces - should be balanced
        open_braces = content.count('{')
        close_braces = content.count('}')
        assert open_braces == close_braces, \
            f"Unbalanced braces: {open_braces} open, {close_braces} close"

        # Count brackets - should be balanced
        open_brackets = content.count('[')
        close_brackets = content.count(']')
        assert open_brackets == close_brackets, \
            f"Unbalanced brackets: {open_brackets} open, {close_brackets} close"

        # Count parentheses - should be balanced
        open_parens = content.count('(')
        close_parens = content.count(')')
        assert open_parens == close_parens, \
            f"Unbalanced parentheses: {open_parens} open, {close_parens} close"

        # Should not contain Python string artifacts
        assert '"""' not in content, "JS should not contain Python docstrings"
        assert "'''" not in content, "JS should not contain Python triple strings"

    def test_js_has_proper_structure_for_ide(self):
        """
        REQ-tv-d00003-D: The JavaScript file SHALL be readable by IDEs with
        proper syntax highlighting, autocomplete, and error detection.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # File should have proper JS structure
        # Should have function definitions
        assert "function" in content or "=>" in content, \
            "Must have function definitions"

        # Should have object/class structures
        assert "{" in content and "}" in content, "Must have code blocks"


class TestModulePattern:
    """Tests for JavaScript module pattern."""

    def test_js_uses_module_pattern(self):
        """
        REQ-tv-d00003-E: JavaScript code SHALL be organized using a module
        pattern with a single namespace object (e.g., `TraceView`).
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # Should define a namespace object
        assert "TraceView" in content or "const TraceView" in content, \
            "Should define TraceView namespace"

    def test_module_has_logical_subobjects(self):
        """
        REQ-tv-d00003-F: The module pattern SHALL group related functions
        into logical sub-objects: `panel`, `codeViewer`, `editMode`, `state`.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # Check for sub-object definitions
        expected_subobjects = ["panel", "codeViewer", "editMode", "state"]

        for subobj in expected_subobjects:
            assert subobj in content, f"Missing sub-object: {subobj}"


class TestJSLoading:
    """Tests for JavaScript loading at render time."""

    def test_js_loaded_at_render_time(self, htmlerator):
        """
        REQ-tv-d00003-G: JavaScript content SHALL be loaded from the file
        at template render time.
        """
        html = htmlerator.generate(embed_content=True)

        # JS should be present in the generated HTML
        assert "<script>" in html.lower() or "<script " in html.lower(), \
            "Generated HTML must contain script tags"

        # Should contain actual JS content
        assert "TraceView" in html or "openReqPanel" in html, \
            "JavaScript content should be embedded in HTML"


class TestJSEquivalence:
    """Tests for functional equivalence with original."""

    def test_js_produces_identical_behavior(self, htmlerator):
        """
        REQ-tv-d00003-H: The extracted JavaScript SHALL produce functionally
        identical behavior to the current inline JavaScript generation.
        """
        html = htmlerator.generate(embed_content=True)

        # Key functions must be present for identical behavior
        key_functions = [
            "openReqPanel",
            "closeReqCard",
            "openCodeViewer",
        ]

        for func in key_functions:
            assert func in html, f"Missing function in output: {func}"


class TestStateEncapsulation:
    """Tests for state variable encapsulation."""

    def test_global_state_encapsulated(self):
        """
        REQ-tv-d00003-I: Global state variables (e.g., `reqCardStack`,
        `pendingMoves`) SHALL be encapsulated within the module namespace.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # State variables should be inside TraceView namespace
        # They should not be declared as global let/var/const at top level
        lines = content.split('\n')

        global_state_declarations = [
            l for l in lines
            if l.strip().startswith(('let reqCardStack', 'var reqCardStack',
                                    'const reqCardStack', 'let pendingMoves',
                                    'var pendingMoves', 'const pendingMoves'))
            and 'TraceView' not in l
        ]

        assert len(global_state_declarations) == 0, \
            f"State variables should be encapsulated, found global: {global_state_declarations}"


class TestEventHandlers:
    """Tests for event handler binding."""

    def test_dynamic_elements_use_addEventListener(self):
        """
        REQ-tv-d00003-J: Event handlers for dynamically created elements
        SHALL be bound using `addEventListener` rather than inline
        `onclick` attributes.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # Should use addEventListener for dynamic elements
        assert "addEventListener" in content, \
            "Should use addEventListener for event binding"


class TestJSDocComments:
    """Tests for JSDoc documentation."""

    def test_public_functions_have_jsdoc(self):
        """
        REQ-tv-d00003-K: The JavaScript file SHALL include JSDoc comments
        for all public functions.
        """
        import trace_view.html as html_module
        html_path = Path(html_module.__file__).parent
        scripts_path = html_path / "templates" / "partials" / "scripts.js"

        content = scripts_path.read_text()

        # Should have JSDoc comments (/** ... */)
        import re
        jsdoc_pattern = r'/\*\*[\s\S]*?\*/'
        jsdoc_matches = re.findall(jsdoc_pattern, content)

        assert len(jsdoc_matches) > 0, "Should have JSDoc comments"

        # Should have at least a few documented functions
        assert len(jsdoc_matches) >= 5, \
            f"Should have JSDoc for main functions, found {len(jsdoc_matches)}"
