"""
LSP 协议类型定义

定义 Language Server Protocol 相关的数据类型，
参考 LSP 规范: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
"""

from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Union
from enum import IntEnum


class SymbolKind(IntEnum):
    """符号类型枚举"""
    File = 1
    Module = 2
    Namespace = 3
    Package = 4
    Class = 5
    Method = 6
    Property = 7
    Field = 8
    Constructor = 9
    Enum = 10
    Interface = 11
    Function = 12
    Variable = 13
    Constant = 14
    String = 15
    Number = 16
    Boolean = 17
    Array = 18
    Object = 19
    Key = 20
    Null = 21
    EnumMember = 22
    Struct = 23
    Event = 24
    Operator = 25
    TypeParameter = 26


SYMBOL_KIND_NAMES = {
    SymbolKind.File: "File",
    SymbolKind.Module: "Module",
    SymbolKind.Namespace: "Namespace",
    SymbolKind.Package: "Package",
    SymbolKind.Class: "Class",
    SymbolKind.Method: "Method",
    SymbolKind.Property: "Property",
    SymbolKind.Field: "Field",
    SymbolKind.Constructor: "Constructor",
    SymbolKind.Enum: "Enum",
    SymbolKind.Interface: "Interface",
    SymbolKind.Function: "Function",
    SymbolKind.Variable: "Variable",
    SymbolKind.Constant: "Constant",
    SymbolKind.String: "String",
    SymbolKind.Number: "Number",
    SymbolKind.Boolean: "Boolean",
    SymbolKind.Array: "Array",
    SymbolKind.Object: "Object",
    SymbolKind.Key: "Key",
    SymbolKind.Null: "Null",
    SymbolKind.EnumMember: "EnumMember",
    SymbolKind.Struct: "Struct",
    SymbolKind.Event: "Event",
    SymbolKind.Operator: "Operator",
    SymbolKind.TypeParameter: "TypeParameter",
}


@dataclass
class Position:
    """
    文本文档中的位置

    Attributes:
        line: 行号（0-based）
        character: 字符偏移（0-based）
    """
    line: int
    character: int

    def to_dict(self) -> Dict[str, int]:
        return {"line": self.line, "character": self.character}

    @classmethod
    def from_dict(cls, data: Dict[str, int]) -> "Position":
        return cls(line=data["line"], character=data["character"])


@dataclass
class Range:
    """
    文本文档中的范围

    Attributes:
        start: 起始位置
        end: 结束位置
    """
    start: Position
    end: Position

    def to_dict(self) -> Dict[str, Any]:
        return {"start": self.start.to_dict(), "end": self.end.to_dict()}

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Range":
        return cls(
            start=Position.from_dict(data["start"]),
            end=Position.from_dict(data["end"])
        )


@dataclass
class Location:
    """
    代码位置，包含 URI 和范围

    Attributes:
        uri: 文件 URI
        range: 位置范围
    """
    uri: str
    range: Range

    def to_dict(self) -> Dict[str, Any]:
        return {"uri": self.uri, "range": self.range.to_dict()}

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Location":
        return cls(
            uri=data["uri"],
            range=Range.from_dict(data["range"])
        )

    def to_file_path(self) -> str:
        """将 URI 转换为文件路径"""
        if self.uri.startswith("file://"):
            return self.uri[7:]
        return self.uri


@dataclass
class LocationLink:
    """
    位置链接，包含原始位置和目标位置
    """
    originSelectionRange: Optional[Range]
    targetUri: str
    targetRange: Range
    targetSelectionRange: Range

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "LocationLink":
        return cls(
            originSelectionRange=Range.from_dict(data["originSelectionRange"]) if data.get("originSelectionRange") else None,
            targetUri=data["targetUri"],
            targetRange=Range.from_dict(data["targetRange"]),
            targetSelectionRange=Range.from_dict(data["targetSelectionRange"])
        )


@dataclass
class TextDocumentIdentifier:
    """
    文本文档标识符

    Attributes:
        uri: 文档 URI
    """
    uri: str

    def to_dict(self) -> Dict[str, str]:
        return {"uri": self.uri}


@dataclass
class TextDocumentPositionParams:
    """
    文本文档位置参数，用于定义/引用等请求
    """
    textDocument: TextDocumentIdentifier
    position: Position

    def to_dict(self) -> Dict[str, Any]:
        return {
            "textDocument": self.textDocument.to_dict(),
            "position": self.position.to_dict()
        }


@dataclass
class DocumentSymbol:
    """
    文档符号
    """
    name: str
    kind: SymbolKind
    range: Range
    selectionRange: Range
    detail: Optional[str] = None
    children: List["DocumentSymbol"] = field(default_factory=list)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "DocumentSymbol":
        children = [cls.from_dict(c) for c in data.get("children", [])]
        return cls(
            name=data["name"],
            kind=SymbolKind(data["kind"]),
            range=Range.from_dict(data["range"]),
            selectionRange=Range.from_dict(data["selectionRange"]),
            detail=data.get("detail"),
            children=children
        )

    def get_kind_name(self) -> str:
        return SYMBOL_KIND_NAMES.get(self.kind, "Unknown")


@dataclass
class SymbolInformation:
    """
    符号信息（用于工作区符号）
    """
    name: str
    kind: SymbolKind
    location: Location
    containerName: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "SymbolInformation":
        return cls(
            name=data["name"],
            kind=SymbolKind(data["kind"]),
            location=Location.from_dict(data["location"]),
            containerName=data.get("containerName")
        )

    def get_kind_name(self) -> str:
        return SYMBOL_KIND_NAMES.get(self.kind, "Unknown")


@dataclass
class Hover:
    """
    悬停信息
    """
    contents: Union[str, Dict[str, str], List[Union[str, Dict[str, str]]]]
    range: Optional[Range] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Hover":
        contents = data["contents"]
        range_data = data.get("range")
        return cls(
            contents=contents,
            range=Range.from_dict(range_data) if range_data else None
        )

    def get_text(self) -> str:
        """提取悬停文本内容"""
        if isinstance(self.contents, str):
            return self.contents
        elif isinstance(self.contents, dict):
            return self.contents.get("value", str(self.contents))
        elif isinstance(self.contents, list):
            texts = []
            for item in self.contents:
                if isinstance(item, str):
                    texts.append(item)
                elif isinstance(item, dict):
                    texts.append(item.get("value", str(item)))
            return "\n".join(texts)
        return str(self.contents)


@dataclass
class CallHierarchyItem:
    """
    调用层次项
    """
    name: str
    kind: SymbolKind
    uri: str
    range: Range
    selectionRange: Range
    detail: Optional[str] = None
    data: Optional[Any] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "CallHierarchyItem":
        return cls(
            name=data["name"],
            kind=SymbolKind(data["kind"]),
            uri=data["uri"],
            range=Range.from_dict(data["range"]),
            selectionRange=Range.from_dict(data["selectionRange"]),
            detail=data.get("detail"),
            data=data.get("data")
        )

    def to_dict(self) -> Dict[str, Any]:
        result = {
            "name": self.name,
            "kind": self.kind,
            "uri": self.uri,
            "range": self.range.to_dict(),
            "selectionRange": self.selectionRange.to_dict(),
        }
        if self.detail:
            result["detail"] = self.detail
        if self.data:
            result["data"] = self.data
        return result


@dataclass
class CallHierarchyIncomingCall:
    """
    调用层次传入调用
    """
    from_: CallHierarchyItem
    fromRanges: List[Range]

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "CallHierarchyIncomingCall":
        return cls(
            from_=CallHierarchyItem.from_dict(data["from"]),
            fromRanges=[Range.from_dict(r) for r in data["fromRanges"]]
        )


@dataclass
class CallHierarchyOutgoingCall:
    """
    调用层次传出调用
    """
    to: CallHierarchyItem
    fromRanges: List[Range]

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "CallHierarchyOutgoingCall":
        return cls(
            to=CallHierarchyItem.from_dict(data["to"]),
            fromRanges=[Range.from_dict(r) for r in data["fromRanges"]]
        )


class DiagnosticSeverity(IntEnum):
    """诊断严重程度"""
    Error = 1
    Warning = 2
    Information = 3
    Hint = 4


@dataclass
class Diagnostic:
    """
    诊断信息
    """
    range: Range
    message: str
    severity: Optional[DiagnosticSeverity] = None
    code: Optional[Union[int, str]] = None
    source: Optional[str] = None

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Diagnostic":
        severity = None
        if "severity" in data:
            severity = DiagnosticSeverity(data["severity"])
        return cls(
            range=Range.from_dict(data["range"]),
            message=data["message"],
            severity=severity,
            code=data.get("code"),
            source=data.get("source")
        )

    def get_severity_name(self) -> str:
        if self.severity is None:
            return "Unknown"
        return {
            DiagnosticSeverity.Error: "Error",
            DiagnosticSeverity.Warning: "Warning",
            DiagnosticSeverity.Information: "Info",
            DiagnosticSeverity.Hint: "Hint",
        }.get(self.severity, "Unknown")


# JSON-RPC 消息类型
@dataclass
class JsonRpcRequest:
    """JSON-RPC 请求"""
    id: Union[int, str]
    method: str
    params: Optional[Any] = None
    jsonrpc: str = "2.0"

    def to_dict(self) -> Dict[str, Any]:
        result = {
            "jsonrpc": self.jsonrpc,
            "id": self.id,
            "method": self.method
        }
        if self.params is not None:
            result["params"] = self.params
        return result


@dataclass
class JsonRpcResponse:
    """JSON-RPC 响应"""
    id: Union[int, str, None] = None
    result: Optional[Any] = None
    error: Optional[Dict[str, Any]] = None
    jsonrpc: str = "2.0"

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "JsonRpcResponse":
        return cls(
            id=data.get("id"),
            result=data.get("result"),
            error=data.get("error")
        )


@dataclass
class JsonRpcNotification:
    """JSON-RPC 通知（无 id）"""
    method: str
    params: Optional[Any] = None
    jsonrpc: str = "2.0"

    def to_dict(self) -> Dict[str, Any]:
        result = {
            "jsonrpc": self.jsonrpc,
            "method": self.method
        }
        if self.params is not None:
            result["params"] = self.params
        return result
