"""Tests for TestParser - Priority 80 test reference parser."""

from elspais.graph.parsers import ParseContext
from elspais.graph.parsers.test import TestParser


class TestTestParserPriority:
    """Tests for TestParser priority."""

    def test_priority_is_80(self):
        parser = TestParser()
        assert parser.priority == 80


class TestTestParserBasic:
    """Tests for basic test reference parsing."""

    def test_claims_test_with_req_reference(self):
        parser = TestParser()
        lines = [
            (1, "def test_user_auth_REQ_p00001():"),
            (2, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_auth.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 1
        assert results[0].content_type == "test_ref"
        assert "REQ-p00001" in results[0].parsed_data["validates"]

    def test_claims_test_with_inline_marker(self):
        parser = TestParser()
        lines = [
            (1, "def test_something():"),
            (2, "    # Tests REQ-p00001"),
            (3, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_auth.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 1
        assert "REQ-p00001" in results[0].parsed_data["validates"]

    def test_no_test_refs_returns_empty(self):
        parser = TestParser()
        lines = [
            (1, "def test_unrelated():"),
            (2, "    assert 1 + 1 == 2"),
        ]
        ctx = ParseContext(file_path="tests/test_math.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 0

    def test_REQ_d00066_D_validates_assertion_level_reference(self):
        """REQ-d00066-D: Test names with assertion labels are validated."""
        parser = TestParser()
        lines = [
            (1, "def test_REQ_d00060_A_returns_node_counts():"),
            (2, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_mcp.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 1
        assert results[0].content_type == "test_ref"
        # Should validate the full reference including assertion label
        assert "REQ-d00060-A" in results[0].parsed_data["validates"]

    def test_REQ_d00066_D_validates_multi_assertion_reference(self):
        """REQ-d00066-D: Test names with multiple assertion labels are validated."""
        parser = TestParser()
        lines = [
            (1, "def test_REQ_d00060_A_B_combined_test():"),
            (2, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_mcp.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 1
        # Should validate REQ-d00060-A-B (multi-assertion syntax)
        assert "REQ-d00060-A-B" in results[0].parsed_data["validates"]


class TestTestParserCustomConfig:
    """Tests for TestParser with custom configuration.

    REQ-d00101-A: Parser accepts custom PatternConfig for non-standard prefixes.
    REQ-d00101-B: Parser accepts custom comment styles via ReferenceResolver.
    REQ-d00101-C: Parser validates underscore separators in test names.
    """

    def test_REQ_d00101_A_custom_prefix_spec(self):
        """REQ-d00101-A: Parser with custom prefix 'SPEC' instead of 'REQ'."""
        from elspais.utilities.patterns import PatternConfig

        pattern_config = PatternConfig.from_dict(
            {
                "prefix": "SPEC",
                "types": {
                    "prd": {"id": "p", "name": "PRD"},
                    "ops": {"id": "o", "name": "OPS"},
                    "dev": {"id": "d", "name": "DEV"},
                },
                "id_format": {"style": "numeric", "digits": 5},
            }
        )
        parser = TestParser(pattern_config=pattern_config)
        lines = [
            (1, "def test_SPEC_d00101_custom_spec():"),
            (2, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_spec.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 1
        assert "SPEC-d00101" in results[0].parsed_data["validates"]

    def test_REQ_d00101_B_custom_comment_styles_with_resolver(self):
        """REQ-d00101-B: Parser uses custom comment styles from ReferenceResolver."""
        from elspais.utilities.patterns import PatternConfig
        from elspais.utilities.reference_config import (
            ReferenceConfig,
            ReferenceResolver,
        )

        pattern_config = PatternConfig.from_dict(
            {
                "prefix": "REQ",
                "types": {
                    "prd": {"id": "p", "name": "PRD"},
                    "ops": {"id": "o", "name": "OPS"},
                    "dev": {"id": "d", "name": "DEV"},
                },
                "id_format": {"style": "numeric", "digits": 5},
            }
        )

        # Custom config with only C-style block comments
        ref_config = ReferenceConfig(
            separators=["-", "_"],
            case_sensitive=False,
            comment_styles=["/*", "*/"],
            keywords={
                "validates": ["Tests", "Validates"],
            },
        )
        resolver = ReferenceResolver(ref_config)
        parser = TestParser(pattern_config=pattern_config, reference_resolver=resolver)

        lines = [
            (1, "def test_something():"),
            (2, "    /* Tests REQ-p00002 */"),
            (3, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_custom.py")

        list(parser.claim_and_parse(lines, ctx))

        # Note: block comment style matching is limited in inline context,
        # so verify parser instantiation works with the config
        assert parser._pattern_config == pattern_config
        assert parser._reference_resolver == resolver

    def test_REQ_d00101_C_validates_underscore_separators(self):
        """REQ-d00101-C: Parser accepts underscore separators in test names."""
        from elspais.utilities.patterns import PatternConfig
        from elspais.utilities.reference_config import ReferenceConfig, ReferenceResolver

        pattern_config = PatternConfig.from_dict(
            {
                "prefix": "REQ",
                "types": {
                    "prd": {"id": "p", "name": "PRD"},
                    "ops": {"id": "o", "name": "OPS"},
                    "dev": {"id": "d", "name": "DEV"},
                },
                "id_format": {"style": "numeric", "digits": 5},
            }
        )

        # Config that accepts both - and _ as separators
        ref_config = ReferenceConfig(
            separators=["-", "_"],
            case_sensitive=False,
        )
        resolver = ReferenceResolver(ref_config)
        parser = TestParser(pattern_config=pattern_config, reference_resolver=resolver)

        lines = [
            (1, "def test_REQ_d00101_custom_feature():"),
            (2, "    assert True"),
        ]
        ctx = ParseContext(file_path="tests/test_underscore.py")

        results = list(parser.claim_and_parse(lines, ctx))

        assert len(results) == 1
        # Should normalize underscores to hyphens in output
        assert "REQ-d00101" in results[0].parsed_data["validates"]


class TestTestParserFunctionTracking:
    """Tests for function/class context tracking in TestParser.

    REQ-d00054-A: TestParser tracks function_name, class_name,
    function_line, and file_default_validates in parsed_data.
    """

    def test_REQ_d00054_A_tracks_function_name(self):
        """Function name is captured from the enclosing def statement."""
        parser = TestParser()
        lines = [
            (1, "def test_REQ_p00001_foo():"),
            (2, "    assert True"),
        ]
        context = ParseContext(file_path="tests/test_example.py")

        results = list(parser.claim_and_parse(lines, context))

        assert len(results) == 1
        assert results[0].parsed_data["function_name"] == "test_REQ_p00001_foo"

    def test_REQ_d00054_A_tracks_class_name(self):
        """Both class and function names are captured for methods in a test class."""
        parser = TestParser()
        lines = [
            (1, "class TestFoo:"),
            (2, "    def test_REQ_p00001_bar(self):"),
            (3, "        assert True"),
        ]
        context = ParseContext(file_path="tests/test_example.py")

        results = list(parser.claim_and_parse(lines, context))

        assert len(results) == 1
        assert results[0].parsed_data["class_name"] == "TestFoo"
        assert results[0].parsed_data["function_name"] == "test_REQ_p00001_bar"

    def test_REQ_d00054_A_no_function_context_for_module_comment(self):
        """Module-level comments have no function or class context."""
        parser = TestParser()
        lines = [
            (1, "# Tests REQ-p00001"),
            (2, ""),
            (3, "def test_unrelated():"),
            (4, "    pass"),
        ]
        context = ParseContext(file_path="tests/test_example.py")

        results = list(parser.claim_and_parse(lines, context))

        # The module-level comment should produce a result
        module_result = [r for r in results if r.start_line == 1]
        assert len(module_result) == 1
        assert module_result[0].parsed_data["function_name"] is None
        assert module_result[0].parsed_data["class_name"] is None

    def test_REQ_d00054_A_file_default_validates(self):
        """File-level REQ comment populates file_default_validates for all items."""
        parser = TestParser()
        lines = [
            (1, "# Tests REQ-p00001"),
            (2, ""),
            (3, "class TestFoo:"),
            (4, "    def test_REQ_p00002_bar(self):"),
            (5, "        assert True"),
        ]
        context = ParseContext(file_path="tests/test_example.py")

        results = list(parser.claim_and_parse(lines, context))

        # All results should carry the file-level default
        for result in results:
            assert "REQ-p00001" in result.parsed_data["file_default_validates"]

    def test_REQ_d00054_A_function_line_tracks_def_line(self):
        """function_line is the line number of the def statement, not the REQ reference."""
        parser = TestParser()
        lines = [
            (1, "def test_something():"),
            (2, "    # Tests REQ-p00001"),
            (3, "    assert True"),
        ]
        context = ParseContext(file_path="tests/test_example.py")

        results = list(parser.claim_and_parse(lines, context))

        assert len(results) == 1
        # function_line should be line 1 (the def), not line 2 (the comment)
        assert results[0].parsed_data["function_line"] == 1
        assert results[0].start_line == 2

    def test_REQ_d00054_A_comment_ref_inside_function(self):
        """A comment reference inside a function body gets the function context."""
        parser = TestParser()
        lines = [
            (1, "class TestFoo:"),
            (2, "    def test_something(self):"),
            (3, "        # Tests REQ-d00001"),
            (4, "        assert True"),
        ]
        context = ParseContext(file_path="tests/test_example.py")

        results = list(parser.claim_and_parse(lines, context))

        assert len(results) == 1
        assert results[0].parsed_data["function_name"] == "test_something"
        assert results[0].parsed_data["class_name"] == "TestFoo"
        assert "REQ-d00001" in results[0].parsed_data["validates"]
