"""
agentpaas launch — 一键启动 agent

流程:
    1. 启动 PaaS 服务 (后台)
    2. 创建租户 + API Key (如果需要)
    3. 注册 agent (从 YAML 配置)
    4. 开始对话 (支持语音 + 文字)

用法:
    agentpaas launch agent-config.yml
    agentpaas launch agent-config.yml --daemon
    agentpaas launch agent-config.yml --port 9000
"""
from __future__ import annotations

import json
import os
import secrets
import signal
import subprocess
import sys
import time
import urllib.request
import urllib.error
from pathlib import Path


def _wait_for_server(url, timeout=30):
    """等待 PaaS 服务就绪。"""
    for _ in range(timeout):
        try:
            req = urllib.request.Request("{}/health".format(url))
            with urllib.request.urlopen(req, timeout=2):
                return True
        except Exception:
            time.sleep(1)
    return False


def _api_call(base_url, api_key, method, path, data=None):
    """调用 PaaS API。"""
    url = "{}{}".format(base_url.rstrip("/"), path)
    headers = {"Content-Type": "application/json"}
    if api_key:
        headers["Authorization"] = "Bearer {}".format(api_key)
    body = json.dumps(data, ensure_ascii=False).encode() if data else None
    req = urllib.request.Request(url, data=body, headers=headers, method=method)
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        err_body = e.read().decode()
        return {"error": err_body}
    except urllib.error.URLError as e:
        return {"error": str(e)}


def _start_server(port, dev=False):
    """后台启动 PaaS 服务，返回进程。"""
    print("🚀 启动 AgentPaaS 服务 (port {})...".format(port))

    proc = subprocess.Popen(
        [sys.executable, "-m", "agentpaas", "serve", "--port", str(port)]
        + (["--dev"] if dev else []),
        stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    )
    print("  PID: {}".format(proc.pid))

    if not _wait_for_server("http://127.0.0.1:{}".format(port)):
        print("  ✗ 服务启动超时")
        proc.kill()
        return None

    print("  ✓ 服务就绪")
    return proc


def _ensure_tenant(port):
    """确保有租户和 API Key，返回 api_key。"""
    from agentpaas.__main__ import _load_config, _save_config

    cfg = _load_config()
    if cfg.get("api_key"):
        # 测试现有 key 是否有效
        result = _api_call(
            "http://127.0.0.1:{}".format(port), cfg["api_key"],
            "GET", "/api/v1/agents")
        if "error" not in result:
            return cfg["api_key"]

    # 创建新租户
    print("\n📋 创建租户...")
    from agentpaas.db.session import get_db
    from agentpaas.db.models import gen_id, now_utc
    from agentpaas.api.middleware.auth import hash_key

    db = get_db()
    tid = gen_id("tn_")
    uid = gen_id("usr_")
    key = "ap_{}".format(secrets.token_hex(16))
    now = now_utc()
    db.execute(
        "INSERT INTO tenants (id,name,plan,status,created_at) VALUES (?,?,?,'active',?)",
        (tid, "launch", "free", now))
    db.execute(
        "INSERT INTO users (id,tenant_id,email,role,created_at) VALUES (?,?,?,'admin',?)",
        (uid, tid, "", now))
    db.execute(
        "INSERT INTO api_keys (id,tenant_id,user_id,key_hash,key_prefix,name,scopes,rate_limit,status,created_at) "
        "VALUES (?,?,?,?,?,'admin',?,600,'active',?)",
        (gen_id("key_"), tid, uid, hash_key(key), key[:8],
         json.dumps(["agents:*", "keys:*", "billing:read", "admin:*"]), now))
    db.commit()

    cfg["server"] = "http://127.0.0.1:{}".format(port)
    cfg["api_key"] = key
    _save_config(cfg)
    print("  ✓ 租户已创建, API Key: {}...".format(key[:12]))
    return key


def _register_agent(port, api_key, config_path):
    """注册 agent 到 PaaS，返回 agent_id。"""
    import yaml

    config_path = Path(config_path).resolve()
    if not config_path.exists():
        print("✗ 配置文件不存在: {}".format(config_path))
        return None

    with open(config_path, "r", encoding="utf-8") as f:
        config = yaml.safe_load(f)

    name = config.get("name", config_path.stem)
    desc = config.get("description", "")
    tags = config.get("tags", [])
    if isinstance(tags, str):
        tags = [t.strip() for t in tags.split(",")]

    print("\n📝 注册 agent: {}".format(name))

    result = _api_call(
        "http://127.0.0.1:{}".format(port), api_key,
        "POST", "/api/v1/agents", {
            "name": name,
            "description": desc,
            "config": config,
            "tags": tags,
        })

    if "agent_id" in result:
        agent_id = result["agent_id"]
        version = result["version"]
        print("  ✓ Agent ID: {}  (v{})".format(agent_id, version))
        return agent_id
    else:
        print("  ✗ 注册失败: {}".format(result.get("error", "")))
        return None


def _chat_loop(agent_id, port, api_key, claude_code=True):
    """交互式对话循环（文字模式）。"""
    # 尝试加载 agent67 的 PersonalAssistant (Claude Code 模式)
    assistant = None
    if claude_code:
        try:
            project_root = Path(__file__).resolve().parent.parent
            agent_dir = project_root / "agentexample"
            if str(agent_dir) not in sys.path:
                sys.path.insert(0, str(agent_dir))
            if str(project_root) not in sys.path:
                sys.path.insert(0, str(project_root))

            # 从 PaaS 获取配置
            result = _api_call(
                "http://127.0.0.1:{}".format(port), api_key,
                "GET", "/api/v1/agents/{}".format(agent_id))
            config = result.get("config", {})
            system_prompt = config.get("systemPrompt", "")

            from agent67.core.claude_lam import ClaudeLam
            from agent67.core.assistant import PersonalAssistant
            from lambdagent import Context

            assistant = PersonalAssistant.__new__(PersonalAssistant)
            assistant.brain = ClaudeLam(
                "launch_agent", prompt=system_prompt,
                model="sonnet", max_tokens=config.get("model", {}).get("maxTokens", 4096))
            assistant.ctx = Context()
            assistant.conversation_history = []
            assistant.max_history = config.get("memory", {}).get("size", 20)
        except Exception as e:
            print("  ⚠️  Claude Code 模式不可用 ({}), 使用 PaaS API 模式".format(e))
            assistant = None

    mode = "Claude Code CLI" if assistant else "PaaS API"
    print("\n" + "═" * 55)
    print("  对话已就绪! Agent: {}".format(agent_id))
    print("  后端: {}".format(mode))
    print("  输入 exit 退出 | runs 查看历史")
    print("═" * 55 + "\n")

    while True:
        try:
            user_input = input("You: ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\n👋 再见!")
            break

        if not user_input:
            continue

        if user_input.lower() in ("exit", "quit", "bye"):
            print("👋 再见!")
            break
        if user_input.lower() == "runs":
            result = _api_call(
                "http://127.0.0.1:{}".format(port), api_key,
                "GET", "/api/v1/agents/{}/runs?limit=10".format(agent_id))
            runs = result.get("runs", [])
            if runs:
                for r in runs:
                    print("  {} | {} | {}ms | {}".format(
                        r["id"], r.get("status"), r.get("duration_ms", 0),
                        (r.get("created_at") or "")[:19]))
            else:
                print("  (暂无记录)")
            continue
        if user_input.lower() == "trace" and assistant:
            assistant.print_trace()
            continue

        print()
        t0 = time.time()

        if assistant:
            response = assistant.chat(user_input)
            duration_ms = int((time.time() - t0) * 1000)
            steps = len(assistant.ctx.trace)
            # 回写到 PaaS
            _api_call(
                "http://127.0.0.1:{}".format(port), api_key,
                "POST", "/api/v1/agents/{}/runs/record".format(agent_id), {
                    "input": user_input[:500], "output": response[:2000],
                    "status": "completed", "duration_ms": duration_ms,
                    "steps": steps, "source": "launch-claude-code",
                })
        else:
            result = _api_call(
                "http://127.0.0.1:{}".format(port), api_key,
                "POST", "/api/v1/agents/{}/run".format(agent_id),
                {"input": user_input})
            response = result.get("output", result.get("error", "(无回复)"))
            duration_ms = int((time.time() - t0) * 1000)

        print("🐂 lambda: {}".format(response))
        print("  [{:.1f}s]\n".format(duration_ms / 1000))


# ── 公开入口 ────────────────────────────────────────────────

def cmd_launch(config_path, port=8000):
    """一键启动: 服务 + 注册 + 对话。退出时自动关闭服务。"""
    proc = _start_server(port)
    if not proc:
        return

    try:
        api_key = _ensure_tenant(port)
        agent_id = _register_agent(port, api_key, config_path)
        if not agent_id:
            return

        _chat_loop(agent_id, port, api_key)
    except KeyboardInterrupt:
        print("\n\n🛑 中断")
    finally:
        print("\n关闭 PaaS 服务...")
        proc.terminate()
        try:
            proc.wait(timeout=5)
        except subprocess.TimeoutExpired:
            proc.kill()
        print("  ✓ 已关闭")


LAUNCH_PID_FILE = Path.home() / ".agentpaas" / "launch_daemon.pid"
LAUNCH_INFO_FILE = Path.home() / ".agentpaas" / "launch_daemon.json"


def cmd_launch_daemon(config_path, port=8000):
    """后台启动: 服务 + 注册 agent，然后返回。不进入对话。
    之后可以用 wechat / 其他终端 chat 连接。"""
    proc = _start_server(port)
    if not proc:
        return

    api_key = _ensure_tenant(port)
    agent_id = _register_agent(port, api_key, config_path)
    if not agent_id:
        proc.kill()
        return

    # 保存 daemon 信息
    LAUNCH_PID_FILE.parent.mkdir(parents=True, exist_ok=True)
    LAUNCH_PID_FILE.write_text(str(proc.pid))
    LAUNCH_INFO_FILE.write_text(json.dumps({
        "pid": proc.pid,
        "port": port,
        "agent_id": agent_id,
        "api_key": api_key,
        "config": str(Path(config_path).resolve()),
        "started_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
    }, indent=2))

    print("\n✅ 后台运行中")
    print("  PID:      {}".format(proc.pid))
    print("  Port:     {}".format(port))
    print("  Agent:    {}".format(agent_id))
    print("  API:      http://127.0.0.1:{}".format(port))
    print()
    print("连接方式:")
    print("  agentpaas run {} 'Hello'              # 单次调用".format(agent_id))
    print("  agentpaas wechat start {}             # 微信桥接".format(agent_id))
    print()
    print("停止: kill {}".format(proc.pid))
