"""CLI 入口: 供 SKILL.md 通过 Bash 调用各模块。"""

from __future__ import annotations

import json
import sys
from pathlib import Path

import yaml


def cmd_execute(args: list[str]) -> None:
    """执行 prompt + test cases，输出 execution_results.json。"""
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--config", required=True)
    parsed = parser.parse_args(args)

    from promptgrad.config import load_config
    from promptgrad.executor import Executor
    from promptgrad.loader import Loader

    config = load_config(parsed.config)
    loader = Loader()
    cases = loader.load_yaml_dir(config.test_cases_dir)

    executor = Executor(
        prompt_config=config.prompt_config,
        model_config=config.model_config,
        concurrency=config.concurrency,
    )
    results = executor.run(cases)

    tmp_dir = Path(config.tmp_dir)
    tmp_dir.mkdir(parents=True, exist_ok=True)
    output_path = tmp_dir / "execution_results.json"
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(
            [
                {
                    "case_id": r.case_id,
                    "input": r.input,
                    "output": r.output,
                    "latency_ms": r.latency_ms,
                    "token_usage": r.token_usage,
                }
                for r in results
            ],
            f,
            ensure_ascii=False,
            indent=2,
        )
    print(f"Results written to {output_path}")


def cmd_evaluate(args: list[str]) -> None:
    """评估执行结果 (rule + reference)，输出 partial_eval.json。"""
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--results", required=True)
    parser.add_argument("--config", required=True)
    parsed = parser.parse_args(args)

    from promptgrad.config import load_config
    from promptgrad.evaluator import Evaluator
    from promptgrad.loader import Loader
    from promptgrad.models import ExecutionResult

    config = load_config(parsed.config)
    loader = Loader()
    cases = loader.load_yaml_dir(config.test_cases_dir)

    with open(parsed.results, "r", encoding="utf-8") as f:
        raw_results = json.load(f)
    results = [ExecutionResult(**r) for r in raw_results]

    evaluator = Evaluator(rubric=config.raw["eval_rubric"], concurrency=config.concurrency)
    eval_result = evaluator.evaluate(results, cases)

    tmp_dir = Path(config.tmp_dir)
    tmp_dir.mkdir(parents=True, exist_ok=True)
    output_path = tmp_dir / "partial_eval.json"
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(
            {
                "version": eval_result.version,
                "case_scores": [
                    {
                        "case_id": cs.case_id,
                        "scores": cs.scores,
                        "weighted_score": cs.weighted_score,
                        "critique": cs.critique,
                        "passed": cs.passed,
                    }
                    for cs in eval_result.case_scores
                ],
                "avg_score": eval_result.avg_score,
                "pass_rate": eval_result.pass_rate,
                "dimension_breakdown": eval_result.dimension_breakdown,
                "worst_dimension": eval_result.worst_dimension,
            },
            f,
            ensure_ascii=False,
            indent=2,
        )
    print(f"Eval results written to {output_path}")


def cmd_regression_check(args: list[str]) -> None:
    """回归保护检查，输出 regression_result.json。"""
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--config", required=True)
    parser.add_argument("--new-prompt-version", required=True, type=int)
    parser.add_argument("--prev-pass-rate", required=True, type=float)
    parsed = parser.parse_args(args)

    from promptgrad.config import load_config
    from promptgrad.loader import Loader
    from promptgrad.optimizer import Optimizer

    config = load_config(parsed.config)

    prompt_path = Path(config.prompts_dir) / f"v{parsed.new_prompt_version}.yaml"
    with open(prompt_path, "r", encoding="utf-8") as f:
        new_prompt = yaml.safe_load(f)

    loader = Loader()
    all_cases = loader.load_yaml_dir(config.test_cases_dir)

    # 读取上一轮评估结果获取已通过 case
    tmp_dir = Path(config.tmp_dir)
    eval_path = tmp_dir / "partial_eval.json"
    with open(eval_path, "r", encoding="utf-8") as f:
        eval_data = json.load(f)
    passed_ids = {cs["case_id"] for cs in eval_data["case_scores"] if cs["passed"]}
    passed_cases = [c for c in all_cases if c.id in passed_ids]

    optimizer = Optimizer(concurrency=config.concurrency)
    regression_passed = optimizer.regression_check(
        new_prompt=new_prompt,
        passed_cases=passed_cases,
        model_config=config.model_config,
        rubric=config.raw["eval_rubric"],
        prev_pass_rate=parsed.prev_pass_rate,
    )

    output_path = tmp_dir / "regression_result.json"
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump({"regression_passed": regression_passed}, f)
    print(f"Regression {'PASSED' if regression_passed else 'FAILED'}")


def cmd_install_skill(args: list[str]) -> None:
    """安装 SKILL.md 到 ~/.claude/skills/promptgrad/。"""
    import importlib.resources

    skills_dir = Path.home() / ".claude" / "skills" / "promptgrad"

    # 找到 SKILL.md 模板
    pkg_dir = Path(__file__).parent.parent
    skill_src = pkg_dir / "SKILL.md"
    if not skill_src.exists():
        # 可能是 pip install 的情况，从 package data 找
        try:
            ref = importlib.resources.files("promptgrad") / "skill_template.md"
            skill_content = ref.read_text(encoding="utf-8")
        except (FileNotFoundError, TypeError):
            print("Error: 找不到 SKILL.md 模板")
            sys.exit(1)
    else:
        skill_content = skill_src.read_text(encoding="utf-8")

    # 用当前 Python 解释器路径替换占位符
    python_path = sys.executable
    skill_content = skill_content.replace("{{PROMPTGRAD_PYTHON}}", python_path)

    # 写入
    skills_dir.mkdir(parents=True, exist_ok=True)
    (skills_dir / "SKILL.md").write_text(skill_content, encoding="utf-8")
    print(f"Skill installed to {skills_dir / 'SKILL.md'}")
    print(f"Python engine: {python_path}")
    print("Done! 在 Claude Code 中说 '跑 promptgrad' 即可使用。")


def cmd_uninstall_skill(args: list[str]) -> None:
    """卸载 Skill。"""
    skills_dir = Path.home() / ".claude" / "skills" / "promptgrad"
    if skills_dir.exists():
        import shutil

        shutil.rmtree(skills_dir)
        print(f"Skill removed from {skills_dir}")
    else:
        print("Skill not installed.")


def main() -> None:
    """分发子命令。"""
    if len(sys.argv) < 2:
        print("Usage: promptgrad <command> [args]")
        print("Commands: install-skill, uninstall-skill, execute, evaluate, regression-check")
        sys.exit(1)

    command = sys.argv[1]
    remaining = sys.argv[2:]

    commands = {
        "install-skill": cmd_install_skill,
        "uninstall-skill": cmd_uninstall_skill,
        "execute": cmd_execute,
        "evaluate": cmd_evaluate,
        "regression-check": cmd_regression_check,
    }

    if command not in commands:
        print(f"Unknown command: {command}")
        sys.exit(1)

    commands[command](remaining)


if __name__ == "__main__":
    main()
