"""symbols.py 单元测试 — 符号提取"""

import pytest

from index1.symbols import (
    Tag,
    extract_tags,
    filename_to_lang,
    is_codegraph_available,
)


class TestFilenameToLang:
    def test_python(self):
        assert filename_to_lang("test.py") == "python"

    def test_javascript(self):
        assert filename_to_lang("app.js") == "javascript"

    def test_typescript(self):
        assert filename_to_lang("index.ts") == "typescript"

    def test_rust(self):
        assert filename_to_lang("main.rs") == "rust"

    def test_unknown_extension(self):
        assert filename_to_lang("photo.jpg") is None


class TestExtractTags:
    """tree-sitter 可用时的标签提取测试"""

    def test_python_function_def(self):
        code = 'def hello():\n    print("hi")\n'
        tags = extract_tags("test.py", code, "test.py")
        if not is_codegraph_available():
            pytest.skip("tree-sitter not installed")
        defs = [t for t in tags if t.kind == "def"]
        names = [t.name for t in defs]
        assert "hello" in names

    def test_python_class_def(self):
        code = "class Greeter:\n    def greet(self):\n        pass\n"
        tags = extract_tags("test.py", code, "test.py")
        if not is_codegraph_available():
            pytest.skip("tree-sitter not installed")
        defs = [t for t in tags if t.kind == "def"]
        names = [t.name for t in defs]
        assert "Greeter" in names
        assert "greet" in names

    def test_python_references(self):
        code = "import os\npath = os.path.join('a', 'b')\n"
        tags = extract_tags("test.py", code, "test.py")
        if not is_codegraph_available():
            pytest.skip("tree-sitter not installed")
        refs = [t for t in tags if t.kind == "ref"]
        ref_names = [t.name for t in refs]
        # Python .scm 查询捕获函数调用引用
        assert "join" in ref_names or len(refs) > 0

    def test_javascript_function_def(self):
        code = "function fetchData() { return 42; }\n"
        tags = extract_tags("app.js", code, "app.js")
        if not is_codegraph_available():
            pytest.skip("tree-sitter not installed")
        defs = [t for t in tags if t.kind == "def"]
        names = [t.name for t in defs]
        assert "fetchData" in names

    def test_empty_code(self):
        tags = extract_tags("test.py", "", "test.py")
        assert tags == []

    def test_large_file_skipped(self):
        """超过 1MB 的文件应跳过"""
        large_code = "x = 1\n" * 200000  # ~1.2MB
        tags = extract_tags("big.py", large_code, "big.py")
        assert tags == []

    def test_tag_structure(self):
        code = "def add(a, b):\n    return a + b\n"
        tags = extract_tags("math.py", code, "src/math.py")
        if not is_codegraph_available():
            pytest.skip("tree-sitter not installed")
        if not tags:
            pytest.skip("no tags extracted")
        tag = tags[0]
        assert isinstance(tag, Tag)
        assert tag.rel_fname == "src/math.py"
        assert tag.fname == "math.py"
        assert isinstance(tag.line, int)


class TestPygmentsFallback:
    """Pygments 降级测试"""

    def test_fallback_extracts_identifiers(self):
        """当语言无 .scm 文件时应降级到 Pygments"""
        from index1.symbols import _pygments_fallback

        code = "def hello():\n    world = 42\n    return world\n"
        tags = _pygments_fallback("test.py", code, "test.py")
        # Pygments 应该能提取到标识符
        names = [t.name for t in tags]
        assert "hello" in names or "world" in names

    def test_fallback_all_ref_kind(self):
        """Pygments 降级的 tag 全部是 ref"""
        from index1.symbols import _pygments_fallback

        code = "class Foo:\n    pass\n"
        tags = _pygments_fallback("test.py", code, "test.py")
        for t in tags:
            assert t.kind == "ref"
            assert t.line == -1  # 行号未知

    def test_fallback_unknown_file(self):
        """未知文件类型返回空"""
        from index1.symbols import _pygments_fallback

        tags = _pygments_fallback("data.xyz", "hello world", "data.xyz")
        assert tags == [] or isinstance(tags, list)


class TestCodegraphAvailability:
    def test_returns_bool(self):
        result = is_codegraph_available()
        assert isinstance(result, bool)
