#!/usr/bin/env python3
"""
coco Agent CLI — 智能体管理工具

用法:
  python cli.py create <name>              创建新智能体
  python cli.py chat <name>                文字对话
  python cli.py voice <name>               语音对话
  python cli.py list                       列出所有智能体
  python cli.py memory list <name>         列出记忆模块
  python cli.py memory load <name> <id>    加载记忆模块
  python cli.py memory unload <name> <id>  卸载记忆模块
  python cli.py memory search <name> <q>   搜索记忆
  python cli.py stats <name>               查看统计
  python cli.py check <name>               检查配置是否就绪
"""

import sys
import argparse
import shutil
from pathlib import Path

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

from coco.runtime import project_root, resource_root

AGENTS_DIR = project_root() / "agents"


def _ensure_agents_dir() -> None:
    if AGENTS_DIR.exists():
        return
    bundled_agents = resource_root() / "agents"
    if not bundled_agents.exists():
        AGENTS_DIR.mkdir(parents=True, exist_ok=True)
        return
    shutil.copytree(bundled_agents, AGENTS_DIR)


_ensure_agents_dir()


def _profile_user_name() -> str:
    """当前用户在个人设置里的称呼。"""
    try:
        from coco.runtime import load_user_profile
        return (load_user_profile().get("display_name") or "公子").strip() or "公子"
    except Exception:
        return "公子"


def _check_dependencies():
    """检查关键依赖是否安装"""
    missing = []
    try:
        import yaml
    except ImportError:
        missing.append("pyyaml")
    try:
        import requests
    except ImportError:
        missing.append("requests")
    try:
        import tencentcloud
    except ImportError:
        missing.append("tencentcloud-sdk-python-asr")

    if missing:
        print(f"缺少依赖: {', '.join(missing)}")
        print(f"请运行: pip install {' '.join(missing)}")
        sys.exit(1)


def _check_api_key(agent_config):
    """检查 API key 是否配置"""
    from coco.runtime import active_user_model, global_api_key, global_config_path, models_path

    model = active_user_model()
    api_key = model.get("api_key", "") or global_api_key() or agent_config.api_key
    if not api_key:
        return False, (
            "未配置 API key。请选择以下方式之一:\n"
            "  1. 设置环境变量: set coco_api_key=sk-xxx\n"
            f"  2. 在用户级模型配置中填入 api_key: {models_path()}\n"
            f"  3. 在全局配置中填入 api_key: {global_config_path()}"
        )
    if api_key.startswith("sk-"):
        return True, "OK"
    return True, "OK (非标准格式, 可能使用兼容 API)"


def _check_tencent_asr_key():
    """检查腾讯云 ASR 密钥是否配置"""
    from coco.runtime import global_config_path, tencent_asr_config

    config = tencent_asr_config()
    if config.get("secret_id") and config.get("secret_key"):
        return True, "OK"
    return False, (
        "未配置腾讯云 ASR 密钥。请选择以下方式之一:\n"
        "  1. 设置环境变量: set TENCENTCLOUD_SECRET_ID=xxx 和 set TENCENTCLOUD_SECRET_KEY=xxx\n"
        f"  2. 在全局配置中填入 tencent_asr.secret_id / secret_key: {global_config_path()}"
    )


# ─── 子命令 ────────────────────────────────────────────────────


def cmd_create(args):
    """创建新智能体"""
    agent_dir = AGENTS_DIR / args.name
    if agent_dir.exists():
        print(f"智能体 '{args.name}' 已存在")
        return

    agent_dir.mkdir(parents=True)

    from coco.config import AgentConfig
    config = AgentConfig(name=args.name)
    config.to_yaml(agent_dir / "config.yaml")

    identity = f"""# {args.name} 的身份

你是 {args.name}，一个智能助手。

## 性格
友好、专业、乐于助人。

## 主人设定
- 用户称呼来自个人设置里的“称呼”：{{user_name}}
- 主人设定来自个人设置里的“设定”：{{主人设定}}
- 如果主人设定为空，就只遵循本身份文件和对话上下文。

## 能力
- 回答各种问题
- 帮助用户完成任务
- 记住对话内容

## 约束
- 保持诚实
- 不确定时坦诚说明
"""
    (agent_dir / "IDENTITY.md").write_text(identity, encoding="utf-8")

    (agent_dir / "public_memory").mkdir(parents=True, exist_ok=True)

    print(f"智能体 '{args.name}' 已创建")
    print(f"  目录: {agent_dir}")
    from coco.runtime import models_path
    if args.api_base:
        print(f"  API 地址属于用户级模型配置，未写入智能体 config.yaml: {args.api_base}")
    print(f"  API key 建议配置在用户级模型文件: {models_path()}")
    print(f"  编辑 IDENTITY.md 自定义人格")
    print(f"\n  检查配置: python cli.py check {args.name}")
    print(f"  启动对话: python cli.py chat {args.name}")


def cmd_check(args):
    """检查智能体配置"""
    agent_dir = _resolve_agent(args.name)

    from coco.config import AgentConfig
    from coco.runtime import active_user_model
    config = AgentConfig.from_yaml(agent_dir / "config.yaml")
    model = active_user_model()

    print(f"智能体: {config.name}")
    print(f"模型: {model['model']}")
    print(f"API 地址: {model['api_base']}")

    ok, msg = _check_api_key(config)
    if ok:
        print(f"API key: 已配置")
    else:
        print(f"API key: 未配置")

    asr_ok, asr_msg = _check_tencent_asr_key()
    print(f"腾讯云 ASR: {'已配置' if asr_ok else '未配置'}")

    # 检查依赖
    deps_ok = True
    try:
        import yaml
        import requests
    except ImportError as e:
        print(f"依赖: 缺少 {e.name}")
        deps_ok = False
    else:
        print(f"依赖: 完整")

    # 检查身份文件
    identity_path = agent_dir / "IDENTITY.md"
    if identity_path.exists():
        print(f"身份文件: 存在 ({identity_path.stat().st_size} bytes)")
    else:
        print("身份文件: 不存在")

    # 检查记忆
    from coco.memory import MemoryEngine
    from coco.runtime import migrate_legacy_agent_memory
    engine = MemoryEngine(
        agent_dir,
        memory_dir=migrate_legacy_agent_memory(agent_dir.name, agent_dir / "memory"),
        raw_retention_days=config.memory.summary_threshold_days,
        summary_retention_days=config.memory.summary_retention_days,
        semantic_decay_days=config.memory.semantic_decay_days,
        semantic_forget_days=config.memory.semantic_forget_days,
    )
    stats = engine.get_stats()
    print(f"记忆: {stats['total_modules']} 模块, {stats['semantic_facts']} 事实")

    if not ok:
        print(f"\n提示: {msg}")
    if not asr_ok:
        print(f"\n语音提示: {asr_msg}")
    if ok and asr_ok:
        print("\n配置就绪, 可以启动对话")


def cmd_chat(args):
    """文字对话"""
    agent_dir = _resolve_agent(args.name)

    from coco.config import AgentConfig
    from coco.runtime import active_user_model
    config = AgentConfig.from_yaml(agent_dir / "config.yaml")
    model = active_user_model()
    ok, msg = _check_api_key(config)
    if not ok:
        print(f"启动失败: {msg}")
        return

    from coco.agent import Agent
    agent = Agent(str(agent_dir))

    print(f"{agent.config.name} 已就绪 (输入 /quit 退出, /help 查看命令)")
    print("-" * 50)

    try:
        while True:
            user_input = input(f"\n{_profile_user_name()}: ").strip()

            if not user_input:
                continue

            if user_input.startswith("/"):
                result = _handle_command(agent, user_input)
                if result == "QUIT":
                    break
                print(result)
                continue

            # 先试 API 可达性
            print(f"\n{agent.config.name}: ", end="", flush=True)
            try:
                for chunk in agent.chat_stream(user_input):
                    print(chunk, end="", flush=True)
                print()
            except Exception as e:
                error_str = str(e)
                if "403" in error_str or "401" in error_str:
                    print(f"\n\n[API 认证失败]")
                    print(f"请检查用户级模型配置中的 api_key 和 api_base")
                    print(f"当前 api_base: {model['api_base']}")
                elif "Connection" in error_str or "connect" in error_str.lower():
                    print(f"\n\n[无法连接 API]")
                    print(f"请检查网络和 api_base: {model['api_base']}")
                else:
                    print(f"\n\n[错误] {error_str[:200]}")

    except KeyboardInterrupt:
        print("\n\n已中断")
    finally:
        agent.close()
        print(f"\n{agent.config.name} 的记忆已保存")


def cmd_voice(args):
    """语音对话"""
    agent_dir = _resolve_agent(args.name)

    from coco.config import AgentConfig
    config = AgentConfig.from_yaml(agent_dir / "config.yaml")
    ok, msg = _check_api_key(config)
    if not ok:
        print(f"启动失败: {msg}")
        return
    asr_ok, asr_msg = _check_tencent_asr_key()
    if not asr_ok:
        print(f"启动失败: {asr_msg}")
        return

    from coco.agent import Agent
    agent = Agent(str(agent_dir))

    print(f"{agent.config.name} 语音模式")
    print(f"  STT: 腾讯云 ASR ({config.voice.stt_engine_model_type})")
    print(f"  TTS: edge-tts ({config.voice.tts_voice})")
    print()

    print("按键操作:")
    print("  Enter  → 开始说话，说完再按 Enter 结束")
    print("  /text <文字> → 文字对话（不录音）")
    print("  /quit → 退出")
    print()

    try:
        while True:
            result = agent.chat_voice()
            if result and "/QUIT" in str(result):
                break
    except KeyboardInterrupt:
        print("\n\n已中断")
    finally:
        agent.close()


def cmd_memory(args):
    """记忆管理"""
    agent_dir = _resolve_agent(args.name)
    from coco.agent import Agent
    agent = Agent(str(agent_dir))

    if args.action == "list":
        result = agent.list_memories(args.type)
    elif args.action == "load":
        result = agent.load_memory(args.module_id)
    elif args.action == "unload":
        result = agent.unload_memory(args.module_id)
    elif args.action == "search":
        result = agent.search_memory(args.query)
    else:
        result = "未知操作"

    print(result)
    agent.close()


def cmd_speak(args):
    """朗读文字"""
    agent_dir = _resolve_agent(args.name)
    from coco.agent import Agent
    agent = Agent(str(agent_dir))
    text = " ".join(args.text)
    print(f"朗读: {text[:50]}...")
    agent.speak(text)
    print("播放完毕")
    agent.close()


def cmd_stt(args):
    """测试语音识别"""
    agent_dir = _resolve_agent(args.name)
    asr_ok, asr_msg = _check_tencent_asr_key()
    if not asr_ok:
        print(f"启动失败: {asr_msg}")
        return
    from coco.agent import Agent
    agent = Agent(str(agent_dir))
    try:
        text = agent.listen()
        print(f"识别结果: {text}")
    finally:
        agent.close()


def cmd_stats(args):
    """查看统计"""
    agent_dir = _resolve_agent(args.name)
    from coco.agent import Agent
    agent = Agent(str(agent_dir))

    print(f"智能体: {agent.config.name}")
    print(agent.memory_stats())
    agent.close()


def cmd_list(args):
    """列出所有智能体"""
    if not AGENTS_DIR.exists():
        print("暂无智能体")
        return

    agents = sorted(AGENTS_DIR.iterdir())
    found = False
    print("智能体列表:")
    for a in agents:
        if a.is_dir() and (a / "config.yaml").exists():
            from coco.config import AgentConfig
            config = AgentConfig.from_yaml(a / "config.yaml")
            desc = config.description or "(无描述)"
            print(f"  {a.name} — {desc}")
            found = True

    if not found:
        print("暂无智能体")


def cmd_serve(args):
    """启动 Web 桥接服务"""
    from coco.web_bridge import run_bridge

    run_bridge(AGENTS_DIR, host=args.host, port=args.port)


def cmd_desktop(args):
    """启动透明桌面界面"""
    from coco.desktop import run_desktop

    run_desktop(width=args.width, height=args.height)


# ─── 内部命令处理 ──────────────────────────────────────────────


def _handle_command(agent, cmd: str) -> str:
    parts = cmd.split(maxsplit=1)
    action = parts[0].lower()

    if action in ("/quit", "/exit"):
        return "QUIT"

    elif action == "/help":
        return (
            "命令列表:\n"
            "  /quit      退出对话\n"
            "  /memories  列出记忆模块\n"
            "  /load <id> 加载记忆模块\n"
            "  /unload <id> 卸载记忆模块\n"
            "  /search <q> 搜索记忆\n"
            "  /stats     记忆统计\n"
            "  /remember <事实>  记住一条事实\n"
            "  /reset     重置会话(保留记忆)\n"
            "  /help      显示帮助"
        )

    elif action == "/memories":
        return agent.list_memories(parts[1] if len(parts) > 1 else None)

    elif action == "/load":
        if len(parts) > 1:
            return agent.load_memory(parts[1])
        return "用法: /load <模块ID>"

    elif action == "/unload":
        if len(parts) > 1:
            return agent.unload_memory(parts[1])
        return "用法: /unload <模块ID>"

    elif action == "/search":
        if len(parts) > 1:
            return agent.search_memory(parts[1])
        return "用法: /search <关键词>"

    elif action == "/stats":
        return agent.memory_stats()

    elif action == "/remember":
        if len(parts) > 1:
            return agent.remember_this(parts[1])
        return "用法: /remember <事实内容>"

    elif action == "/reset":
        agent.reset_session()
        return "会话已重置"

    else:
        return f"未知命令: {action} (输入 /help 查看帮助)"


def _resolve_agent(name: str) -> Path:
    agent_dir = AGENTS_DIR / name
    if not agent_dir.exists():
        print(f"智能体 '{name}' 不存在")
        print(f"可用: python cli.py create {name}")
        sys.exit(1)
    return agent_dir


# ─── 入口 ─────────────────────────────────────────────────────


def main():
    parser = argparse.ArgumentParser(
        description="coco Agent CLI — 独立智能体管理工具",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例:
  python cli.py create mybot             创建智能体
  python cli.py check mybot              检查配置
  python cli.py chat mybot               开始对话
  python cli.py memory list mybot        列出记忆
  python cli.py memory search mybot Python  搜索记忆
  python cli.py stt mybot                测试语音识别
  python cli.py serve                    启动 Web 桥接
  python cli.py desktop                  启动桌面界面
  python cli.py stats mybot              查看统计
  python cli.py list                     列出所有智能体
        """,
    )

    subparsers = parser.add_subparsers(dest="command")

    p_create = subparsers.add_parser("create", help="创建新智能体")
    p_create.add_argument("name", help="智能体名称")

    p_check = subparsers.add_parser("check", help="检查配置")

    p_chat = subparsers.add_parser("chat", help="文字对话")

    p_voice = subparsers.add_parser("voice", help="语音对话 (按键录音)")

    p_speak = subparsers.add_parser("speak", help="朗读文字 (测试TTS)")
    p_speak.add_argument("name", help="智能体名称")
    p_speak.add_argument("text", nargs="+", help="要朗读的文字")

    p_stt = subparsers.add_parser("stt", help="测试语音识别")

    p_mem = subparsers.add_parser("memory", help="记忆管理")
    p_mem.add_argument("action", choices=["list", "load", "unload", "search"], help="操作")

    p_stats = subparsers.add_parser("stats", help="查看统计")
    p_serve = subparsers.add_parser("serve", help="启动 Web 桥接")
    p_serve.add_argument("--host", default="127.0.0.1", help="监听地址")
    p_serve.add_argument("--port", type=int, default=8765, help="监听端口")
    p_desktop = subparsers.add_parser("desktop", help="启动桌面界面")
    p_desktop.add_argument("--width", type=int, default=540, help="窗口宽度")
    p_desktop.add_argument("--height", type=int, default=700, help="初始窗口高度")
    subparsers.add_parser("list", help="列出全部")

    # 需要 name 参数的命令
    for p in [p_check, p_chat, p_voice, p_stt, p_mem, p_stats]:
        p.add_argument("name", help="智能体名称")

    p_mem.add_argument("extra", nargs="?", help="模块ID 或 搜索词")

    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        return

    _check_dependencies()

    if args.command == "memory":
        if args.action in ("load", "unload"):
            args.module_id = args.extra
        elif args.action == "search":
            args.query = args.extra
        args.type = None
        cmd_memory(args)
    else:
        {
            "create": cmd_create,
            "check": cmd_check,
            "chat": cmd_chat,
            "voice": cmd_voice,
            "speak": cmd_speak,
            "stt": cmd_stt,
            "stats": cmd_stats,
            "serve": cmd_serve,
            "desktop": cmd_desktop,
            "list": cmd_list,
        }[args.command](args)


if __name__ == "__main__":
    main()
