#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

from common import get_auto_install_skills, load_agent_definition, load_json


def run_sophhub_download(skill_name: str, output_dir: Path, *, timeout: int = 300) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        ["npx", "-y", "sophhub@latest", "download", skill_name, "-o", str(output_dir)],
        capture_output=True,
        text=True,
        check=False,
        timeout=timeout,
    )


def replace_skill_directory(source_dir: Path, target_dir: Path) -> None:
    """删除目标 skill 目录并用新下载内容完整替换。"""
    if target_dir.exists():
        shutil.rmtree(target_dir)
    shutil.copytree(source_dir, target_dir)


def install_single_skill(skill_name: str, skills_dir: Path) -> dict[str, object]:
    target_dir = skills_dir / skill_name

    with tempfile.TemporaryDirectory(prefix=f"agent-install-skill-{skill_name}-") as tmp:
        tmp_path = Path(tmp)
        proc = run_sophhub_download(skill_name, tmp_path)

        downloaded_dir = tmp_path / skill_name
        if proc.returncode != 0:
            return {
                "name": skill_name,
                "ok": False,
                "reason": "download_failed",
                "returncode": proc.returncode,
                "stdout": proc.stdout.strip(),
                "stderr": proc.stderr.strip(),
            }

        if not downloaded_dir.is_dir():
            return {
                "name": skill_name,
                "ok": False,
                "reason": "download_missing_directory",
                "expected_path": str(downloaded_dir),
                "stdout": proc.stdout.strip(),
                "stderr": proc.stderr.strip(),
            }

        skills_dir.mkdir(parents=True, exist_ok=True)
        had_existing = target_dir.exists()
        replace_skill_directory(downloaded_dir, target_dir)

        return {
            "name": skill_name,
            "ok": True,
            "target_dir": str(target_dir),
            "replaced": had_existing,
        }


def load_agent_def_for_workspace(
    workspace: Path,
    *,
    agent_id: str | None = None,
    source_path: Path | None = None,
) -> dict[str, object]:
    config_path = workspace / ".config.json"
    if config_path.is_file():
        return load_json(config_path)
    if agent_id:
        return load_agent_definition(agent_id, source_path)
    raise ValueError("workspace 下无 .config.json，请提供 --agent-id")


def install_agent_skills(
    workspace: Path,
    *,
    agent_id: str | None = None,
    source_path: Path | None = None,
) -> dict[str, object]:
    agent_def = load_agent_def_for_workspace(workspace, agent_id=agent_id, source_path=source_path)
    auto_install = get_auto_install_skills(agent_def)
    skills_dir = workspace / "skills"

    if not auto_install:
        return {
            "ok": True,
            "workspace": str(workspace),
            "skills_dir": str(skills_dir),
            "installed": [],
            "failed": [],
            "details": [],
            "message": "无 auto_install skill，跳过。",
        }

    results: list[dict[str, object]] = []
    for item in auto_install:
        skill_name = str(item["name"])
        results.append(install_single_skill(skill_name, skills_dir))

    failed = [item for item in results if not item.get("ok")]
    installed = [str(item["name"]) for item in results if item.get("ok")]

    return {
        "ok": not failed,
        "workspace": str(workspace),
        "skills_dir": str(skills_dir),
        "installed": installed,
        "failed": [
            {
                "name": str(item["name"]),
                "reason": item.get("reason"),
                "stderr": item.get("stderr"),
            }
            for item in failed
        ],
        "details": results,
        "message": (
            f"已重新安装 {len(installed)} 个 skill（直接替换目录）。"
            if not failed
            else f"{len(failed)} 个 skill 安装失败，已成功 {len(installed)} 个。"
        ),
    }


def main() -> int:
    parser = argparse.ArgumentParser(description="安装或重新安装 Agent 的 auto_install skills（直接替换目录）")
    parser.add_argument("--workspace", required=True, help="Agent workspace 路径")
    parser.add_argument("--agent-id", help="Agent ID（workspace 尚无 .config.json 时使用）")
    parser.add_argument("--source-path", help="Agent 下载目录")
    args = parser.parse_args()

    try:
        result = install_agent_skills(
            Path(args.workspace).expanduser().resolve(),
            agent_id=args.agent_id,
            source_path=Path(args.source_path).expanduser().resolve() if args.source_path else None,
        )
    except (ValueError, FileNotFoundError) as exc:
        payload = {"ok": False, "message": str(exc)}
        json.dump(payload, sys.stdout, indent=2, ensure_ascii=False)
        sys.stdout.write("\n")
        return 1

    json.dump(result, sys.stdout, indent=2, ensure_ascii=False)
    sys.stdout.write("\n")
    return 0 if result.get("ok") else 1


if __name__ == "__main__":
    raise SystemExit(main())
