"""
语言服务器配置定义

定义各种语言服务器的配置，包括命令、支持的文件扩展名、
项目根目录标识文件等。
"""

import os
import shutil
from dataclasses import dataclass, field
from typing import List, Optional, Callable


@dataclass
class ServerConfig:
    """
    语言服务器配置

    Attributes:
        id: 服务器唯一标识
        extensions: 支持的文件扩展名列表
        command: 启动命令
        root_markers: 项目根目录标识文件
        env: 环境变量
        check_command: 检查命令是否可用的方式
    """
    id: str
    extensions: List[str]
    command: List[str]
    root_markers: List[str] = field(default_factory=list)
    env: Optional[dict] = None
    check_command: Optional[str] = None  # 要检查的命令名

    def is_available(self) -> bool:
        """检查语言服务器是否可用"""
        cmd = self.check_command or self.command[0]
        return shutil.which(cmd) is not None

    def matches_file(self, file_path: str) -> bool:
        """检查文件是否匹配此服务器"""
        ext = os.path.splitext(file_path)[1].lower()
        return ext in self.extensions

    def find_root(self, file_path: str) -> Optional[str]:
        """
        查找项目根目录

        从文件所在目录向上查找，直到找到包含 root_markers 的目录
        """
        if not self.root_markers:
            return os.path.dirname(file_path)

        current = os.path.dirname(os.path.abspath(file_path))
        while current != os.path.dirname(current):  # 不是根目录
            for marker in self.root_markers:
                if os.path.exists(os.path.join(current, marker)):
                    return current
            current = os.path.dirname(current)

        # 如果没找到标记，返回文件所在目录
        return os.path.dirname(file_path)


# 预定义的语言服务器配置
SERVERS: List[ServerConfig] = [
    # Python - pyright
    ServerConfig(
        id="pyright",
        extensions=[".py", ".pyi"],
        command=["pyright-langserver", "--stdio"],
        root_markers=["pyproject.toml", "setup.py", "setup.cfg", "requirements.txt", "pyrightconfig.json"],
        check_command="pyright-langserver"
    ),

    # TypeScript/JavaScript
    ServerConfig(
        id="typescript",
        extensions=[".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
        command=["typescript-language-server", "--stdio"],
        root_markers=["package.json", "tsconfig.json", "jsconfig.json"],
        check_command="typescript-language-server"
    ),

    # Go
    ServerConfig(
        id="gopls",
        extensions=[".go"],
        command=["gopls", "serve"],
        root_markers=["go.mod", "go.sum"],
        check_command="gopls"
    ),

    # Rust
    ServerConfig(
        id="rust-analyzer",
        extensions=[".rs"],
        command=["rust-analyzer"],
        root_markers=["Cargo.toml", "Cargo.lock"],
        check_command="rust-analyzer"
    ),

    # Java
    ServerConfig(
        id="jdtls",
        extensions=[".java"],
        command=["jdtls"],
        root_markers=["pom.xml", "build.gradle", "build.gradle.kts", ".project"],
        check_command="jdtls"
    ),

    # C/C++
    ServerConfig(
        id="clangd",
        extensions=[".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"],
        command=["clangd"],
        root_markers=["compile_commands.json", "CMakeLists.txt", ".clangd", "Makefile"],
        check_command="clangd"
    ),

    # Ruby
    ServerConfig(
        id="ruby-lsp",
        extensions=[".rb", ".rake", ".gemspec", ".ru"],
        command=["ruby-lsp"],
        root_markers=["Gemfile", "Gemfile.lock", ".ruby-version"],
        check_command="ruby-lsp"
    ),

    # PHP
    ServerConfig(
        id="intelephense",
        extensions=[".php"],
        command=["intelephense", "--stdio"],
        root_markers=["composer.json", "composer.lock"],
        check_command="intelephense"
    ),

    # Swift
    ServerConfig(
        id="sourcekit-lsp",
        extensions=[".swift"],
        command=["sourcekit-lsp"],
        root_markers=["Package.swift", ".xcodeproj", ".xcworkspace"],
        check_command="sourcekit-lsp"
    ),

    # Kotlin
    ServerConfig(
        id="kotlin-language-server",
        extensions=[".kt", ".kts"],
        command=["kotlin-language-server"],
        root_markers=["build.gradle", "build.gradle.kts", "pom.xml"],
        check_command="kotlin-language-server"
    ),

    # Lua
    ServerConfig(
        id="lua-language-server",
        extensions=[".lua"],
        command=["lua-language-server"],
        root_markers=[".luarc.json", ".luarc.jsonc", ".luacheckrc"],
        check_command="lua-language-server"
    ),

    # Bash/Shell
    ServerConfig(
        id="bash-language-server",
        extensions=[".sh", ".bash", ".zsh", ".ksh"],
        command=["bash-language-server", "start"],
        root_markers=[],
        check_command="bash-language-server"
    ),

    # YAML
    ServerConfig(
        id="yaml-language-server",
        extensions=[".yaml", ".yml"],
        command=["yaml-language-server", "--stdio"],
        root_markers=[],
        check_command="yaml-language-server"
    ),

    # JSON
    ServerConfig(
        id="vscode-json-languageserver",
        extensions=[".json", ".jsonc"],
        command=["vscode-json-languageserver", "--stdio"],
        root_markers=[],
        check_command="vscode-json-languageserver"
    ),

    # Elixir
    ServerConfig(
        id="elixir-ls",
        extensions=[".ex", ".exs"],
        command=["elixir-ls"],
        root_markers=["mix.exs"],
        check_command="elixir-ls"
    ),

    # Haskell
    ServerConfig(
        id="haskell-language-server",
        extensions=[".hs", ".lhs"],
        command=["haskell-language-server-wrapper", "--lsp"],
        root_markers=["stack.yaml", "cabal.project", "*.cabal"],
        check_command="haskell-language-server-wrapper"
    ),

    # Zig
    ServerConfig(
        id="zls",
        extensions=[".zig", ".zon"],
        command=["zls"],
        root_markers=["build.zig", "zls.json"],
        check_command="zls"
    ),

    # Nix
    ServerConfig(
        id="nixd",
        extensions=[".nix"],
        command=["nixd"],
        root_markers=["flake.nix", "default.nix", "shell.nix"],
        check_command="nixd"
    ),

    # OCaml
    ServerConfig(
        id="ocamllsp",
        extensions=[".ml", ".mli"],
        command=["ocamllsp"],
        root_markers=["dune-project", "dune", "*.opam"],
        check_command="ocamllsp"
    ),

    # Gleam
    ServerConfig(
        id="gleam",
        extensions=[".gleam"],
        command=["gleam", "lsp"],
        root_markers=["gleam.toml"],
        check_command="gleam"
    ),

    # Dart
    ServerConfig(
        id="dart",
        extensions=[".dart"],
        command=["dart", "language-server", "--protocol=lsp"],
        root_markers=["pubspec.yaml"],
        check_command="dart"
    ),

    # Vue
    ServerConfig(
        id="vue-language-server",
        extensions=[".vue"],
        command=["vue-language-server", "--stdio"],
        root_markers=["package.json", "vue.config.js"],
        check_command="vue-language-server"
    ),

    # Svelte
    ServerConfig(
        id="svelte-language-server",
        extensions=[".svelte"],
        command=["svelteserver", "--stdio"],
        root_markers=["package.json", "svelte.config.js"],
        check_command="svelteserver"
    ),

    # Astro
    ServerConfig(
        id="astro-ls",
        extensions=[".astro"],
        command=["astro-ls", "--stdio"],
        root_markers=["package.json", "astro.config.mjs"],
        check_command="astro-ls"
    ),
]


def get_server_for_file(file_path: str) -> Optional[ServerConfig]:
    """
    根据文件路径获取对应的语言服务器配置

    Args:
        file_path: 文件路径

    Returns:
        匹配的服务器配置，如果没有匹配返回 None
    """
    for server in SERVERS:
        if server.matches_file(file_path):
            return server
    return None


def get_available_servers() -> List[ServerConfig]:
    """
    获取所有可用的语言服务器

    Returns:
        可用的服务器配置列表
    """
    return [server for server in SERVERS if server.is_available()]


def get_server_by_id(server_id: str) -> Optional[ServerConfig]:
    """
    根据 ID 获取服务器配置

    Args:
        server_id: 服务器 ID

    Returns:
        服务器配置，如果不存在返回 None
    """
    for server in SERVERS:
        if server.id == server_id:
            return server
    return None
