"""Skill management CLI commands"""

import asyncio
import os
from typing import TYPE_CHECKING, Optional

import typer
from rich import print as rprint
from rich.table import Table

if TYPE_CHECKING:
    from agentkit.evolution.experience_store import ExperienceStore
    from agentkit.evolution.risk_guard_learner import RiskGuardLearner

skill_app = typer.Typer(name="skill", help="Skill management commands", no_args_is_help=True)


@skill_app.command("list")
def list_skills(
    server_url: Optional[str] = typer.Option(None, "--server-url", help="AgentKit server URL"),
):
    """List registered skills"""
    if server_url:
        # Remote mode: call API
        import httpx

        try:
            with httpx.Client(timeout=10.0) as client:
                response = client.get(f"{server_url}/api/v1/skills")
                response.raise_for_status()
                skills = response.json()
        except Exception as e:
            rprint(f"[red]Error connecting to server: {e}[/red]")
            raise typer.Exit(code=1)
    else:
        # Local mode: use SkillRegistry directly, loading from default configs/skills/
        from agentkit.skills.loader import SkillLoader
        from agentkit.skills.registry import SkillRegistry
        from agentkit.tools.registry import ToolRegistry

        registry = SkillRegistry()
        # Load skills from the default configs/skills/ directory if it exists
        default_skills_dir = os.path.join(
            os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "configs", "skills"
        )
        if os.path.isdir(default_skills_dir):
            loader = SkillLoader(registry, ToolRegistry())
            loader.load_from_directory(default_skills_dir)
        skills = [
            {
                "name": s.name,
                "agent_type": s.config.agent_type,
                "version": s.config.version,
                "description": s.config.description,
            }
            for s in registry.list_skills()
        ]

    if not skills:
        rprint("[dim]No skills registered[/dim]")
        return

    table = Table(title="Skills")
    table.add_column("Name", style="cyan")
    table.add_column("Type")
    table.add_column("Description")
    for s in skills:
        table.add_row(
            s.get("name", ""),
            s.get("agent_type", ""),
            s.get("description", ""),
        )
    rprint(table)


@skill_app.command("load")
def load_skill(
    path: str = typer.Argument(help="Path to skill YAML file"),
):
    """Load a skill from YAML file"""
    if not os.path.exists(path):
        rprint(f"[red]Error: File not found: {path}[/red]")
        raise typer.Exit(code=1)

    try:
        from agentkit.skills.loader import SkillLoader
        from agentkit.skills.registry import SkillRegistry
        from agentkit.tools.registry import ToolRegistry

        registry = SkillRegistry()
        loader = SkillLoader(registry, ToolRegistry())
        skill = loader.load_from_file(path)
        rprint(f"[green]Skill loaded:[/green] {skill.name}")
        rprint(f"  Description: {skill.config.description}")
        rprint(f"  Mode: {skill.config.task_mode}")
    except Exception as e:
        rprint(f"[red]Error loading skill: {e}[/red]")
        raise typer.Exit(code=1)


@skill_app.command("create")
def skill_create(
    name: str = typer.Argument(..., help="Skill name"),
    output_dir: Optional[str] = typer.Option(".", "--output-dir", "-o", help="Output directory"),
):
    """Create a new SKILL.md template"""
    template = f'''---
name: {name}
description: "Description of {name}"
agent_type: {name}
execution_mode: react
intent:
  keywords: ["{name}"]
  description: "Tasks related to {name}"
quality_gate:
  required_fields: []
  min_word_count: 0
---

# Trigger
- When to use this skill

# Steps
1. Step one
2. Step two
3. Step three

# Pitfalls
- Common mistakes to avoid

# Verification
- How to verify the output
'''
    output_path = os.path.join(output_dir, f"{name}.md")
    os.makedirs(output_dir, exist_ok=True)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(template)
    rprint(f"[green]Created SKILL.md template:[/green] {output_path}")


@skill_app.command("info")
def skill_info(
    name: str = typer.Argument(help="Skill name"),
    server_url: Optional[str] = typer.Option(None, "--server-url", help="AgentKit server URL"),
):
    """Show skill details"""
    if server_url:
        import httpx

        try:
            with httpx.Client(timeout=10.0) as client:
                response = client.get(f"{server_url}/api/v1/skills/{name}")
                response.raise_for_status()
                info = response.json()
        except Exception as e:
            rprint(f"[red]Error: {e}[/red]")
            raise typer.Exit(code=1)
    else:
        from agentkit.skills.registry import SkillRegistry

        registry = SkillRegistry()
        try:
            skill = registry.get(name)
            info = {
                "name": skill.name,
                "agent_type": skill.config.agent_type,
                "version": skill.config.version,
                "description": skill.config.description,
                "task_mode": skill.config.task_mode,
                "execution_mode": skill.config.execution_mode,
            }
        except Exception as e:
            rprint(f"[red]Skill '{name}' not found: {e}[/red]")
            raise typer.Exit(code=1)

    table = Table(title=f"Skill: {name}")
    table.add_column("Field", style="cyan")
    table.add_column("Value")
    for key, value in info.items():
        table.add_row(key, str(value))
    rprint(table)


@skill_app.command("learn-risk-guards")
def learn_risk_guards(
    skill: Optional[str] = typer.Option(None, "--skill", help="限定只分析该 skill 的失败轨迹"),
    top_k: int = typer.Option(20, "--top-k", help="检索失败轨迹的最大数量"),
    server_url: Optional[str] = typer.Option(None, "--server-url", help="AgentKit server URL"),
):
    """从失败轨迹学习风险守卫建议（不自动应用，需人工审查）

    v7: 借鉴 SkillHarness 论文风险守卫 R 概念，分析失败轨迹生成 preconditions 候选。
    输出仅供人工审查，不会自动修改任何 YAML。
    """
    if server_url:
        rprint("[yellow]远程模式暂不支持 learn-risk-guards，请使用本地模式[/yellow]")
        raise typer.Exit(code=1)

    learner = _build_risk_guard_learner()
    if learner is None:
        raise typer.Exit(code=1)

    suggestions = asyncio.run(learner.learn(skill_name=skill, top_k=top_k))
    _render_risk_guard_suggestions(suggestions)


def _build_risk_guard_learner() -> "RiskGuardLearner | None":
    """从本地配置构建 RiskGuardLearner，失败返回 None 并打印真实错误"""
    from agentkit.cli.chat import _build_gateway
    from agentkit.evolution.risk_guard_learner import RiskGuardLearner
    from agentkit.server.config import find_config_path, load_config_with_dotenv

    config_path = find_config_path()
    if config_path is None:
        rprint("[red]Error: 未找到 agentkit.yaml 配置文件。[/red]")
        rprint("[dim]请运行 `agentkit init` 生成配置，或使用 --config 指定路径。[/dim]")
        return None

    try:
        server_config = load_config_with_dotenv(config_path)
    except Exception as e:
        rprint(f"[red]Error: 加载配置失败: {e}[/red]")
        return None

    try:
        gateway = _build_gateway(server_config)
    except Exception as e:
        rprint(f"[red]Error: 构建 LLM Gateway 失败: {e}[/red]")
        rprint("[dim]请检查 agentkit.yaml 中的 llm 配置（providers + api_key）。[/dim]")
        return None

    experience_store = _try_get_experience_store(server_config)
    if experience_store is None:
        rprint("[red]Error: 无法连接 PostgreSQL ExperienceStore。[/red]")
        rprint(
            "[dim]请在 agentkit.yaml 的 evolution.database_url 或 "
            "memory.episodic.database_url 中配置 PostgreSQL 连接串，"
            "或设置 DATABASE_URL 环境变量。[/dim]"
        )
        return None

    return RiskGuardLearner(experience_store, gateway)


def _try_get_experience_store(server_config) -> "ExperienceStore | None":
    """尝试从 server_config 构建 PostgreSQL ExperienceStore，不可用时返回 None

    查找 database_url 的优先级：
    1. server_config.evolution.database_url
    2. server_config.memory.episodic.database_url
    3. DATABASE_URL 环境变量
    """
    import os

    database_url: str | None = None

    # 1. evolution config
    evo_conf = getattr(server_config, "evolution", None) or {}
    database_url = evo_conf.get("database_url") if isinstance(evo_conf, dict) else None

    # 2. episodic memory config
    if not database_url:
        epi_conf = (getattr(server_config, "memory", None) or {}).get("episodic", {})
        database_url = epi_conf.get("database_url") if isinstance(epi_conf, dict) else None

    # 3. env var
    if not database_url:
        database_url = os.environ.get("DATABASE_URL")

    if not database_url:
        return None

    try:
        from agentkit.evolution.experience_store import ExperienceStore
        from agentkit.memory.models import ExperienceModel, create_experience_session_factory

        session_factory = create_experience_session_factory(database_url)
        return ExperienceStore(
            session_factory=session_factory,
            experience_model=ExperienceModel,
        )
    except Exception as e:
        import logging

        logging.getLogger(__name__).warning(f"Failed to create PostgreSQL ExperienceStore: {e}")
        return None


def _render_risk_guard_suggestions(suggestions: list) -> None:
    """渲染 RiskGuardSuggestion 列表到终端"""
    if not suggestions:
        rprint("[dim]未从失败轨迹中学习到风险守卫建议[/dim]")
        return

    rprint(
        "[bold yellow]⚠ 以下为自动生成的风险守卫建议，"
        "必须人工审查后手动编辑 YAML 应用，不会自动生效。[/bold yellow]\n"
    )
    table = Table(title="Risk Guard Suggestions (待人工审查)")
    table.add_column("Skill", style="cyan")
    table.add_column("Precondition")
    table.add_column("Confidence", justify="right")
    table.add_column("Reason")
    for s in suggestions:
        table.add_row(
            s.skill_name,
            s.precondition,
            f"{s.confidence:.2f}",
            s.reason,
        )
    rprint(table)
