"""
LSP 功能测试

测试 LSP 协议类型、客户端和工具。
注意：完整的 LSP 测试需要安装对应的语言服务器。
"""

import asyncio
import os
import pytest
import tempfile
import sys

# 添加 src 到路径
src_path = os.path.join(os.path.dirname(__file__), "..", "src")
sys.path.insert(0, src_path)

# 直接导入子模块，避免 __init__.py 的循环导入问题
from lsp.protocol import (
    Position, Range, Location, DocumentSymbol, SymbolKind,
    Hover, JsonRpcRequest, JsonRpcResponse
)
from lsp.server import get_server_for_file, ServerConfig


class TestLSPProtocol:
    """测试 LSP 协议类型"""

    def test_position(self):
        """测试 Position 类型"""
        pos = Position(line=10, character=5)
        assert pos.line == 10
        assert pos.character == 5

        # 测试序列化
        data = pos.to_dict()
        assert data == {"line": 10, "character": 5}

        # 测试反序列化
        pos2 = Position.from_dict(data)
        assert pos2.line == pos.line
        assert pos2.character == pos.character

        print("Position 测试通过")

    def test_range(self):
        """测试 Range 类型"""
        start = Position(line=5, character=0)
        end = Position(line=5, character=10)
        range_ = Range(start=start, end=end)

        assert range_.start.line == 5
        assert range_.end.character == 10

        # 测试序列化
        data = range_.to_dict()
        assert "start" in data
        assert "end" in data

        # 测试反序列化
        range2 = Range.from_dict(data)
        assert range2.start.line == range_.start.line
        assert range2.end.character == range_.end.character

        print("Range 测试通过")

    def test_location(self):
        """测试 Location 类型"""
        range_ = Range(
            start=Position(line=10, character=0),
            end=Position(line=10, character=20)
        )
        location = Location(uri="file:///path/to/file.py", range=range_)

        assert location.uri == "file:///path/to/file.py"
        assert location.to_file_path() == "/path/to/file.py"

        print("Location 测试通过")

    def test_document_symbol(self):
        """测试 DocumentSymbol 类型"""
        range_ = Range(
            start=Position(line=5, character=0),
            end=Position(line=10, character=1)
        )

        symbol = DocumentSymbol(
            name="my_function",
            kind=SymbolKind.Function,
            range=range_,
            selectionRange=range_,
            detail="def my_function()"
        )

        assert symbol.name == "my_function"
        assert symbol.kind == SymbolKind.Function
        assert symbol.get_kind_name() == "Function"

        print("DocumentSymbol 测试通过")

    def test_json_rpc_request(self):
        """测试 JSON-RPC 请求"""
        request = JsonRpcRequest(
            id=1,
            method="textDocument/definition",
            params={"textDocument": {"uri": "file:///test.py"}}
        )

        data = request.to_dict()
        assert data["jsonrpc"] == "2.0"
        assert data["id"] == 1
        assert data["method"] == "textDocument/definition"
        assert "params" in data

        print("JsonRpcRequest 测试通过")

    def test_json_rpc_response(self):
        """测试 JSON-RPC 响应"""
        # 成功响应
        response = JsonRpcResponse.from_dict({
            "jsonrpc": "2.0",
            "id": 1,
            "result": {"uri": "file:///test.py"}
        })
        assert response.id == 1
        assert response.result is not None
        assert response.error is None

        # 错误响应
        error_response = JsonRpcResponse.from_dict({
            "jsonrpc": "2.0",
            "id": 2,
            "error": {"code": -32600, "message": "Invalid Request"}
        })
        assert error_response.error is not None

        print("JsonRpcResponse 测试通过")

    def test_hover(self):
        """测试 Hover 类型"""
        # 字符串内容
        hover1 = Hover(contents="def my_function()")
        assert hover1.get_text() == "def my_function()"

        # MarkupContent
        hover2 = Hover(contents={"kind": "markdown", "value": "**bold**"})
        assert "bold" in hover2.get_text()

        # 列表内容
        hover3 = Hover(contents=["line1", {"kind": "plaintext", "value": "line2"}])
        text = hover3.get_text()
        assert "line1" in text
        assert "line2" in text

        print("Hover 测试通过")


class TestServerConfig:
    """测试语言服务器配置"""

    def test_get_server_for_file(self):
        """测试根据文件获取服务器配置"""
        # Python 文件
        server = get_server_for_file("/path/to/test.py")
        assert server is not None
        assert server.id == "pyright"

        # TypeScript 文件
        server = get_server_for_file("/path/to/test.ts")
        assert server is not None
        assert server.id == "typescript"

        # Go 文件
        server = get_server_for_file("/path/to/main.go")
        assert server is not None
        assert server.id == "gopls"

        # 未知文件类型
        server = get_server_for_file("/path/to/file.unknown")
        assert server is None

        print("get_server_for_file 测试通过")

    def test_server_matches_file(self):
        """测试服务器文件匹配"""
        server = ServerConfig(
            id="test",
            extensions=[".py", ".pyi"],
            command=["test-server"],
            root_markers=["pyproject.toml"]
        )

        assert server.matches_file("test.py") is True
        assert server.matches_file("test.pyi") is True
        assert server.matches_file("test.js") is False

        print("matches_file 测试通过")

    def test_find_root(self):
        """测试项目根目录查找"""
        server = ServerConfig(
            id="test",
            extensions=[".py"],
            command=["test-server"],
            root_markers=["pyproject.toml", "setup.py"]
        )

        # 创建临时目录结构
        with tempfile.TemporaryDirectory() as tmpdir:
            # 创建项目结构
            os.makedirs(os.path.join(tmpdir, "src"))
            open(os.path.join(tmpdir, "pyproject.toml"), "w").close()
            test_file = os.path.join(tmpdir, "src", "test.py")
            open(test_file, "w").close()

            root = server.find_root(test_file)
            assert root == tmpdir

        print("find_root 测试通过")


class TestLspTool:
    """测试 LSP 工具

    注意：由于模块导入的复杂性，工具测试需要在完整项目环境下运行。
    这里只进行基本的导入检查。
    """

    def test_tool_import(self):
        """测试工具模块可以导入"""
        # 由于相对导入，这里跳过直接导入测试
        # 实际使用中通过 ToolRegistry 获取工具
        print("工具导入测试跳过（需要完整项目环境）")


def run_tests():
    """运行所有测试"""
    print("=" * 50)
    print("LSP 功能测试")
    print("=" * 50)

    # 协议类型测试
    print("\n--- 协议类型测试 ---")
    protocol_tests = TestLSPProtocol()
    protocol_tests.test_position()
    protocol_tests.test_range()
    protocol_tests.test_location()
    protocol_tests.test_document_symbol()
    protocol_tests.test_json_rpc_request()
    protocol_tests.test_json_rpc_response()
    protocol_tests.test_hover()

    # 服务器配置测试
    print("\n--- 服务器配置测试 ---")
    server_tests = TestServerConfig()
    server_tests.test_get_server_for_file()
    server_tests.test_server_matches_file()
    server_tests.test_find_root()

    # 工具测试
    print("\n--- 工具测试 ---")
    tool_tests = TestLspTool()
    tool_tests.test_tool_import()

    print("\n" + "=" * 50)
    print("所有测试通过!")
    print("=" * 50)


if __name__ == "__main__":
    run_tests()
