from pathlib import Path
from tempfile import TemporaryDirectory
import unittest

from unittest.mock import patch

from agentic_toolbelt.cli import copy_payload, main


class CliTests(unittest.TestCase):
    def test_copy_payload_to_empty_directory(self):
        with TemporaryDirectory() as tmp:
            destination = Path(tmp)
            copied, skipped = copy_payload(destination)

            self.assertEqual(skipped, [])
            self.assertEqual(
                set(copied),
                {
                    ".agents",
                    ".codex",
                    ".codex/agents",
                    ".codex/config.toml",
                    ".github",
                    ".tasks",
                    "templates",
                    "AGENTS.md",
                },
            )
            self.assertTrue((destination / ".agents" / "ralph" / "agents.sh").is_file())
            self.assertTrue((destination / ".codex" / "skills" / "commit" / "SKILL.md").is_file())
            self.assertTrue((destination / ".codex" / "config.toml").is_file())
            self.assertTrue((destination / ".codex" / "agents" / "planner.toml").is_file())
            self.assertTrue((destination / ".agents" / "skills" / "task-breakdown" / "assets" / "task.template.json").is_file())
            self.assertTrue((destination / ".tasks" / "README.md").is_file())
            self.assertTrue((destination / "templates" / "codex" / "routing-profiles.toml").is_file())
            self.assertTrue((destination / "AGENTS.md").is_file())

    def test_copy_payload_skips_existing_without_force(self):
        with TemporaryDirectory() as tmp:
            destination = Path(tmp)
            existing_agents = destination / "AGENTS.md"
            existing_agents.write_text("custom\n", encoding="utf-8")
            existing_config = destination / ".codex" / "config.toml"
            existing_config.parent.mkdir(parents=True)
            existing_config.write_text("custom = true\n", encoding="utf-8")
            existing_runtime_agents = destination / ".codex" / "agents"
            existing_runtime_agents.mkdir(parents=True, exist_ok=True)
            sentinel_agent = existing_runtime_agents / "local-only.toml"
            sentinel_agent.write_text("custom = true\n", encoding="utf-8")

            copied, skipped = copy_payload(destination)

            self.assertIn("AGENTS.md", skipped)
            self.assertIn(".codex/config.toml", skipped)
            self.assertIn(".codex/agents", skipped)
            self.assertNotIn("AGENTS.md", copied)
            self.assertNotIn(".codex/config.toml", copied)
            self.assertNotIn(".codex/agents", copied)
            self.assertEqual(existing_agents.read_text(encoding="utf-8"), "custom\n")
            self.assertEqual(existing_config.read_text(encoding="utf-8"), "custom = true\n")
            self.assertEqual(sentinel_agent.read_text(encoding="utf-8"), "custom = true\n")

    def test_copy_payload_overwrites_when_force_enabled(self):
        with TemporaryDirectory() as tmp:
            destination = Path(tmp)
            existing_agents = destination / "AGENTS.md"
            existing_agents.write_text("custom\n", encoding="utf-8")
            existing_config = destination / ".codex" / "config.toml"
            existing_config.parent.mkdir(parents=True)
            existing_config.write_text("custom = true\n", encoding="utf-8")
            existing_runtime_agents = destination / ".codex" / "agents"
            existing_runtime_agents.mkdir(parents=True, exist_ok=True)
            sentinel_agent = existing_runtime_agents / "local-only.toml"
            sentinel_agent.write_text("custom = true\n", encoding="utf-8")

            copied, skipped = copy_payload(destination, force=True)

            self.assertEqual(skipped, [])
            self.assertIn("AGENTS.md", copied)
            self.assertIn(".codex/config.toml", copied)
            self.assertIn(".codex/agents", copied)
            self.assertTrue(existing_agents.read_text(encoding="utf-8").startswith("# AGENTS.md"))
            self.assertIn("[agents]", existing_config.read_text(encoding="utf-8"))
            self.assertFalse(sentinel_agent.exists())
            self.assertTrue((destination / ".codex" / "agents" / "implementer.toml").is_file())

    def test_copy_payload_does_not_touch_existing_repo_temp_directory(self):
        with TemporaryDirectory() as tmp:
            destination = Path(tmp)
            sentinel_dir = destination / ".agentic_set_tmp"
            sentinel_dir.mkdir()
            sentinel_file = sentinel_dir / "keep.txt"
            sentinel_file.write_text("preserve me\n", encoding="utf-8")

            copy_payload(destination)

            self.assertTrue(sentinel_dir.is_dir())
            self.assertEqual(sentinel_file.read_text(encoding="utf-8"), "preserve me\n")

    def test_main_copies_into_current_directory(self):
        with TemporaryDirectory() as tmp:
            with patch("agentic_toolbelt.cli.Path.cwd", return_value=Path(tmp)):
                exit_code = main([])

            self.assertEqual(exit_code, 0)
            self.assertTrue((Path(tmp) / "AGENTS.md").is_file())
            self.assertTrue((Path(tmp) / ".codex" / "config.toml").is_file())

    def test_main_recovers_from_partial_destination(self):
        with TemporaryDirectory() as tmp:
            smoke_root = Path(tmp) / ".agents"
            smoke_root.mkdir()
            (smoke_root / "ralph").mkdir()
            (smoke_root / "ralph" / "README.md").write_text("stale", encoding="utf-8")

            with patch("agentic_toolbelt.cli.Path.cwd", return_value=Path(tmp)):
                exit_code = main(["--force"])

            self.assertEqual(exit_code, 0)
            self.assertTrue((Path(tmp) / ".agents" / "ralph" / "agents.sh").is_file())
            self.assertTrue((Path(tmp) / ".codex" / "skills" / "commit" / "SKILL.md").is_file())
            self.assertTrue((Path(tmp) / ".codex" / "config.toml").is_file())
            self.assertTrue((Path(tmp) / ".codex" / "agents" / "implementer.toml").is_file())

    def test_copy_payload_rejects_incomplete_installed_payload(self):
        with TemporaryDirectory() as package_tmp, TemporaryDirectory() as destination_tmp:
            package_root = Path(package_tmp)
            (package_root / ".agents" / "ralph").mkdir(parents=True)
            (package_root / ".codex" / "skills").mkdir(parents=True)
            (package_root / ".github").mkdir()
            (package_root / "templates").mkdir()
            (package_root / "AGENTS.md").write_text("# AGENTS.md\n", encoding="utf-8")

            with patch("agentic_toolbelt.cli.resources.files", return_value=package_root):
                with self.assertRaises(FileNotFoundError) as ctx:
                    copy_payload(Path(destination_tmp))

            self.assertIn("missing packaged path '.agents/skills'", str(ctx.exception))


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