"""
Roneia Client - 初始配置向导

交互式配置向导：
1. 服务器连接（URL + Token + 测试连接）
2. Skill 配置（从服务器获取列表 + 安装依赖 + 启用）
3. 保存配置到 ~/.roneia/config.yaml
"""

import asyncio
import json
import getpass
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional

from .config import RoneiaClientConfig
from .dep_manager import DependencyManager, SKILL_DEPENDENCIES
from .skill_store import SkillStore


DEFAULT_CONFIG_PATH = str(Path.home() / ".roneia" / "config.yaml")


def run_setup() -> int:
    """配置向导入口"""
    try:
        return asyncio.run(_setup_async())
    except KeyboardInterrupt:
        print("\n\n配置已取消")
        return 1


async def _setup_async() -> int:
    """异步配置向导"""
    print()
    print("=" * 60)
    print("           Roneia - 初始配置向导")
    print("=" * 60)
    print()

    # 检查已有配置
    config_path = DEFAULT_CONFIG_PATH
    if Path(config_path).exists():
        answer = input(f"已存在配置文件: {config_path}\n是否覆盖? [y/N] > ").strip().lower()
        if answer not in ("y", "yes"):
            print("已取消")
            return 0
        print()

    config = RoneiaClientConfig()

    # ---- 步骤 1: 服务器连接 ----
    print("1) 服务器连接")
    print()

    default_url = config.server.url
    url = input(f"   服务器地址 [{default_url}]: ").strip()
    if not url:
        url = default_url
    config.server.url = url

    token = getpass.getpass("   认证令牌: ").strip()
    if token:
        config.server.token = token

    # 测试连接
    print()
    print("   正在测试连接...", end="", flush=True)
    connected, skills = await _test_connection(url, token)

    if connected:
        print(" 连接成功!")
    else:
        print(" 连接失败!")
        print("   (配置仍会保存，之后可通过 /skills 命令管理 Skill)")
        skills = []

    print()

    # ---- 步骤 2: Skill 配置 ----
    skill_store = SkillStore()
    dm = DependencyManager()

    if skills:
        print("2) Skill 配置")
        print(f"   从服务器获取到 {len(skills)} 个可用 Skill:")
        print()

        for i, skill in enumerate(skills, 1):
            name = skill.get("name", "")
            title = skill.get("title", "")
            deps = SKILL_DEPENDENCIES.get(name, [])
            dep_note = "(无额外依赖)" if not deps else f"(需安装依赖)"
            print(f"     [{i}] {name:<18} - {title} {dep_note}")

        print()
        choice = input("   选择要启用的 Skill (逗号分隔, 回车全部跳过): ").strip()

        if choice:
            indices = []
            for part in choice.split(","):
                part = part.strip()
                if part.isdigit():
                    idx = int(part) - 1
                    if 0 <= idx < len(skills):
                        indices.append(idx)

            enabled_names = []
            for idx in indices:
                skill = skills[idx]
                name = skill.get("name", "")

                # 安装到 SkillStore
                skill_store.install(
                    name=name,
                    version=skill.get("version", ""),
                    title=skill.get("title", ""),
                    description=skill.get("description", ""),
                )

                # 检查并安装依赖
                missing = dm.check_missing(name)
                if missing:
                    print(f"\n   正在安装 {name} 依赖...")
                    if dm.install_packages(missing):
                        print(f"   依赖安装完成")
                    else:
                        print(f"   依赖安装失败，请手动安装:")
                        print(f"     pip install {' '.join(missing)}")
                        print(f"   (Skill 仍会启用，部分功能可能不可用)")

                # 启用
                skill_store.enable(name)
                enabled_names.append(name)

            if enabled_names:
                print(f"\n   已启用: {', '.join(enabled_names)}")
    else:
        print("2) Skill 配置")
        print("   (跳过 - 连接服务器后使用 /skills 命令管理)")

    print()

    # ---- 步骤 3: 保存配置 ----
    print("3) 保存配置")
    config.to_yaml(config_path)
    print(f"   配置已保存到: {config_path}")

    print()
    print("=" * 60)
    print("   配置完成! 运行 roneia 开始使用")
    print("=" * 60)
    print()

    return 0


async def _test_connection(url: str, token: str) -> tuple:
    """
    测试服务器连接并获取 Skill 列表

    Returns:
        (connected: bool, skills: List[Dict])
    """
    try:
        import websockets
    except ImportError:
        return False, []

    # 拼接 token 到 URL
    connect_url = url
    if token:
        separator = "&" if "?" in url else "?"
        connect_url = f"{url}{separator}token={token}"

    try:
        ws = await asyncio.wait_for(
            websockets.connect(connect_url, ping_interval=None),
            timeout=10.0,
        )
    except Exception:
        return False, []

    try:
        # 发送认证
        import platform
        auth_msg = {
            "type": "auth.request",
            "id": "setup-auth",
            "payload": {
                "token": token,
                "client_info": {
                    "hostname": platform.node(),
                    "platform": platform.system(),
                    "version": "1.0.0",
                    "skills": [],
                },
            },
        }
        await ws.send(json.dumps(auth_msg, ensure_ascii=False))

        # 等待认证响应
        response = await asyncio.wait_for(ws.recv(), timeout=10.0)
        data = json.loads(response)
        if data.get("type") != "auth.response" or not data.get("payload", {}).get("success"):
            await ws.close()
            return False, []

        # 请求 Skill 列表
        list_msg = {
            "type": "skill.registry.list",
            "id": "setup-list",
            "payload": {},
        }
        await ws.send(json.dumps(list_msg, ensure_ascii=False))

        # 等待 Skill 列表响应
        skills = []
        try:
            response = await asyncio.wait_for(ws.recv(), timeout=10.0)
            data = json.loads(response)
            if data.get("type") == "skill.registry.response":
                skills = data.get("payload", {}).get("skills", [])
        except asyncio.TimeoutError:
            pass

        await ws.close()
        return True, skills

    except Exception:
        try:
            await ws.close()
        except Exception:
            pass
        return False, []
