"""
InteractionManager - 统一交互管理器

处理所有需要服务端阻塞等待客户端响应的场景：
- 权限授权 (PERMISSION)
- 用户确认 (CONFIRMATION)
- 用户输入 (INPUT)
- 选择题 (CHOICE)

特性：
- 统一抽象：所有交互类型使用统一的请求/响应模型
- 阻塞等待：服务端可以同步等待客户端响应
- 会话共享：子会话的交互请求路由到顶级会话
- 记忆功能：支持记住用户选择
- 超时处理：自动处理超时情况
"""

import asyncio
import uuid
from enum import Enum
from typing import Dict, Any, Optional, List, Callable, Awaitable, Tuple
from dataclasses import dataclass, field, asdict
from datetime import datetime

from core.logger import log_event, log_info
from core.session_id import SessionIDGenerator


class InteractionType(str, Enum):
    """交互类型"""
    PERMISSION = "permission"      # 权限授权
    CONFIRMATION = "confirmation"  # 用户确认
    INPUT = "input"               # 用户输入
    CHOICE = "choice"             # 选择题
    CLARIFY = "clarify"           # 用户澄清（AskUser）


@dataclass
class InteractionRequest:
    """交互请求"""
    request_id: str                    # 唯一请求 ID
    interaction_type: InteractionType  # 交互类型
    session_id: str                    # 发起请求的会话 ID
    root_session_id: str               # 顶级会话 ID（用于路由）

    # 请求内容
    title: str                         # 标题
    message: str                       # 详细信息

    # 类型特定数据
    metadata: Dict[str, Any] = field(default_factory=dict)

    # 选项（用于 PERMISSION/CHOICE 类型）
    options: List[Dict[str, str]] = field(default_factory=list)

    # 默认值
    default_value: Any = None

    # 超时设置（秒），None 表示不超时
    timeout: Optional[float] = 300.0

    # 时间戳
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "request_id": self.request_id,
            "interaction_type": self.interaction_type.value,
            "session_id": self.session_id,
            "root_session_id": self.root_session_id,
            "title": self.title,
            "message": self.message,
            "metadata": self.metadata,
            "options": self.options,
            "default_value": self.default_value,
            "timeout": self.timeout,
            "created_at": self.created_at,
        }


@dataclass
class InteractionResponse:
    """交互响应"""
    request_id: str                    # 对应的请求 ID

    # 响应结果
    approved: bool = True              # 是否批准/确认
    value: Any = None                  # 用户输入的值

    # 记忆选项（用于权限）
    remember: bool = False             # 是否记住选择
    remember_scope: str = "session"    # 记忆范围: session/pattern/always
    remember_pattern: Optional[str] = None  # 记住的模式（如 "git commit*"）

    # 时间戳
    responded_at: str = field(default_factory=lambda: datetime.now().isoformat())

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "InteractionResponse":
        """从字典创建"""
        return cls(
            request_id=data.get("request_id", ""),
            approved=data.get("approved", False),
            value=data.get("value"),
            remember=data.get("remember", False),
            remember_scope=data.get("remember_scope", "session"),
            remember_pattern=data.get("remember_pattern"),
        )

    @classmethod
    def timeout_response(cls, request_id: str, default_value: Any = None) -> "InteractionResponse":
        """创建超时响应"""
        return cls(
            request_id=request_id,
            approved=False,
            value=default_value,
            remember=False,
        )


# 发送回调类型
SendCallback = Callable[[Dict[str, Any]], Awaitable[None]]


class InteractionManager:
    """
    交互管理器

    统一管理所有需要用户交互的请求：
    - 权限授权
    - 用户确认
    - 用户输入
    - 选择题
    """

    def __init__(self):
        # 待处理的请求: request_id -> (request, future)
        self._pending_requests: Dict[str, Tuple[InteractionRequest, asyncio.Future]] = {}

        # 记忆的选择: cache_key -> response
        # cache_key 格式: "{root_session_id}:{interaction_type}:{pattern}"
        self._remembered_choices: Dict[str, InteractionResponse] = {}

        # WebSocket 发送回调: root_session_id -> send_callback
        self._send_callbacks: Dict[str, SendCallback] = {}

    # ==================== 会话管理 ====================

    def register_session(self, root_session_id: str, send_callback: SendCallback):
        """
        注册会话的发送回调

        Args:
            root_session_id: 顶级会话 ID
            send_callback: 发送消息的回调函数
        """
        self._send_callbacks[root_session_id] = send_callback
        log_event("interaction_session_registered",
            root_session_id=root_session_id
        )

    def unregister_session(self, root_session_id: str):
        """
        注销会话

        Args:
            root_session_id: 顶级会话 ID
        """
        self._send_callbacks.pop(root_session_id, None)

        # 取消该会话的所有待处理请求
        cancelled_count = 0
        for req_id, (req, future) in list(self._pending_requests.items()):
            if req.root_session_id == root_session_id:
                if not future.done():
                    future.cancel()
                del self._pending_requests[req_id]
                cancelled_count += 1

        # 清理该会话的记忆选择
        keys_to_remove = [k for k in self._remembered_choices if k.startswith(f"{root_session_id}:")]
        for key in keys_to_remove:
            del self._remembered_choices[key]

        log_event("interaction_session_unregistered",
            root_session_id=root_session_id,
            cancelled_requests=cancelled_count
        )

    # ==================== 交互请求 ====================

    async def request(
        self,
        interaction_type: InteractionType,
        session_id: str,
        title: str,
        message: str,
        metadata: Optional[Dict[str, Any]] = None,
        options: Optional[List[Dict[str, str]]] = None,
        default_value: Any = None,
        timeout: Optional[float] = None,
        cache_key: Optional[str] = None,
    ) -> InteractionResponse:
        """
        发起交互请求并等待响应

        Args:
            interaction_type: 交互类型
            session_id: 发起请求的会话 ID（可能是子会话）
            title: 标题
            message: 详细信息
            metadata: 元数据
            options: 选项列表
            default_value: 默认值
            timeout: 超时时间（秒），None 表示不超时
            cache_key: 缓存键（用于记忆功能，如果为 None 则不缓存）

        Returns:
            InteractionResponse: 用户响应

        Raises:
            RuntimeError: 没有注册发送回调
            asyncio.CancelledError: 请求被取消
        """
        # 获取顶级会话 ID
        root_session_id = SessionIDGenerator.get_root_id(session_id)

        # 使用新的阶段性日志
        log_event(
            "interaction_start",
            interaction_type=interaction_type.value,
            session_id=session_id,
            title=title,
        )

        # 检查是否有记忆的选择
        if cache_key:
            full_cache_key = f"{root_session_id}:{cache_key}"
            if full_cache_key in self._remembered_choices:
                cached = self._remembered_choices[full_cache_key]
                log_event(
                    "interaction_cached",
                    interaction_type=interaction_type.value,
                    cache_key=full_cache_key,
                    approved=cached.approved,
                )
                return cached

        # 检查是否有发送回调
        send_callback = self._send_callbacks.get(root_session_id)
        if not send_callback:
            log_event(
                "interaction_error",
                message=f"没有注册发送回调: {root_session_id}",
                root_session_id=root_session_id,
            )
            raise RuntimeError(f"No send callback registered for session: {root_session_id}")

        # 创建请求
        request = InteractionRequest(
            request_id=str(uuid.uuid4()),
            interaction_type=interaction_type,
            session_id=session_id,
            root_session_id=root_session_id,
            title=title,
            message=message,
            metadata=metadata or {},
            options=options or [],
            default_value=default_value,
            timeout=timeout,
        )

        # 创建 Future
        future: asyncio.Future = asyncio.get_event_loop().create_future()
        self._pending_requests[request.request_id] = (request, future)

        log_event(
            "interaction_request_created",
            interaction_type=interaction_type.value,
            request_id=request.request_id,
            session_id=session_id,
        )

        # 发送请求到客户端
        try:
            await send_callback({
                "type": "interaction_request",
                "session_id": root_session_id,
                "data": request.to_dict()
            })
            log_event(
                "interaction_waiting",
                interaction_type=interaction_type.value,
                request_id=request.request_id,
            )
        except Exception as e:
            # 发送失败，清理并返回默认拒绝
            self._pending_requests.pop(request.request_id, None)
            log_event(
                "interaction_send_error",
                interaction_type=interaction_type.value,
                request_id=request.request_id,
                error=str(e),
            )
            return InteractionResponse.timeout_response(request.request_id, default_value)

        # 等待响应（timeout=None 表示不超时）
        try:
            if timeout is None:
                response = await future
            else:
                response = await asyncio.wait_for(future, timeout=timeout)

            # 使用新的阶段性日志记录响应
            log_event(
                "interaction_end",
                interaction_type=interaction_type.value,
                request_id=request.request_id,
                approved=response.approved,
                value=response.value,
                remember=response.remember,
            )

            # 处理记忆选项
            if cache_key and response.remember:
                full_cache_key = f"{root_session_id}:{cache_key}"
                self._remembered_choices[full_cache_key] = response
                log_event(
                    "interaction_remembered",
                    interaction_type=interaction_type.value,
                    cache_key=full_cache_key,
                    approved=response.approved,
                )

            return response

        except asyncio.TimeoutError:
            log_event(
                "interaction_timeout",
                interaction_type=interaction_type.value,
                request_id=request.request_id,
                timeout=timeout,
            )
            return InteractionResponse.timeout_response(request.request_id, default_value)

        except asyncio.CancelledError:
            log_event(
                "interaction_cancelled",
                interaction_type=interaction_type.value,
                request_id=request.request_id,
            )
            raise

        finally:
            self._pending_requests.pop(request.request_id, None)

    # ==================== 便捷方法 ====================

    async def request_permission(
        self,
        session_id: str,
        permission: str,
        pattern: str,
        metadata: Optional[Dict[str, Any]] = None,
        timeout: Optional[float] = None,
    ) -> InteractionResponse:
        """
        请求权限授权

        Args:
            session_id: 会话 ID
            permission: 权限类型（如 read, write, bash）
            pattern: 目标模式（如文件路径、命令）
            metadata: 元数据
            timeout: 超时时间（秒），None 表示不超时

        Returns:
            InteractionResponse
        """
        return await self.request(
            interaction_type=InteractionType.PERMISSION,
            session_id=session_id,
            title=f"{permission} 权限请求",
            message=f"Agent 请求 {permission} 权限: {pattern}",
            metadata={
                "permission": permission,
                "pattern": pattern,
                **(metadata or {})
            },
            options=[
                {"value": "allow_once", "label": "允许一次"},
                {"value": "allow_session", "label": "本次会话允许"},
                {"value": "allow_pattern", "label": "允许此类操作"},
                {"value": "deny", "label": "拒绝"}
            ],
            default_value="deny",
            timeout=timeout,
            cache_key=f"permission:{permission}:{pattern}",
        )

    async def request_confirmation(
        self,
        session_id: str,
        title: str,
        message: str,
        metadata: Optional[Dict[str, Any]] = None,
        timeout: float = 60.0,
    ) -> InteractionResponse:
        """
        请求用户确认

        Args:
            session_id: 会话 ID
            title: 标题
            message: 详细信息
            metadata: 元数据
            timeout: 超时时间

        Returns:
            InteractionResponse
        """
        return await self.request(
            interaction_type=InteractionType.CONFIRMATION,
            session_id=session_id,
            title=title,
            message=message,
            metadata=metadata,
            options=[
                {"value": "confirm", "label": "确认"},
                {"value": "cancel", "label": "取消"}
            ],
            default_value="cancel",
            timeout=timeout,
            cache_key=None,  # 确认不缓存
        )

    async def request_input(
        self,
        session_id: str,
        title: str,
        message: str,
        input_type: str = "text",
        placeholder: str = "",
        validation: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None,
        timeout: float = 300.0,
    ) -> InteractionResponse:
        """
        请求用户输入

        Args:
            session_id: 会话 ID
            title: 标题
            message: 详细信息
            input_type: 输入类型（text, password, number）
            placeholder: 占位符
            validation: 验证正则表达式
            metadata: 元数据
            timeout: 超时时间

        Returns:
            InteractionResponse
        """
        return await self.request(
            interaction_type=InteractionType.INPUT,
            session_id=session_id,
            title=title,
            message=message,
            metadata={
                "input_type": input_type,
                "placeholder": placeholder,
                "validation": validation,
                **(metadata or {})
            },
            default_value="",
            timeout=timeout,
            cache_key=None,  # 输入不缓存
        )

    async def request_choice(
        self,
        session_id: str,
        title: str,
        message: str,
        options: List[Dict[str, str]],
        default_value: str = "",
        metadata: Optional[Dict[str, Any]] = None,
        timeout: float = 300.0,
    ) -> InteractionResponse:
        """
        请求用户选择

        Args:
            session_id: 会话 ID
            title: 标题
            message: 详细信息
            options: 选项列表 [{"value": "...", "label": "...", "description": "..."}]
            default_value: 默认值
            metadata: 元数据
            timeout: 超时时间

        Returns:
            InteractionResponse
        """
        return await self.request(
            interaction_type=InteractionType.CHOICE,
            session_id=session_id,
            title=title,
            message=message,
            metadata=metadata,
            options=options,
            default_value=default_value,
            timeout=timeout,
            cache_key=None,  # 选择不缓存
        )

    # ==================== 响应处理 ====================

    def handle_response(self, response_data: Dict[str, Any]) -> bool:
        """
        处理客户端响应

        Args:
            response_data: 响应数据

        Returns:
            bool: 是否成功处理
        """
        request_id = response_data.get("request_id")

        if not request_id or request_id not in self._pending_requests:
            log_event("interaction_response_orphan",
                request_id=request_id
            )
            return False

        request, future = self._pending_requests[request_id]

        if future.done():
            log_event("interaction_response_late",
                request_id=request_id
            )
            return False

        response = InteractionResponse.from_dict(response_data)
        future.set_result(response)

        log_event("interaction_response_handled",
            request_id=request_id,
            approved=response.approved
        )

        return True

    # ==================== 状态查询 ====================

    def get_pending_count(self, root_session_id: Optional[str] = None) -> int:
        """获取待处理请求数量"""
        if root_session_id:
            return sum(1 for req, _ in self._pending_requests.values()
                      if req.root_session_id == root_session_id)
        return len(self._pending_requests)

    def has_pending_requests(self, root_session_id: Optional[str] = None) -> bool:
        """是否有待处理请求"""
        return self.get_pending_count(root_session_id) > 0

    def clear_remembered_choices(self, root_session_id: Optional[str] = None):
        """清除记忆的选择"""
        if root_session_id:
            keys_to_remove = [k for k in self._remembered_choices
                            if k.startswith(f"{root_session_id}:")]
            for key in keys_to_remove:
                del self._remembered_choices[key]
        else:
            self._remembered_choices.clear()


# ==================== 全局实例 ====================

_interaction_manager: Optional[InteractionManager] = None


def get_interaction_manager() -> InteractionManager:
    """获取全局交互管理器"""
    global _interaction_manager
    if _interaction_manager is None:
        _interaction_manager = InteractionManager()
    return _interaction_manager
