"""OrganizationContext - 组织上下文，管理 AgentProfile 与能力矩阵"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field

logger = logging.getLogger(__name__)


@dataclass
class AgentProfile:
    """Agent 档案 - 描述组织中一个 Agent 的能力与状态"""

    name: str
    agent_type: str  # "react", "rewoo", "plan_exec", "reflexion", "direct"
    capabilities: list[str]  # capability tag strings
    skills: list[str]  # skill names
    current_load: int = 0  # number of active tasks
    max_concurrency: int = 1
    availability: bool = True
    specializations: list[str] = field(default_factory=list)
    model: str = "default"
    execution_mode: str = "react"


class OrganizationContext:
    """组织上下文 - 管理 Agent 档案与能力矩阵，支持基于能力的 Agent 发现"""

    def __init__(self) -> None:
        self._agents: dict[str, AgentProfile] = {}
        self._capability_matrix: dict[str, list[str]] = {}  # capability -> [agent_names]

    def register_agent(self, profile: AgentProfile) -> None:
        """注册 Agent 档案"""
        self._agents[profile.name] = profile
        # 更新能力矩阵
        for cap in profile.capabilities:
            cap_lower = cap.lower()
            if cap_lower not in self._capability_matrix:
                self._capability_matrix[cap_lower] = []
            if profile.name not in self._capability_matrix[cap_lower]:
                self._capability_matrix[cap_lower].append(profile.name)
        logger.info(f"Agent profile '{profile.name}' registered")

    def unregister_agent(self, name: str) -> None:
        """注销 Agent 档案"""
        profile = self._agents.pop(name, None)
        if profile is None:
            return
        # 清理能力矩阵
        for cap in profile.capabilities:
            cap_lower = cap.lower()
            if cap_lower in self._capability_matrix:
                self._capability_matrix[cap_lower] = [
                    n for n in self._capability_matrix[cap_lower] if n != name
                ]
                if not self._capability_matrix[cap_lower]:
                    del self._capability_matrix[cap_lower]
        logger.info(f"Agent profile '{name}' unregistered")

    def get_agent_profile(self, name: str) -> AgentProfile | None:
        """获取 Agent 档案"""
        return self._agents.get(name)

    def list_agents(self) -> list[AgentProfile]:
        """列出所有 Agent 档案"""
        return list(self._agents.values())

    def find_best_agent(
        self,
        required_capabilities: list[str],
        exclude: list[str] | None = None,
    ) -> AgentProfile | None:
        """根据能力需求找到最佳 Agent

        逻辑：
        1. 找到拥有所有所需能力的 Agent
        2. 在匹配的 Agent 中，优先选择 current_load 较低的
        3. 排除 exclude 列表中的 Agent
        4. 排除不可用的 Agent
        5. 没有匹配则返回 None
        """
        exclude_set = set(exclude or [])

        # 对每个所需能力，查找拥有该能力的 Agent 名称集合
        candidate_names: set[str] | None = None
        for cap in required_capabilities:
            cap_lower = cap.lower()
            agents_with_cap = set(self._capability_matrix.get(cap_lower, []))
            if candidate_names is None:
                candidate_names = agents_with_cap
            else:
                candidate_names &= agents_with_cap

        if not candidate_names:
            return None

        # 过滤排除和不可用的 Agent，按 load 排序
        candidates = [
            self._agents[name]
            for name in candidate_names
            if name not in exclude_set
            and name in self._agents
            and self._agents[name].availability
        ]

        if not candidates:
            return None

        candidates.sort(key=lambda p: p.current_load)
        return candidates[0]

    def update_load(self, name: str, delta: int) -> None:
        """更新 Agent 负载"""
        profile = self._agents.get(name)
        if profile is not None:
            profile.current_load = max(0, profile.current_load + delta)

    def set_availability(self, name: str, available: bool) -> None:
        """设置 Agent 可用性"""
        profile = self._agents.get(name)
        if profile is not None:
            profile.availability = available

    @classmethod
    def from_agent_pool(cls, agent_pool, skill_registry) -> OrganizationContext:
        """从 AgentPool 和 SkillRegistry 构建 OrganizationContext

        Args:
            agent_pool: AgentPool 实例，提供运行时 Agent 列表
            skill_registry: SkillRegistry 实例，提供 Skill 配置查询
        """
        ctx = cls()

        if agent_pool is None or skill_registry is None:
            return ctx

        for agent_info in agent_pool.list_agents():
            agent_name = agent_info["name"]
            agent_type = agent_info.get("agent_type", "react")

            # 尝试从 skill_registry 获取 SkillConfig
            capabilities: list[str] = []
            skills: list[str] = []
            execution_mode = "react"
            model = "default"
            max_concurrency = 1

            try:
                skill = skill_registry.get(agent_name)
                config = skill.config
                capabilities = [cap.tag for cap in config.capabilities]
                execution_mode = config.execution_mode
                model = config.llm.get("model", "default") if config.llm else "default"
                max_concurrency = config.max_concurrency
                skills = [agent_name]
            except Exception:
                # Agent 不在 skill_registry 中，使用默认值
                skills = [agent_name]

            profile = AgentProfile(
                name=agent_name,
                agent_type=agent_type,
                capabilities=capabilities,
                skills=skills,
                execution_mode=execution_mode,
                model=model,
                max_concurrency=max_concurrency,
            )
            ctx.register_agent(profile)

        return ctx
