"""BoardRouter 单元测试 — @board 前缀路由解析"""

from __future__ import annotations

from agentkit.experts.board_router import (
    BOARD_PREFIX_PATTERN,
    BoardRouter,
    BoardRoutingResult,
    MAX_EXPERTS,
)
from agentkit.experts.config import ExpertConfig, ExpertTemplate
from agentkit.experts.registry import ExpertTemplateRegistry


# ── 辅助函数 ──────────────────────────────────────────────


def _make_expert_template(
    name: str = "test_expert",
    persona: str = "测试专家",
    speaking_style: str = "直接",
    decision_framework: str = "分析",
) -> ExpertTemplate:
    """创建测试用 ExpertTemplate"""
    config = ExpertConfig(
        name=name,
        agent_type="expert",
        persona=persona,
        thinking_style="analytical",
        speaking_style=speaking_style,
        decision_framework=decision_framework,
        bound_skills=[],
        task_mode="llm_generate",
        prompt={"identity": persona},
    )
    return ExpertTemplate(
        name=name,
        config=config,
        is_builtin=True,
        description=f"{name} 测试模板",
    )


def _make_registry_with_experts() -> ExpertTemplateRegistry:
    """创建包含预注册专家模板的注册中心"""
    registry = ExpertTemplateRegistry()
    registry.register(_make_expert_template("elon_musk", persona="Elon Musk"))
    registry.register(_make_expert_template("jeff_bezos", persona="Jeff Bezos"))
    registry.register(_make_expert_template("allenzhang", persona="张小龙"))

    # 注册 private_board 模板（使用 bound_skills 存储成员列表）
    board_config = ExpertConfig(
        name="private_board",
        agent_type="expert",
        persona="私董会模板",
        bound_skills=["elon_musk", "jeff_bezos", "allenzhang"],
        task_mode="llm_generate",
        prompt={"identity": "Private Board"},
    )
    registry.register(
        ExpertTemplate(
            name="private_board",
            config=board_config,
            is_builtin=True,
            description="默认私董会模板",
        )
    )
    return registry


# ── BOARD_PREFIX_PATTERN 正则测试 ──────────────────────────


class TestBoardPrefixPattern:
    """BOARD_PREFIX_PATTERN 正则匹配测试"""

    def test_match_board_only(self):
        """@board 前缀匹配（无专家指定）"""
        match = BOARD_PREFIX_PATTERN.match("@board 讨论AI未来")
        assert match is not None
        assert match.group(1) is None
        assert match.group(2) == "讨论AI未来"

    def test_match_board_with_experts(self):
        """@board:expert1,expert2 格式匹配"""
        match = BOARD_PREFIX_PATTERN.match("@board:elon_musk,jeff_bezos SpaceX上市")
        assert match is not None
        assert match.group(1) == "elon_musk,jeff_bezos"
        assert match.group(2) == "SpaceX上市"

    def test_match_board_with_template_name(self):
        """@board:private_board 显式使用模板"""
        match = BOARD_PREFIX_PATTERN.match("@board:private_board 讨论主题")
        assert match is not None
        assert match.group(1) == "private_board"
        assert match.group(2) == "讨论主题"

    def test_no_match_regular_input(self):
        """普通输入不匹配"""
        assert BOARD_PREFIX_PATTERN.match("你好，今天天气怎么样") is None
        assert BOARD_PREFIX_PATTERN.match("@team 分析数据") is None
        assert BOARD_PREFIX_PATTERN.match("@skill:search 搜索内容") is None

    def test_match_board_with_multiline_topic(self):
        """多行主题匹配"""
        match = BOARD_PREFIX_PATTERN.match("@board 第一行\n第二行")
        assert match is not None
        assert "第一行" in match.group(2)
        assert "第二行" in match.group(2)


# ── BoardRouter.resolve 测试 ──────────────────────────────


class TestBoardRouterResolve:
    """BoardRouter.resolve 路由解析测试"""

    def test_resolve_default_template(self):
        """@board 主题 → 使用默认模板"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board 如何看待AI对教育的影响")

        assert result.matched is True
        assert result.board_mode is True
        assert result.topic == "如何看待AI对教育的影响"
        assert result.use_default_template is True
        assert result.match_method == "explicit_board"
        assert "elon_musk" in result.specified_experts
        assert "jeff_bezos" in result.specified_experts
        assert "allenzhang" in result.specified_experts

    def test_resolve_explicit_template(self):
        """@board:private_board 主题 → 显式使用默认模板"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board:private_board 讨论主题")

        assert result.matched is True
        assert result.use_default_template is True
        assert result.topic == "讨论主题"
        assert len(result.specified_experts) == 3

    def test_resolve_specified_experts(self):
        """@board:expert1,expert2 主题 → 指定专家"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board:elon_musk,jeff_bezos SpaceX上市问题")

        assert result.matched is True
        assert result.use_default_template is False
        assert result.specified_experts == ["elon_musk", "jeff_bezos"]
        assert result.topic == "SpaceX上市问题"

    def test_resolve_non_board_input(self):
        """普通输入不匹配"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("你好，今天天气怎么样")

        assert result.matched is False
        assert result.board_mode is False
        assert result.topic == "你好，今天天气怎么样"

    def test_resolve_empty_topic(self):
        """@board 无主题 → 空主题"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board")

        assert result.matched is True
        assert result.topic == ""

    def test_resolve_with_rounds_option(self):
        """@board:expert1,expert2 rounds=N 主题 → 解析最大轮次"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board:elon_musk,jeff_bezos rounds=3 SpaceX上市问题")

        assert result.matched is True
        assert result.max_rounds == 3
        assert result.topic == "SpaceX上市问题"
        assert result.specified_experts == ["elon_musk", "jeff_bezos"]

    def test_resolve_rounds_option_clamped(self):
        """rounds 超出范围会被限制"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board rounds=999 讨论主题")

        assert result.matched is True
        assert result.max_rounds == 50
        assert result.topic == "讨论主题"

    def test_resolve_without_rounds_option(self):
        """未指定 rounds 时 max_rounds 为 None"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board:elon_musk 讨论主题")

        assert result.matched is True
        assert result.max_rounds is None
        assert result.topic == "讨论主题"

    def test_resolve_invalid_expert_names_filtered(self):
        """无效专家名被过滤"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        result = router.resolve("@board:elon_musk,invalid@name,jeff_bezos 主题")

        assert result.matched is True
        assert "elon_musk" in result.specified_experts
        assert "jeff_bezos" in result.specified_experts
        assert "invalid@name" not in result.specified_experts

    def test_resolve_max_experts_limit(self):
        """专家数量超过上限被截断"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        # 构造超过 MAX_EXPERTS 个专家名
        names = ",".join(f"expert_{i}" for i in range(MAX_EXPERTS + 5))
        result = router.resolve(f"@board:{names} 讨论主题")

        assert result.matched is True
        assert len(result.specified_experts) <= MAX_EXPERTS

    def test_resolve_default_template_fallback(self):
        """无注册中心时使用硬编码回退默认成员"""
        router = BoardRouter(template_registry=ExpertTemplateRegistry())
        result = router.resolve("@board 讨论主题")

        assert result.matched is True
        assert result.use_default_template is True
        # 回退到硬编码列表
        assert len(result.specified_experts) > 0
        assert "elon_musk" in result.specified_experts


# ── BoardRouter.resolve_expert_configs 测试 ────────────────


class TestBoardRouterResolveConfigs:
    """BoardRouter.resolve_expert_configs 配置解析测试"""

    def test_resolve_configs_from_templates(self):
        """从注册模板解析专家配置"""
        registry = _make_registry_with_experts()
        router = BoardRouter(template_registry=registry)
        configs = router.resolve_expert_configs(["elon_musk", "jeff_bezos"])

        assert len(configs) == 2
        assert configs[0].name == "elon_musk"
        assert configs[0].is_lead is True  # 第一个为主持人
        assert configs[1].name == "jeff_bezos"
        assert configs[1].is_lead is False
        # 验证 board 模式字段
        assert configs[0].speaking_style == "直接"
        assert configs[0].decision_framework == "分析"

    def test_resolve_configs_dynamic_generation(self):
        """未注册的专家名动态生成配置"""
        router = BoardRouter(template_registry=ExpertTemplateRegistry())
        configs = router.resolve_expert_configs(["unknown_expert"])

        assert len(configs) == 1
        assert configs[0].name == "unknown_expert"
        assert configs[0].is_lead is True

    def test_resolve_configs_first_is_moderator(self):
        """第一个专家自动设为主持人"""
        registry = _make_registry_with_experts()
        router = BoardRouter(template_registry=registry)
        configs = router.resolve_expert_configs(["elon_musk", "jeff_bezos", "allenzhang"])

        assert configs[0].is_lead is True
        assert configs[1].is_lead is False
        assert configs[2].is_lead is False

    def test_resolve_configs_empty_list(self):
        """空列表返回空配置"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        configs = router.resolve_expert_configs([])
        assert len(configs) == 0

    def test_resolve_configs_invalid_name_skipped(self):
        """无效专家名被跳过"""
        router = BoardRouter(template_registry=_make_registry_with_experts())
        configs = router.resolve_expert_configs(["elon_musk", "invalid@name", "jeff_bezos"])

        assert len(configs) == 2
        assert configs[0].name == "elon_musk"
        assert configs[1].name == "jeff_bezos"

    def test_resolve_configs_ensure_at_least_one_lead(self):
        """确保至少有一个主持人"""
        registry = _make_registry_with_experts()
        # 修改模板使 is_lead 全为 False
        for name in ["elon_musk", "jeff_bezos"]:
            template = registry.get(name)
            if template:
                template.config.is_lead = False

        router = BoardRouter(template_registry=registry)
        configs = router.resolve_expert_configs(["elon_musk", "jeff_bezos"])

        # 第一个应被强制设为 lead
        assert configs[0].is_lead is True


# ── BoardRoutingResult 数据类测试 ──────────────────────────


class TestBoardRoutingResult:
    """BoardRoutingResult 数据类测试"""

    def test_default_values(self):
        """默认值"""
        result = BoardRoutingResult()
        assert result.matched is False
        assert result.board_mode is False
        assert result.specified_experts == []
        assert result.topic == ""
        assert result.use_default_template is False
        assert result.match_method == ""
        assert result.max_rounds is None

    def test_custom_values(self):
        """自定义值"""
        result = BoardRoutingResult(
            matched=True,
            board_mode=True,
            specified_experts=["a", "b"],
            topic="测试主题",
            use_default_template=True,
            match_method="explicit_board",
            max_rounds=7,
        )
        assert result.matched is True
        assert result.board_mode is True
        assert result.specified_experts == ["a", "b"]
        assert result.topic == "测试主题"
        assert result.use_default_template is True
        assert result.match_method == "explicit_board"
