"""
agent67v2.core.bootstrap — 统一启动引导

将 agent-config.yml 编译为可运行的 Lambda Term，
自动处理 subAgents 节的子代理注册和工具注入。

用法:
  # 方式 1: PaaS CLI
  python3 -m agentpaas agent create --name lambda2 --config agentexample/agent67v2/agent-config.yml
  python3 -m agentpaas chat lambda2

  # 方式 2: Python 直接调用
  from agent67v2.core.bootstrap import build_agent67v2
  agent = build_agent67v2()
  result = agent.apply("帮我看看当前目录")

流程:
  1. 读取 agent-config.yml
  2. 解析 subAgents 节，编译每个子代理
  3. 注册子代理为 Skill 到 SkillRegistry
  4. 创建 call_* 元工具 + ToolSearch
  5. 通过 overrides["tools"] 注入到 from_config()
  6. 返回完整的协调者 Term
"""
from __future__ import annotations

import json
import os
import sys
import yaml
from pathlib import Path
from typing import Any, Dict, Optional

PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
AGENT_DIR = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

from lambdagent.core import Term, Context
from lambdagent.primitives import Tool
from lambdagent.skills import Skill, SkillSignature, SkillPack, SkillRegistry


# ════════════════════════════════════════════════════════════
# SubAgent 编译与注册
# ════════════════════════════════════════════════════════════

def _compile_sub_agent(name: str, config_path: Path) -> Optional[Term]:
    """编译单个子代理 YAML 为 Term"""
    if not config_path.exists():
        print(f"  ⚠️  子代理配置不存在: {config_path}")
        return None

    try:
        from lambdagent.fromconfig.compiler import from_config
        return from_config(str(config_path))
    except Exception as e:
        print(f"  ⚠️  子代理 {name} 编译失败: {e}")
        return None


def _register_sub_agents(config_path: Path, sub_agents_cfg: dict) -> Dict[str, Skill]:
    """
    编译并注册所有子代理为 Skill。

    Args:
        config_path: agent-config.yml 所在目录
        sub_agents_cfg: subAgents 配置节

    Returns:
        {agent_name: Skill} 映射
    """
    skills = {}
    pack = SkillPack(
        name="agent67v2",
        description="agent67v2 多智能体协作系统",
        version="2.0.0",
    )

    for agent_name, agent_def in sub_agents_cfg.items():
        # 解析子代理配置文件路径 (相对于 agent-config.yml 所在目录)
        rel_path = agent_def.get("config", f"agents/{agent_name}.yml")
        agent_yml = config_path / rel_path

        # 编译子代理
        term = _compile_sub_agent(agent_name, agent_yml)
        if term is None:
            continue

        # 创建 Skill
        skill = Skill(
            name=agent_name,
            term=term,
            description=agent_def.get("description", ""),
            signature=SkillSignature(input_type="Str", output_type="Str"),
            tags=agent_def.get("tags", []),
            version="2.0.0",
            author="agent67v2",
        )
        pack.add(skill)
        skills[agent_name] = skill

    # 注册到全局 SkillRegistry
    registry = SkillRegistry()
    registry.register_pack(pack)

    return skills


# ════════════════════════════════════════════════════════════
# 元工具构建
# ════════════════════════════════════════════════════════════

def _make_agent_caller(skill: Skill):
    """为一个子代理 Skill 创建调用函数"""
    def call_agent(input_str: str) -> str:
        try:
            # 解析输入
            if isinstance(input_str, str):
                try:
                    data = json.loads(input_str)
                    task = data.get("task", input_str)
                except (json.JSONDecodeError, AttributeError):
                    task = input_str
            else:
                task = str(input_str)

            ctx = Context()
            result = skill.apply(task, ctx)
            return str(result)
        except Exception as e:
            return f"[ERROR] {skill._name} 执行失败: {e}"

    return call_agent


def _build_meta_tools(skills: Dict[str, Skill], sub_agents_cfg: dict) -> Dict[str, Any]:
    """
    构建协调者的元工具集合。

    根据 subAgents 配置中的 tool 字段，为每个子代理创建对应的 call_* 函数。
    """
    tools = {}

    for agent_name, agent_def in sub_agents_cfg.items():
        tool_name = agent_def.get("tool", f"call_{agent_name.replace('-agent', '')}")
        skill = skills.get(agent_name)
        if skill:
            tools[tool_name] = _make_agent_caller(skill)

    # ToolSearch 元工具
    from agent67v2.tools.tool_search import tool_search
    tools["ToolSearch"] = lambda x: tool_search.apply(x)

    return tools


# ════════════════════════════════════════════════════════════
# 主入口: build_agent67v2
# ════════════════════════════════════════════════════════════

def build_agent67v2(config_file: str = None, **overrides) -> Term:
    """
    从 agent-config.yml 构建完整的 agent67v2 协调者。

    流程:
      1. 读取 agent-config.yml
      2. 解析 subAgents，编译并注册子代理
      3. 构建 call_* 元工具
      4. 通过 overrides["tools"] 注入到 from_config()
      5. 返回可执行的协调者 Term

    Args:
        config_file: agent-config.yml 路径 (默认: 自动定位)
        **overrides: 传递给 from_config 的覆盖参数

    Returns:
        Term: 可执行的协调者 Lambda Term
    """
    # 定位配置文件
    if config_file:
        config_path = Path(config_file).resolve()
    else:
        config_path = AGENT_DIR / "agent-config.yml"

    if not config_path.exists():
        raise FileNotFoundError(f"配置文件不存在: {config_path}")

    config_dir = config_path.parent

    # 读取配置
    with open(config_path, "r", encoding="utf-8") as f:
        cfg = yaml.safe_load(f)

    # 编译并注册子代理
    sub_agents_cfg = cfg.get("subAgents", {})
    if sub_agents_cfg:
        print(f"  🔄 编译 {len(sub_agents_cfg)} 个子代理...")
        skills = _register_sub_agents(config_dir, sub_agents_cfg)
        print(f"  ✅ {len(skills)} 个子代理已注册为 Skill")

        # 构建元工具
        meta_tools = _build_meta_tools(skills, sub_agents_cfg)

        # 注入到 overrides
        existing_tools = overrides.get("tools", {})
        existing_tools.update(meta_tools)
        overrides["tools"] = existing_tools

    # 通过 from_config 编译协调者
    from lambdagent.fromconfig.compiler import from_config
    agent = from_config(str(config_path), **overrides)

    return agent


def build_and_chat(config_file: str = None, **overrides):
    """
    构建 agent67v2 并进入交互式对话。

    用于 PaaS chat 模式的直接调用。
    """
    agent = build_agent67v2(config_file, **overrides)

    print(f"\n{'═' * 50}")
    print(f"  🐑 lambda v2 — 多智能体协作版")
    print(f"  输入 'exit' 退出")
    print(f"{'═' * 50}\n")

    while True:
        try:
            user_input = input("You: ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\n👋 lambda v2 下线了！")
            break

        if not user_input:
            continue
        if user_input.lower() in ("exit", "quit", "bye"):
            print("👋 lambda v2 下线了！")
            break

        print()
        ctx = Context()
        result = agent.apply(user_input, ctx)
        print(f"🐑 lambda v2: {result}")
        print()
