"""
测试 ServerSkillsMiddleware
===========================

测试服务端技能中间件的功能和效果。

测试内容：
1. Middleware 创建和初始化
2. skill 工具注册和功能
3. before_agent() - 技能元数据加载和白名单过滤
4. _format_skills_list() - 技能列表格式化
5. wrap_model_call() - 系统提示注入
6. 技能目录路径

使用示例：
    pytest langchain_agentx/middleware/test_server_skill_middleware.py -v
    python langchain_agentx/middleware/test_server_skill_middleware.py
    python langchain_agentx/middleware/test_server_skill_middleware.py 1  # 仅初始化测试
    python langchain_agentx/middleware/test_server_skill_middleware.py 2  # 仅工具测试
"""
import sys
from pathlib import Path
from unittest.mock import Mock

# 确保项目根目录在 Python 路径中（支持直接运行 python test_xxx.py）
_project_root = Path(__file__).resolve().parent.parent.parent
if str(_project_root) not in sys.path:
    sys.path.insert(0, str(_project_root))

from langchain_agentx.middleware import (
    ServerSkillsMiddleware,
    SkillsState,
    SkillsStateUpdate,
)


def print_section(title: str, width: int = 80):
    """打印分隔符"""
    print("\n" + "=" * width)
    print(title)
    print("=" * width)


def test_middleware_initialization():
    """测试 Middleware 初始化"""
    print_section("测试 ServerSkillsMiddleware 初始化")

    middleware = ServerSkillsMiddleware()

    print(f"✓ Middleware 创建成功")
    print(f"  skills_dir: {middleware.skills_dir}")
    print(f"  enabled_skills: {middleware.enabled_skills}")

    # 检查工具（skill 工具）
    assert len(middleware.tools) == 1, "应该注册 1 个工具（skill）"
    assert middleware.tools[0].name == "skill", "工具名称应该是 skill"

    print(f"✓ 工具注册成功")
    print(f"  工具数量: {len(middleware.tools)}")
    print(f"  工具名称: {middleware.tools[0].name}")

    print_section("初始化测试通过")


def test_middleware_initialization_with_whitelist():
    """测试带白名单的初始化"""
    print_section("测试 ServerSkillsMiddleware 初始化（带白名单）")

    enabled_skills = ["module_analysis", "architecture_analysis"]

    middleware = ServerSkillsMiddleware(enabled_skills=enabled_skills)

    print(f"✓ Middleware 创建成功（带白名单）")
    print(f"  enabled_skills: {middleware.enabled_skills}")
    assert middleware.enabled_skills == enabled_skills, "白名单应该正确设置"

    print_section("带白名单初始化测试通过")


def test_skill_tool():
    """测试 skill 工具"""
    print_section("测试 skill 工具")

    middleware = ServerSkillsMiddleware()

    # 获取工具（skill 工具）
    skill_tool = middleware.tools[0]
    assert skill_tool.name == "skill", "工具名称应该正确"

    print(f"✓ 工具获取成功: {skill_tool.name}")

    # 测试工具调用（如果技能目录存在）
    skills_dir = middleware.skills_dir
    if skills_dir.exists():
        # 查找第一个技能
        skill_dirs = [d for d in skills_dir.iterdir() if d.is_dir()]
        if skill_dirs:
            skill_name = skill_dirs[0].name
            print(f"  测试读取技能: {skill_name}")

            try:
                result = skill_tool.invoke({"skill_name": skill_name})
                assert isinstance(result, str), "应该返回字符串"
                assert len(result) > 0, "内容不应该为空"
                assert "---" in result or "#" in result, "应该包含 Markdown 内容"

                print(f"✓ 工具调用成功")
                print(f"  技能名称: {skill_name}")
                print(f"  内容长度: {len(result)} 字符")
                print(f"  内容预览（前 100 字符）: {result[:100]}...")
            except Exception as e:
                print(f"⚠ 工具调用失败（可能是技能不存在）: {e}")
        else:
            print(f"⚠ 技能目录为空，跳过工具调用测试")
    else:
        print(f"⚠ 技能目录不存在: {skills_dir}，跳过工具调用测试")

    # 测试不存在的技能
    try:
        result = skill_tool.invoke({"skill_name": "non_existent_skill"})
        print(f"❌ 应该抛出异常，但返回了: {result[:50] if result else 'None'}...")
    except ValueError as e:
        print(f"✓ 不存在的技能正确抛出异常: {str(e)[:100]}...")

    print_section("skill 工具测试通过")


def test_format_skills_list():
    """测试技能列表格式化"""
    print_section("测试 _format_skills_list")

    middleware = ServerSkillsMiddleware()

    # 测试空列表
    empty_result = middleware._format_skills_list([])
    assert empty_result == "（暂无可用技能）", "空列表应该返回提示信息"
    print(f"✓ 空列表格式化正确")

    # 测试有技能的列表
    skills = [
        {
            "name": "test_skill1",
            "description": "测试技能1",
            "path": "/path/to/skill1/SKILL.md",
            "source": "user"
        },
        {
            "name": "test_skill2",
            "description": "测试技能2",
            "path": "/path/to/skill2/SKILL.md",
            "source": "user",
            "tool_groups": ["code_search", "code_structure"]
        }
    ]

    result = middleware._format_skills_list(skills)
    assert isinstance(result, str), "应该返回字符串"
    assert "test_skill1" in result, "应该包含技能1"
    assert "test_skill2" in result, "应该包含技能2"

    print(f"✓ 技能列表格式化成功")
    print(f"  结果长度: {len(result)} 字符")
    print(f"  结果预览:")
    print(result[:300] + "..." if len(result) > 300 else result)

    print_section("技能列表格式化测试通过")


def test_before_agent():
    """测试 before_agent 方法"""
    print_section("测试 before_agent")

    middleware = ServerSkillsMiddleware()

    # 创建模拟的 state 和 runtime
    state = SkillsState()
    runtime = Mock()

    # 调用 before_agent
    result = middleware.before_agent(state, runtime)

    assert result is not None, "应该返回状态更新"
    assert "skills_metadata" in result, "应该包含 skills_metadata"
    assert isinstance(result["skills_metadata"], list), "skills_metadata 应该是列表"

    skills_count = len(result["skills_metadata"])
    print(f"✓ before_agent 执行成功")
    print(f"  加载技能数: {skills_count}")

    if skills_count > 0:
        print(f"  技能列表:")
        for skill in result["skills_metadata"]:
            print(f"    - {skill['name']}: {skill['description']}")

    print_section("before_agent 测试通过")


def test_before_agent_with_whitelist():
    """测试带白名单的 before_agent"""
    print_section("测试 before_agent（带白名单）")

    enabled_skills = ["module_analysis"]  # 只启用一个技能

    middleware = ServerSkillsMiddleware(enabled_skills=enabled_skills)

    state = SkillsState()
    runtime = Mock()

    result = middleware.before_agent(state, runtime)

    assert result is not None, "应该返回状态更新"
    skills = result["skills_metadata"]

    # 检查白名单过滤
    skill_names = [s["name"] for s in skills]
    assert all(name in enabled_skills for name in skill_names), "所有技能都应该在白名单中"

    print(f"✓ 白名单过滤成功")
    print(f"  启用技能: {skill_names}")
    print(f"  白名单: {enabled_skills}")

    print_section("带白名单的 before_agent 测试通过")


def test_wrap_model_call():
    """测试 wrap_model_call 方法"""
    print_section("测试 wrap_model_call")

    middleware = ServerSkillsMiddleware()

    # 创建模拟的 request
    request = Mock()
    request.system_prompt = "原始系统提示"
    request.state = {
        "skills_metadata": [
            {
                "name": "test_skill",
                "description": "测试技能",
                "path": "/path/to/skill/SKILL.md",
                "source": "user"
            }
        ]
    }

    # 创建模拟的 handler
    response = Mock()
    response.content = "响应内容"

    def handler(req):
        prompt = getattr(req, 'system_prompt', '')
        assert prompt != request.system_prompt or "技能系统" in prompt or "Skills System" in prompt, "系统提示应该被修改或包含技能系统"
        return response

    # override 应该返回一个新对象，其 system_prompt 被修改
    def override_mock(**kwargs):
        new_req = Mock()
        new_req.system_prompt = kwargs.get('system_prompt', request.system_prompt)
        new_req.state = request.state
        return new_req

    request.override = override_mock

    result = middleware.wrap_model_call(request, handler)

    assert result is not None, "应该返回响应"
    print(f"✓ wrap_model_call 执行成功（有 override 方法）")

    # 测试没有 override 方法的情况
    request_no_override = Mock()
    request_no_override.system_prompt = "原始系统提示"
    request_no_override.state = request.state
    delattr(request_no_override, 'override')

    result2 = middleware.wrap_model_call(request_no_override, handler)
    assert result2 is not None, "应该返回响应"
    print(f"✓ wrap_model_call 执行成功（无 override 方法）")

    print_section("wrap_model_call 测试通过")


def test_wrap_model_call_empty_skills():
    """测试空技能列表的系统提示注入"""
    print_section("测试 wrap_model_call（空技能列表）")

    middleware = ServerSkillsMiddleware()

    request = Mock()
    request.system_prompt = "原始系统提示"
    request.state = {"skills_metadata": []}  # 空列表

    response = Mock()
    response.content = "响应内容"

    def handler(req):
        prompt = getattr(req, 'system_prompt', '')
        assert "（暂无可用技能）" in prompt or "暂无可用技能" in prompt or "技能系统" in prompt, "应该包含空技能提示或技能系统"
        return response

    def override_mock(**kwargs):
        new_req = Mock()
        new_req.system_prompt = kwargs.get('system_prompt', request.system_prompt)
        new_req.state = request.state
        return new_req

    request.override = override_mock

    result = middleware.wrap_model_call(request, handler)
    assert result is not None, "应该返回响应"

    print(f"✓ 空技能列表处理正确")

    print_section("空技能列表测试通过")


def test_skills_directory_path():
    """测试技能目录路径设置"""
    print_section("测试技能目录路径")

    middleware = ServerSkillsMiddleware()

    # 检查技能目录路径
    skills_dir = middleware.skills_dir
    assert skills_dir is not None, "技能目录应该被设置"
    assert isinstance(skills_dir, Path), "应该是 Path 对象"

    # 检查路径结构
    assert "server_skill" in str(skills_dir), "路径应该包含 server_skill"
    assert "skill" in str(skills_dir), "路径应该包含 skill 目录"

    print(f"✓ 技能目录路径设置正确")
    print(f"  路径: {skills_dir}")
    print(f"  路径存在: {skills_dir.exists()}")

    if skills_dir.exists():
        skill_count = len([d for d in skills_dir.iterdir() if d.is_dir()])
        print(f"  技能目录数: {skill_count}")

    print_section("技能目录路径测试通过")


def run_all_tests():
    """运行所有测试"""
    print_section("ServerSkillsMiddleware 测试套件")

    test_functions = [
        test_middleware_initialization,
        test_middleware_initialization_with_whitelist,
        test_skill_tool,
        test_format_skills_list,
        test_before_agent,
        test_before_agent_with_whitelist,
        test_wrap_model_call,
        test_wrap_model_call_empty_skills,
        test_skills_directory_path,
    ]

    passed = 0
    failed = 0

    for test_func in test_functions:
        try:
            test_func()
            passed += 1
        except AssertionError as e:
            print(f"❌ {test_func.__name__} 失败: {e}")
            failed += 1
        except Exception as e:
            print(f"❌ {test_func.__name__} 异常: {e}")
            import traceback
            traceback.print_exc()
            failed += 1

    print_section("测试结果")
    print(f"通过: {passed}")
    print(f"失败: {failed}")
    print(f"总计: {passed + failed}")

    if failed == 0:
        print("\n✅ 所有测试通过！")
    else:
        print(f"\n❌ {failed} 个测试失败")


if __name__ == "__main__":
    import sys

    if len(sys.argv) > 1:
        test_num = sys.argv[1]
        if test_num == "1":
            print_section("仅测试初始化")
            test_middleware_initialization()
            test_middleware_initialization_with_whitelist()
            test_skills_directory_path()
        elif test_num == "2":
            print_section("仅测试工具")
            test_skill_tool()
            test_format_skills_list()
        else:
            print(f"未知的测试编号: {test_num}")
            print("使用: python test_server_skill_middleware.py [1|2]")
    else:
        run_all_tests()
