"""
Roneia Protocol - 云端-本地通信协议

定义 WebSocket JSON-RPC 风格的通信协议。

消息类型:
- task: 客户端发送任务请求
- skill_call: 服务器请求客户端执行本地 Skill
- skill_result: 客户端返回 Skill 执行结果
- response: 服务器返回任务最终响应
- error: 错误消息
- heartbeat: 心跳包
- auth: 认证消息
"""

import json
import uuid
from dataclasses import dataclass, field, asdict
from datetime import datetime
from enum import Enum
from typing import Any, Dict, List, Optional, Union


class MessageType(Enum):
    """消息类型"""
    # 任务相关
    TASK_REQUEST = "task.request"           # 客户端 → 服务器: 发送任务
    TASK_RESPONSE = "task.response"         # 服务器 → 客户端: 返回最终结果
    TASK_PROGRESS = "task.progress"         # 服务器 → 客户端: 任务进度更新
    TASK_CANCEL = "task.cancel"             # 客户端 → 服务器: 取消任务

    # Skill 调用相关
    SKILL_CALL = "skill.call"               # 服务器 → 客户端: 请求执行本地 Skill
    SKILL_RESULT = "skill.result"           # 客户端 → 服务器: 返回 Skill 执行结果
    SKILL_LIST = "skill.list"               # 客户端 → 服务器: 上报本地 Skill 列表

    # Skill 注册中心相关（新增）
    SKILL_REGISTRY_LIST = "skill.registry.list"         # 客户端 → 服务器: 请求 Skill 列表
    SKILL_REGISTRY_RESPONSE = "skill.registry.response" # 服务器 → 客户端: 返回 Skill 列表
    SKILL_STATUS_UPDATE = "skill.status.update"         # 客户端 → 服务器: 同步已启用 Skill

    # 权限相关
    PERMISSION_REQUEST = "permission.request"   # 服务器 → 客户端: 请求权限确认
    PERMISSION_RESPONSE = "permission.response" # 客户端 → 服务器: 权限确认结果

    # 连接管理
    AUTH_REQUEST = "auth.request"           # 客户端 → 服务器: 认证请求
    AUTH_RESPONSE = "auth.response"         # 服务器 → 客户端: 认证结果
    HEARTBEAT = "heartbeat"                 # 双向: 心跳包
    PING = "ping"                           # 客户端 → 服务器: Ping
    PONG = "pong"                           # 服务器 → 客户端: Pong

    # 语音配置
    VOICE_CONFIG_REQUEST = "voice.config.request"    # 客户端 → 服务器: 请求语音配置
    VOICE_CONFIG_RESPONSE = "voice.config.response"  # 服务器 → 客户端: 返回语音配置

    # 搜索配置
    SEARCH_CONFIG_REQUEST = "search.config.request"    # 客户端 → 服务器: 请求搜索配置
    SEARCH_CONFIG_RESPONSE = "search.config.response"  # 服务器 → 客户端: 返回搜索配置

    # 人设管理
    PERSONA_GET = "persona.get"                # 客户端 → 服务器: 获取当前人设
    PERSONA_UPDATE = "persona.update"          # 客户端 → 服务器: 更新人设
    PERSONA_RESPONSE = "persona.response"      # 服务器 → 客户端: 人设响应

    # 系统消息
    ERROR = "error"                         # 错误消息
    NOTIFICATION = "notification"           # 通知消息


class ErrorCode(Enum):
    """错误码"""
    # 通用错误 (1xxx)
    UNKNOWN_ERROR = 1000
    INVALID_MESSAGE = 1001
    INVALID_METHOD = 1002
    INVALID_PARAMS = 1003

    # 认证错误 (2xxx)
    AUTH_REQUIRED = 2001
    AUTH_FAILED = 2002
    AUTH_EXPIRED = 2003
    INVALID_TOKEN = 2004

    # 任务错误 (3xxx)
    TASK_NOT_FOUND = 3001
    TASK_TIMEOUT = 3002
    TASK_CANCELLED = 3003
    TASK_FAILED = 3004

    # Skill 错误 (4xxx)
    SKILL_NOT_FOUND = 4001
    SKILL_CALL_FAILED = 4002
    SKILL_TIMEOUT = 4003
    PERMISSION_DENIED = 4004

    # 连接错误 (5xxx)
    CONNECTION_LOST = 5001
    HEARTBEAT_TIMEOUT = 5002


@dataclass
class Message:
    """
    通信消息基类

    基于 JSON-RPC 2.0 风格，但进行了简化和扩展。
    """
    type: MessageType
    """消息类型"""

    payload: Dict[str, Any] = field(default_factory=dict)
    """消息负载"""

    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    """消息ID，用于请求-响应匹配"""

    timestamp: str = field(default_factory=lambda: datetime.utcnow().isoformat())
    """消息时间戳"""

    correlation_id: Optional[str] = None
    """关联消息ID（用于响应消息关联请求消息）"""

    metadata: Dict[str, Any] = field(default_factory=dict)
    """额外元数据"""

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "type": self.type.value,
            "payload": self.payload,
            "id": self.id,
            "timestamp": self.timestamp,
            "correlation_id": self.correlation_id,
            "metadata": self.metadata,
        }

    def to_json(self) -> str:
        """转换为 JSON 字符串"""
        return json.dumps(self.to_dict(), ensure_ascii=False)

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Message":
        """从字典创建"""
        return cls(
            type=MessageType(data.get("type", "")),
            payload=data.get("payload", {}),
            id=data.get("id", str(uuid.uuid4())),
            timestamp=data.get("timestamp", datetime.utcnow().isoformat()),
            correlation_id=data.get("correlation_id"),
            metadata=data.get("metadata", {}),
        )

    @classmethod
    def from_json(cls, json_str: str) -> "Message":
        """从 JSON 字符串创建"""
        return cls.from_dict(json.loads(json_str))


# ============================================================================
# 便捷消息构造函数
# ============================================================================

def create_task_request(
    text: str,
    session_id: Optional[str] = None,
    context: Optional[Dict[str, Any]] = None,
) -> Message:
    """
    创建任务请求消息

    Args:
        text: 用户输入的任务文本
        session_id: 会话ID（可选）
        context: 上下文信息（可选）

    Returns:
        任务请求消息
    """
    return Message(
        type=MessageType.TASK_REQUEST,
        payload={
            "text": text,
            "session_id": session_id,
            "context": context or {},
        },
    )


def create_task_response(
    text: str,
    correlation_id: str,
    success: bool = True,
    error: Optional[Dict[str, Any]] = None,
) -> Message:
    """
    创建任务响应消息

    Args:
        text: 响应文本
        correlation_id: 关联的请求消息ID
        success: 是否成功
        error: 错误信息（可选）

    Returns:
        任务响应消息
    """
    return Message(
        type=MessageType.TASK_RESPONSE,
        payload={
            "text": text,
            "success": success,
            "error": error,
        },
        correlation_id=correlation_id,
    )


def create_skill_call(
    skill_name: str,
    tool_name: str,
    arguments: Dict[str, Any],
    permission: Optional[str] = None,
    purpose: Optional[str] = None,
) -> Message:
    """
    创建 Skill 调用请求消息

    Args:
        skill_name: Skill 名称
        tool_name: 工具名称
        arguments: 调用参数
        permission: 所需权限（可选）
        purpose: 操作目的描述（可选）

    Returns:
        Skill 调用请求消息
    """
    return Message(
        type=MessageType.SKILL_CALL,
        payload={
            "skill": skill_name,
            "tool": tool_name,
            "args": arguments,
            "permission": permission,
            "purpose": purpose,
        },
    )


def create_skill_result(
    correlation_id: str,
    success: bool,
    data: Any = None,
    error: Optional[Dict[str, Any]] = None,
) -> Message:
    """
    创建 Skill 执行结果消息

    Args:
        correlation_id: 关联的调用请求消息ID
        success: 是否成功
        data: 执行结果数据
        error: 错误信息（可选）

    Returns:
        Skill 执行结果消息
    """
    return Message(
        type=MessageType.SKILL_RESULT,
        payload={
            "success": success,
            "data": data,
            "error": error,
        },
        correlation_id=correlation_id,
    )


def create_skill_list(skills: List[Dict[str, Any]]) -> Message:
    """
    创建 Skill 列表消息

    Args:
        skills: Skill 列表，每个包含 name, version, tools 等信息

    Returns:
        Skill 列表消息
    """
    return Message(
        type=MessageType.SKILL_LIST,
        payload={
            "skills": skills,
        },
    )


def create_permission_request(
    skill_name: str,
    permission: str,
    reason: str,
    purpose: str,
) -> Message:
    """
    创建权限请求消息

    Args:
        skill_name: Skill 名称
        permission: 权限字符串
        reason: 请求原因
        purpose: 操作目的

    Returns:
        权限请求消息
    """
    return Message(
        type=MessageType.PERMISSION_REQUEST,
        payload={
            "skill_name": skill_name,
            "permission": permission,
            "reason": reason,
            "purpose": purpose,
        },
    )


def create_permission_response(
    correlation_id: str,
    granted: bool,
) -> Message:
    """
    创建权限响应消息

    Args:
        correlation_id: 关联的请求消息ID
        granted: 是否授权

    Returns:
        权限响应消息
    """
    return Message(
        type=MessageType.PERMISSION_RESPONSE,
        payload={
            "granted": granted,
        },
        correlation_id=correlation_id,
    )


def create_auth_request(token: str, client_info: Optional[Dict[str, Any]] = None) -> Message:
    """
    创建认证请求消息

    Args:
        token: 认证令牌
        client_info: 客户端信息（可选）

    Returns:
        认证请求消息
    """
    return Message(
        type=MessageType.AUTH_REQUEST,
        payload={
            "token": token,
            "client_info": client_info or {},
        },
    )


def create_auth_response(
    correlation_id: str,
    success: bool,
    client_id: Optional[str] = None,
    error: Optional[str] = None,
) -> Message:
    """
    创建认证响应消息

    Args:
        correlation_id: 关联的请求消息ID
        success: 是否成功
        client_id: 分配的客户端ID（成功时）
        error: 错误信息（失败时）

    Returns:
        认证响应消息
    """
    return Message(
        type=MessageType.AUTH_RESPONSE,
        payload={
            "success": success,
            "client_id": client_id,
            "error": error,
        },
        correlation_id=correlation_id,
    )


def create_heartbeat() -> Message:
    """创建心跳消息"""
    return Message(
        type=MessageType.HEARTBEAT,
        payload={
            "timestamp": datetime.utcnow().isoformat(),
        },
    )


def create_ping() -> Message:
    """创建 Ping 消息"""
    return Message(
        type=MessageType.PING,
        payload={},
    )


def create_pong(correlation_id: str) -> Message:
    """创建 Pong 消息"""
    return Message(
        type=MessageType.PONG,
        payload={},
        correlation_id=correlation_id,
    )


def create_error(
    code: ErrorCode,
    message: str,
    details: Optional[Dict[str, Any]] = None,
    correlation_id: Optional[str] = None,
) -> Message:
    """
    创建错误消息

    Args:
        code: 错误码
        message: 错误消息
        details: 错误详情（可选）
        correlation_id: 关联的请求消息ID（可选）

    Returns:
        错误消息
    """
    return Message(
        type=MessageType.ERROR,
        payload={
            "code": code.value,
            "message": message,
            "details": details or {},
        },
        correlation_id=correlation_id,
    )


def create_notification(
    notification_type: str,
    data: Dict[str, Any],
) -> Message:
    """
    创建通知消息

    Args:
        notification_type: 通知类型
        data: 通知数据

    Returns:
        通知消息
    """
    return Message(
        type=MessageType.NOTIFICATION,
        payload={
            "notification_type": notification_type,
            "data": data,
        },
    )


def create_task_progress(
    correlation_id: str,
    progress: float,
    status: str,
    message: Optional[str] = None,
) -> Message:
    """
    创建任务进度消息

    Args:
        correlation_id: 关联的任务请求消息ID
        progress: 进度（0-100）
        status: 状态描述
        message: 详细消息（可选）

    Returns:
        任务进度消息
    """
    return Message(
        type=MessageType.TASK_PROGRESS,
        payload={
            "progress": progress,
            "status": status,
            "message": message,
        },
        correlation_id=correlation_id,
    )


def create_skill_registry_list_request() -> Message:
    """
    创建 Skill 注册中心列表请求消息

    Returns:
        Skill 列表请求消息
    """
    return Message(
        type=MessageType.SKILL_REGISTRY_LIST,
        payload={},
    )


def create_skill_registry_response(
    correlation_id: str,
    skills: List[Dict[str, Any]],
) -> Message:
    """
    创建 Skill 注册中心列表响应消息

    Args:
        correlation_id: 关联的请求消息ID
        skills: Skill 列表

    Returns:
        Skill 列表响应消息
    """
    return Message(
        type=MessageType.SKILL_REGISTRY_RESPONSE,
        payload={
            "skills": skills,
        },
        correlation_id=correlation_id,
    )


def create_skill_status_update(
    enabled_skills: List[str],
) -> Message:
    """
    创建 Skill 状态更新消息

    Args:
        enabled_skills: 已启用的 Skill 名称列表

    Returns:
        Skill 状态更新消息
    """
    return Message(
        type=MessageType.SKILL_STATUS_UPDATE,
        payload={
            "enabled_skills": enabled_skills,
        },
    )


def create_voice_config_request() -> Message:
    """创建语音配置请求消息（Client → Server）"""
    return Message(
        type=MessageType.VOICE_CONFIG_REQUEST,
        payload={},
    )


def create_voice_config_response(
    correlation_id: str,
    config: Dict[str, Any],
) -> Message:
    """
    创建语音配置响应消息（Server → Client）

    Args:
        correlation_id: 关联的请求消息ID
        config: 语音配置字典

    Returns:
        语音配置响应消息
    """
    return Message(
        type=MessageType.VOICE_CONFIG_RESPONSE,
        payload={
            "config": config,
        },
        correlation_id=correlation_id,
    )


def create_search_config_request() -> Message:
    """创建搜索配置请求消息（Client → Server）"""
    return Message(
        type=MessageType.SEARCH_CONFIG_REQUEST,
        payload={},
    )


def create_search_config_response(
    correlation_id: str,
    config: Dict[str, Any],
) -> Message:
    """
    创建搜索配置响应消息（Server → Client）

    Args:
        correlation_id: 关联的请求消息ID
        config: 搜索配置字典

    Returns:
        搜索配置响应消息
    """
    return Message(
        type=MessageType.SEARCH_CONFIG_RESPONSE,
        payload={
            "config": config,
        },
        correlation_id=correlation_id,
    )


def create_persona_get_request() -> Message:
    """创建人设获取请求消息（Client → Server）"""
    return Message(
        type=MessageType.PERSONA_GET,
        payload={},
    )


def create_persona_update_request(content: str = "", reset: bool = False) -> Message:
    """
    创建人设更新请求消息（Client → Server）

    Args:
        content: 新的人设内容
        reset: 是否恢复默认人设
    """
    return Message(
        type=MessageType.PERSONA_UPDATE,
        payload={
            "content": content,
            "reset": reset,
        },
    )


def create_persona_response(
    correlation_id: str,
    content: str,
    success: bool = True,
) -> Message:
    """
    创建人设响应消息（Server → Client）

    Args:
        correlation_id: 关联的请求消息ID
        content: 人设内容
        success: 是否成功
    """
    return Message(
        type=MessageType.PERSONA_RESPONSE,
        payload={
            "content": content,
            "success": success,
        },
        correlation_id=correlation_id,
    )


# ============================================================================
# 消息验证
# ============================================================================

def validate_message(data: Dict[str, Any]) -> tuple[bool, Optional[str]]:
    """
    验证消息格式

    Args:
        data: 消息字典

    Returns:
        (是否有效, 错误信息)
    """
    if not isinstance(data, dict):
        return False, "Message must be a dict"

    if "type" not in data:
        return False, "Missing 'type' field"

    try:
        MessageType(data["type"])
    except ValueError:
        return False, f"Invalid message type: {data['type']}"

    if "payload" in data and not isinstance(data["payload"], dict):
        return False, "'payload' must be a dict"

    return True, None
