"""
Tool Call Recorder for Mid Platform.
[AC-IDMP-15] 工具调用结构化记录

Reference:
- spec/intent-driven-mid-platform/openapi.provider.yaml - ToolCallTrace
- spec/intent-driven-mid-platform/requirements.md AC-IDMP-15
"""

import logging
from collections import defaultdict
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any

from app.models.mid.tool_trace import (
    ToolCallBuilder,
    ToolCallStatus,
    ToolCallTrace,
    ToolType,
)

logger = logging.getLogger(__name__)


@dataclass
class ToolCallStatistics:
    """
    工具调用统计信息
    """
    total_calls: int = 0
    success_calls: int = 0
    timeout_calls: int = 0
    error_calls: int = 0
    rejected_calls: int = 0
    total_duration_ms: int = 0
    avg_duration_ms: float = 0.0
    max_duration_ms: int = 0
    min_duration_ms: int = 0

    def update(self, trace: ToolCallTrace) -> None:
        self.total_calls += 1
        self.total_duration_ms += trace.duration_ms
        self.avg_duration_ms = self.total_duration_ms / self.total_calls
        
        if trace.duration_ms > self.max_duration_ms:
            self.max_duration_ms = trace.duration_ms
        if self.min_duration_ms == 0 or trace.duration_ms < self.min_duration_ms:
            self.min_duration_ms = trace.duration_ms

        if trace.status == ToolCallStatus.OK:
            self.success_calls += 1
        elif trace.status == ToolCallStatus.TIMEOUT:
            self.timeout_calls += 1
        elif trace.status == ToolCallStatus.REJECTED:
            self.rejected_calls += 1
        else:
            self.error_calls += 1


class ToolCallRecorder:
    """
    [AC-IDMP-15] 工具调用记录器
    
    功能：
    1. 记录每次工具调用的完整信息（参数摘要、耗时、状态、错误码）
    2. 支持敏感参数脱敏
    3. 提供统计信息
    
    记录字段：
    - tool_name: 工具名称
    - tool_type: 工具类型 (internal | mcp)
    - registry_version: 注册表版本
    - auth_applied: 是否应用鉴权
    - duration_ms: 调用耗时
    - status: 调用状态 (ok | timeout | error | rejected)
    - error_code: 错误码
    - args_digest: 参数摘要（脱敏）
    - result_digest: 结果摘要
    """

    def __init__(self, max_traces_per_session: int = 100):
        self._max_traces_per_session = max_traces_per_session
        self._traces: dict[str, list[ToolCallTrace]] = defaultdict(list)
        self._statistics: dict[str, ToolCallStatistics] = defaultdict(ToolCallStatistics)

    def start_trace(
        self,
        tool_name: str,
        tool_type: ToolType = ToolType.INTERNAL,
    ) -> ToolCallBuilder:
        """
        开始记录一次工具调用
        
        Args:
            tool_name: 工具名称
            tool_type: 工具类型
            
        Returns:
            ToolCallBuilder: 构建器，用于逐步记录调用信息
        """
        return ToolCallBuilder(
            tool_name=tool_name,
            tool_type=tool_type,
        )

    def record(
        self,
        session_id: str,
        trace: ToolCallTrace,
    ) -> None:
        """
        记录一次工具调用的完整信息
        
        Args:
            session_id: 会话ID
            trace: 工具调用追踪记录
        """
        session_traces = self._traces[session_id]
        session_traces.append(trace)

        if len(session_traces) > self._max_traces_per_session:
            session_traces.pop(0)

        self._statistics[trace.tool_name].update(trace)

        logger.info(
            f"[AC-IDMP-15] Tool call recorded: tool={trace.tool_name}, "
            f"type={trace.tool_type.value}, duration_ms={trace.duration_ms}, "
            f"status={trace.status.value}, session={session_id}, "
            f"args_digest={trace.args_digest}, result_digest={trace.result_digest}"
        )

    def record_success(
        self,
        session_id: str,
        tool_name: str,
        tool_type: ToolType,
        duration_ms: int,
        args: Any = None,
        result: Any = None,
        registry_version: str | None = None,
        auth_applied: bool = False,
    ) -> ToolCallTrace:
        """
        记录成功的工具调用（便捷方法）
        """
        trace = ToolCallTrace(
            tool_name=tool_name,
            tool_type=tool_type,
            duration_ms=duration_ms,
            status=ToolCallStatus.OK,
            registry_version=registry_version,
            auth_applied=auth_applied,
            args_digest=ToolCallTrace.compute_digest(args) if args else None,
            result_digest=ToolCallTrace.compute_digest(result) if result else None,
            arguments=args if isinstance(args, dict) else None,
            result=result,
        )
        self.record(session_id, trace)
        return trace

    def record_timeout(
        self,
        session_id: str,
        tool_name: str,
        tool_type: ToolType,
        duration_ms: int,
        args: Any = None,
        registry_version: str | None = None,
        auth_applied: bool = False,
    ) -> ToolCallTrace:
        """
        记录超时的工具调用（便捷方法）
        """
        trace = ToolCallTrace(
            tool_name=tool_name,
            tool_type=tool_type,
            duration_ms=duration_ms,
            status=ToolCallStatus.TIMEOUT,
            error_code="TIMEOUT",
            registry_version=registry_version,
            auth_applied=auth_applied,
            args_digest=ToolCallTrace.compute_digest(args) if args else None,
            arguments=args if isinstance(args, dict) else None,
        )
        self.record(session_id, trace)
        return trace

    def record_error(
        self,
        session_id: str,
        tool_name: str,
        tool_type: ToolType,
        duration_ms: int,
        error_code: str,
        error_message: str | None = None,
        args: Any = None,
        registry_version: str | None = None,
        auth_applied: bool = False,
    ) -> ToolCallTrace:
        """
        记录错误的工具调用（便捷方法）
        """
        trace = ToolCallTrace(
            tool_name=tool_name,
            tool_type=tool_type,
            duration_ms=duration_ms,
            status=ToolCallStatus.ERROR,
            error_code=error_code,
            registry_version=registry_version,
            auth_applied=auth_applied,
            args_digest=ToolCallTrace.compute_digest(args) if args else None,
            arguments=args if isinstance(args, dict) else None,
        )
        self.record(session_id, trace)
        return trace

    def record_rejected(
        self,
        session_id: str,
        tool_name: str,
        tool_type: ToolType,
        reason: str,
        args: Any = None,
        registry_version: str | None = None,
    ) -> ToolCallTrace:
        """
        记录被拒绝的工具调用（便捷方法）
        """
        trace = ToolCallTrace(
            tool_name=tool_name,
            tool_type=tool_type,
            duration_ms=0,
            status=ToolCallStatus.REJECTED,
            error_code=reason,
            registry_version=registry_version,
            args_digest=ToolCallTrace.compute_digest(args) if args else None,
            arguments=args if isinstance(args, dict) else None,
        )
        self.record(session_id, trace)
        return trace

    def get_traces(self, session_id: str) -> list[ToolCallTrace]:
        """
        获取指定会话的所有工具调用记录
        
        Args:
            session_id: 会话ID
            
        Returns:
            list[ToolCallTrace]: 工具调用记录列表
        """
        return self._traces.get(session_id, [])

    def get_statistics(self, tool_name: str | None = None) -> dict[str, Any]:
        """
        获取工具调用统计信息
        
        Args:
            tool_name: 工具名称（可选，不提供则返回所有统计）
            
        Returns:
            dict: 统计信息
        """
        if tool_name:
            stats = self._statistics.get(tool_name)
            if stats:
                return {
                    "tool_name": tool_name,
                    "total_calls": stats.total_calls,
                    "success_rate": stats.success_calls / stats.total_calls if stats.total_calls > 0 else 0,
                    "timeout_rate": stats.timeout_calls / stats.total_calls if stats.total_calls > 0 else 0,
                    "error_rate": stats.error_calls / stats.total_calls if stats.total_calls > 0 else 0,
                    "avg_duration_ms": stats.avg_duration_ms,
                    "max_duration_ms": stats.max_duration_ms,
                    "min_duration_ms": stats.min_duration_ms,
                }
            return {}

        return {
            name: {
                "total_calls": stats.total_calls,
                "success_rate": stats.success_calls / stats.total_calls if stats.total_calls > 0 else 0,
                "avg_duration_ms": stats.avg_duration_ms,
            }
            for name, stats in self._statistics.items()
        }

    def clear_session(self, session_id: str) -> int:
        """
        清除指定会话的记录
        
        Args:
            session_id: 会话ID
            
        Returns:
            int: 清除的记录数
        """
        if session_id in self._traces:
            count = len(self._traces[session_id])
            del self._traces[session_id]
            return count
        return 0

    def to_trace_info_format(self, session_id: str) -> list[dict[str, Any]]:
        """
        转换为 TraceInfo.tool_calls 格式
        
        用于输出到 DialogueResponse.trace.tool_calls
        
        Args:
            session_id: 会话ID
            
        Returns:
            list[dict]: 符合 OpenAPI 格式的工具调用列表
        """
        traces = self.get_traces(session_id)
        return [trace.to_dict() for trace in traces]


_recorder: ToolCallRecorder | None = None


def get_tool_call_recorder() -> ToolCallRecorder:
    """获取全局工具调用记录器实例"""
    global _recorder
    if _recorder is None:
        _recorder = ToolCallRecorder()
    return _recorder
