"""
Performance Event Injector
=========================

独立性能监控事件类：从 config 的 callback.performance_monitor 收集指标，
生成性能事件。由上层应用组合调用并与其他事件流合并处理。
仅 benchmark 模式，始终上报，无开关控制。
"""

from __future__ import annotations

import logging
import time
from typing import Any, AsyncGenerator, Dict, List

logger = logging.getLogger(__name__)

# 事件类型常量，供上层识别
EVENT_TYPE_PERFORMANCE = "performance"


class PerformanceEventInjector:
    """
    性能事件注入器：从 agent config 的 callback 中读取 performance_monitor，
    生成单一性能事件（benchmark 完整报告）。始终上报，由上层组合调用。
    """

    async def inject_performance_events(
        self, config: Dict[str, Any]
    ) -> AsyncGenerator[Dict[str, Any], None]:
        """
        从 config.callbacks[0].performance_monitor 收集指标，yield 一条性能事件。
        无 callback 或无 performance_monitor 时不 yield。

        输出结构（供上层与其它事件流合并）：
            event_type: "performance"
            data: { mode, total_tool_calls, tool_call_chain, ... }
            timestamp: float
        """
        callbacks = config.get("callbacks", [])
        if not callbacks:
            return

        callback = callbacks[0]
        if not hasattr(callback, "performance_monitor") or not callback.performance_monitor:
            return

        monitor = callback.performance_monitor
        metrics = monitor.calculate_metrics()
        degradation_stats: Any = None
        try:
            if hasattr(monitor, "get_degradation_stats"):
                degradation_stats = monitor.get_degradation_stats()
        except Exception as e:
            logger.debug("获取退化统计失败（忽略）：%s", e)

        mode = "benchmark"
        data: Dict[str, Any] = {
            "mode": mode,
            "total_tool_calls": metrics.total_tool_calls,
            "tool_call_chain": metrics.tool_call_chain,
            "total_latency_ms": metrics.total_latency_ms,
            "unique_tools": list(metrics.unique_tools),
            "total_llm_calls": metrics.total_llm_calls,
            "llm_call_chain": metrics.llm_call_chain,
            "total_llm_latency_ms": metrics.total_llm_latency_ms,
            "complete_call_chain": metrics.complete_call_chain,
            "strategy": (
                monitor.strategy.value if monitor.strategy else "unknown"
            ),
            "strategy_explanation": monitor.strategy_explanation or "",
            "average_tool_latency_ms": (
                round(metrics.total_latency_ms / metrics.total_tool_calls, 2)
                if metrics.total_tool_calls > 0
                else 0
            ),
            "average_llm_latency_ms": (
                round(metrics.total_llm_latency_ms / metrics.total_llm_calls, 2)
                if metrics.total_llm_calls > 0
                else 0
            ),
            "context_tokens": metrics.context_tokens,
            "has_warning": metrics.has_warning(),
            "warnings": metrics.get_warnings(),
            "optimization_suggestions": self._generate_optimization_suggestions(
                metrics, monitor
            ),
            "tool_call_degradation": degradation_stats,
            "tool_details": [
                {
                    "tool_name": record.tool_name,
                    "cost_time_ms": record.cost_time_ms,
                    "output_length": record.output_length,
                    "error": record.error,
                }
                for record in monitor.records
            ],
            "llm_details": [
                {
                    "model_name": record.model_name,
                    "cost_time_ms": record.cost_time_ms,
                    "prompt_length": record.prompt_length,
                    "output_length": record.output_length,
                    "error": record.error,
                }
                for record in monitor.llm_records
            ],
            "timestamp": time.time(),
        }

        yield {
            "event_type": EVENT_TYPE_PERFORMANCE,
            "data": data,
            "timestamp": data["timestamp"],
        }

    def _generate_optimization_suggestions(
        self, metrics: Any, monitor: Any
    ) -> List[str]:
        """根据 metrics 生成优化建议列表。

        阈值与 PerformanceMetrics 一致（均为「单次调用平均」或「次数」）：
        - TOOL_COUNT_THRESHOLD: 15（单次 run 工具调用次数）
        - TOOL_AVG_LATENCY_THRESHOLD_MS: 2000（单次工具调用平均宜 <2s）
        - LLM_AVG_LATENCY_THRESHOLD_MS: 3000（单次 LLM 调用平均宜 <3s，每个 LLM 瓶颈）
        """
        suggestions: List[str] = []
        if not metrics.has_warning():
            return suggestions
        threshold_tools = getattr(metrics, "TOOL_COUNT_THRESHOLD", 15)
        threshold_tool_avg = getattr(metrics, "TOOL_AVG_LATENCY_THRESHOLD_MS", 2000)
        threshold_llm_avg = getattr(metrics, "LLM_AVG_LATENCY_THRESHOLD_MS", 3000)
        if metrics.total_tool_calls > threshold_tools:
            suggestions.append("考虑使用混合策略（先摘要后定向）减少工具调用次数")
            suggestions.append("避免循环调用小工具，优先使用一次性加载")
        if metrics.total_tool_calls > 0:
            avg_tool = metrics.total_latency_ms / metrics.total_tool_calls
            if avg_tool > threshold_tool_avg:
                suggestions.append("优化工具实现或检查网络/IO，降低单次工具平均耗时")
                suggestions.append("使用缓存机制避免重复调用")
        if metrics.total_llm_calls > 0:
            avg_llm = metrics.total_llm_latency_ms / metrics.total_llm_calls
            if avg_llm > threshold_llm_avg:
                suggestions.append("单次 LLM 调用平均过慢，建议检查模型选型或上下文大小")
        return suggestions


def create_performance_event_injector() -> PerformanceEventInjector:
    """工厂函数：创建 PerformanceEventInjector 实例。"""
    return PerformanceEventInjector()


__all__ = [
    "EVENT_TYPE_PERFORMANCE",
    "PerformanceEventInjector",
    "create_performance_event_injector",
]
