import importlib.util
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch


SPEC = importlib.util.spec_from_file_location("agent", Path(__file__).with_name("agent.py"))
agent = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(agent)


VALID_SKILL = """---
name: "测试Skill"
description: "当用户说“测试Skill”“生成测试技能”“评测测试技能”时使用。用于验证 Skill 工具链。"
---

# 测试Skill

## 角色
你是测试专家。

## 工作流
1. 读取输入。
2. 输出结果。

## 输出格式
使用结构化中文输出。
"""


class NativeAgentToolTests(unittest.TestCase):
    def test_fs_search_finds_filename_and_content_matches(self):
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            (root / "alpha.txt").write_text("hello skill agent\n", encoding="utf-8")
            (root / "beta.md").write_text("unrelated\n", encoding="utf-8")

            result = agent.tool_fs_search({
                "path": str(root),
                "query": "skill",
                "includeContent": True,
                "maxResults": 10,
            })

            self.assertTrue(result["ok"])
            self.assertEqual(result["count"], 1)
            self.assertEqual(result["matches"][0]["name"], "alpha.txt")
            self.assertIn("skill", result["matches"][0]["snippet"])

    def test_skill_validate_scores_valid_skill(self):
        result = agent.tool_skill_validate({"content": VALID_SKILL})

        self.assertTrue(result["ok"])
        self.assertEqual(result["frontmatter"]["name"], "测试Skill")
        self.assertGreaterEqual(result["score"], 80)
        self.assertFalse(result["errors"])

    def test_skill_write_creates_skill_markdown(self):
        with tempfile.TemporaryDirectory() as tmp:
            result = agent.tool_skill_write({
                "skillsDir": tmp,
                "name": "测试Skill",
                "content": VALID_SKILL,
            })

            path = Path(result["path"])
            self.assertTrue(result["ok"])
            self.assertTrue(path.exists())
            self.assertEqual(path.name, "测试Skill.md")
            self.assertIn("测试Skill", path.read_text(encoding="utf-8"))

    def test_skill_evaluate_returns_trigger_checks(self):
        result = agent.tool_skill_evaluate({
            "content": VALID_SKILL,
            "positivePrompts": ["帮我生成测试技能", "评测测试技能"],
            "negativePrompts": ["帮我写一份采购合同"],
        })

        self.assertTrue(result["ok"])
        self.assertEqual(result["positiveHitRate"], 1)
        self.assertEqual(result["negativeFalsePositiveRate"], 0)

    def test_checkpoint_restore_recovers_modified_file(self):
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            old_checkpoint_root = agent.CHECKPOINT_ROOT
            agent.CHECKPOINT_ROOT = root / "checkpoints"
            try:
                target = root / "data.txt"
                target.write_text("before", encoding="utf-8")

                checkpoint = agent.tool_checkpoint_create({
                    "paths": [str(target)],
                    "label": "test checkpoint",
                })
                target.write_text("after", encoding="utf-8")

                restored = agent.tool_checkpoint_restore({
                    "id": checkpoint["id"],
                    "confirm": True,
                })

                self.assertTrue(restored["ok"])
                self.assertEqual(target.read_text(encoding="utf-8"), "before")
            finally:
                agent.CHECKPOINT_ROOT = old_checkpoint_root

    def test_checkpoint_restore_removes_new_file_when_original_missing(self):
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            old_checkpoint_root = agent.CHECKPOINT_ROOT
            agent.CHECKPOINT_ROOT = root / "checkpoints"
            try:
                target = root / "new.txt"
                checkpoint = agent.tool_checkpoint_create({
                    "paths": [str(target)],
                    "label": "missing file",
                })
                target.write_text("created later", encoding="utf-8")

                restored = agent.tool_checkpoint_restore({
                    "id": checkpoint["id"],
                    "confirm": True,
                })

                self.assertTrue(restored["ok"])
                self.assertFalse(target.exists())
            finally:
                agent.CHECKPOINT_ROOT = old_checkpoint_root

    def test_fs_delete_requires_confirm_and_dry_run_false(self):
        with tempfile.TemporaryDirectory() as tmp:
            target = Path(tmp) / "danger.txt"
            target.write_text("keep me", encoding="utf-8")

            missing_confirm = agent.tool_fs_delete({
                "path": str(target),
                "dryRun": False,
            })

            self.assertTrue(missing_confirm["ok"])
            self.assertTrue(missing_confirm["dryRun"])
            self.assertTrue(target.exists())

            missing_dry_run_false = agent.tool_fs_delete({
                "path": str(target),
                "confirm": True,
            })

            self.assertTrue(missing_dry_run_false["ok"])
            self.assertTrue(missing_dry_run_false["dryRun"])
            self.assertTrue(target.exists())

            deleted = agent.tool_fs_delete({
                "path": str(target),
                "dryRun": False,
                "confirm": True,
            })

            self.assertTrue(deleted["ok"])
            self.assertTrue(deleted["deleted"])
            self.assertFalse(target.exists())

    def test_skill_benchmark_scores_multiple_skills(self):
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            (root / "测试Skill.md").write_text(VALID_SKILL, encoding="utf-8")
            (root / "坏Skill.md").write_text("# 没有 frontmatter\n\n只有正文", encoding="utf-8")

            result = agent.tool_skill_benchmark({
                "skillsDir": str(root),
                "positivePrompts": ["帮我生成测试技能", "评测测试技能"],
                "negativePrompts": ["帮我写采购合同"],
                "minScore": 70,
            })

            self.assertTrue(result["ok"])
            self.assertEqual(result["count"], 2)
            self.assertEqual(result["passed"], 1)
            self.assertEqual(result["failed"], 1)
            self.assertIn("avgScore", result)
            self.assertEqual(result["items"][0]["name"], "测试Skill")
            self.assertGreaterEqual(result["items"][0]["score"], 70)

    def test_cloudflare_pages_deploy_writes_index_and_extracts_url(self):
        class Proc:
            def __init__(self, returncode=0, stdout="", stderr=""):
                self.returncode = returncode
                self.stdout = stdout
                self.stderr = stderr

        calls = []

        def fake_run(command, **kwargs):
            calls.append((command, kwargs))
            if command[-1] == "whoami":
                return Proc(stdout="You are logged in")
            if command[:5] == ["npx", "--yes", "wrangler", "pages", "project"]:
                return Proc(stdout="Project created")
            if command[:5] == ["npx", "--yes", "wrangler", "pages", "deploy"]:
                return Proc(stdout="Deployment complete: https://aipros-demo.pages.dev")
            return Proc()

        with tempfile.TemporaryDirectory() as tmp, patch.object(agent.subprocess, "run", side_effect=fake_run):
            result = agent.tool_cloudflare_pages_deploy({
                "outputDir": tmp,
                "projectName": "AIPROS 演示页",
                "filename": "演示.html",
                "content": "<!doctype html><html><body>ok</body></html>",
            })

            self.assertTrue(result["ok"])
            self.assertEqual(result["projectName"], "aipros")
            self.assertEqual(result["url"], "https://aipros-demo.pages.dev")
            self.assertTrue(Path(result["indexPath"]).exists())
            self.assertEqual(Path(result["indexPath"]).read_text(encoding="utf-8"), "<!doctype html><html><body>ok</body></html>")
            self.assertEqual(calls[-1][0][0:5], ["npx", "--yes", "wrangler", "pages", "deploy"])

    def test_cloudflare_pages_deploy_reports_auth_failure(self):
        class Proc:
            returncode = 1
            stdout = ""
            stderr = "not authenticated"

        with tempfile.TemporaryDirectory() as tmp, patch.object(agent.subprocess, "run", return_value=Proc()):
            result = agent.tool_cloudflare_pages_deploy({
                "outputDir": tmp,
                "projectName": "demo",
                "filename": "index.html",
                "content": "<html></html>",
            })

            self.assertFalse(result["ok"])
            self.assertEqual(result["stage"], "auth")
            self.assertIn("Cloudflare", result["error"])


if __name__ == "__main__":
    unittest.main()
