import subprocess
import sys
import tempfile
import unittest
from pathlib import Path

ROOT = Path(__file__).resolve().parents[2]
SCRIPT = ROOT / "scripts" / "playbook.py"
CUSTOM_DEPLOY_ROOT = "custom/playbook"


def run_script(script, *args):
    return subprocess.run(
        [sys.executable, str(script), *args],
        capture_output=True,
        text=True,
    )


def run_cli(*args):
    return run_script(SCRIPT, *args)


def write_config(root: Path, name: str, body: str) -> Path:
    config_path = root / name
    config_path.write_text(body, encoding="utf-8")
    return config_path


class InstallSkillsTests(unittest.TestCase):
    def assert_style_cleanup_tsl_docs_prefix(
        self, root: Path, agents_home: Path, docs_prefix: str
    ) -> None:
        agents_index = (root / ".agents" / "tsl" / "index.md").read_text(
            encoding="utf-8"
        )
        self.assertIn(f"`{docs_prefix}/tsl/index.md`", agents_index)
        self.assertNotIn("`docs/tsl/index.md`", agents_index)

        skill_file = (agents_home / "skills" / "style-cleanup" / "SKILL.md").read_text(
            encoding="utf-8"
        )
        self.assertIn(f"`{docs_prefix}/tsl/code_style.md`", skill_file)
        self.assertNotIn("`docs/tsl/code_style.md`", skill_file)

    def test_install_skills(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            target = Path(tmp_dir) / "agents"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
agents_home = "{target}"
mode = "list"
skills = ["brainstorming"]
"""
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            result = run_cli("-config", str(config_path))

            skill_file = target / "skills/brainstorming/SKILL.md"
            self.assertEqual(result.returncode, 0)
            self.assertTrue(skill_file.is_file())

    def test_install_skills_installs_generated_thirdparty_skill(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            target = Path(tmp_dir) / "agents"

            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
agents_home = "{target}"
mode = "list"
skills = ["karpathy-guidelines"]
"""
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            result = run_cli("-config", str(config_path))

            skill_file = target / "skills" / "karpathy-guidelines" / "SKILL.md"
            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            self.assertTrue(skill_file.is_file())

    def test_install_skills_rejects_removed_tsl_guide(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            target = Path(tmp_dir) / "agents"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
agents_home = "{target}"
mode = "list"
skills = ["tsl-guide"]
"""
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            result = run_cli("-config", str(config_path))

            self.assertNotEqual(result.returncode, 0)
            self.assertIn("skill not found: tsl-guide", result.stdout + result.stderr)

    def test_install_skills_rejects_codex_home(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            target = Path(tmp_dir) / "codex"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
codex_home = "{target}"
mode = "list"
skills = ["brainstorming"]
"""
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            result = run_cli("-config", str(config_path))

            self.assertNotEqual(result.returncode, 0)
            self.assertIn("codex_home", result.stdout + result.stderr)

    def test_external_clone_flow_rewrites_links_with_configured_playbook_root(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            agents_home = root / "agents-home"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[sync_standards]
langs = ["tsl"]
no_backup = true

[install_skills]
agents_home = "{agents_home}"
mode = "list"
skills = ["style-cleanup"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

            result = run_cli("-config", str(config_path))

            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            self.assertTrue((root / CUSTOM_DEPLOY_ROOT / "SOURCE.md").is_file())
            self.assert_style_cleanup_tsl_docs_prefix(
                root, agents_home, f"{CUSTOM_DEPLOY_ROOT}/docs"
            )

    def test_deployed_snapshot_rewrites_links_from_snapshot_location(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            install_config = write_config(
                root,
                "install.toml",
                f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[sync_standards]
langs = ["tsl"]
""",
            )

            install_result = run_cli("-config", str(install_config))
            self.assertEqual(
                install_result.returncode,
                0,
                msg=install_result.stdout + install_result.stderr,
            )

            snapshot_script = root / CUSTOM_DEPLOY_ROOT / "scripts" / "playbook.py"
            agents_home = root / "local-agents"
            sync_config = write_config(
                root,
                "sync.toml",
                f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[sync_standards]
langs = ["tsl"]
no_backup = true

[install_skills]
agents_home = "{agents_home}"
mode = "list"
skills = ["style-cleanup"]
""",
            )

            sync_result = run_script(snapshot_script, "-config", str(sync_config))
            self.assertEqual(
                sync_result.returncode, 0, msg=sync_result.stdout + sync_result.stderr
            )
            self.assert_style_cleanup_tsl_docs_prefix(
                root, agents_home, f"{CUSTOM_DEPLOY_ROOT}/docs"
            )

    def test_install_skills_creates_symlink_when_skill_link_configured(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            agents_home = root / "agents"
            link_home = root / "claude"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
agents_home = "{agents_home}"
skill_link = "{link_home}"
mode = "list"
skills = ["commit-message"]
"""
            config_path = root / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            result = run_cli("-config", str(config_path))

            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            skills_dst = agents_home / "skills"
            link_path = link_home / "skills"
            self.assertTrue(skills_dst.is_dir())
            self.assertTrue(link_path.is_dir(), "link_path should be accessible as dir")
            self.assertEqual(link_path.resolve(), skills_dst.resolve())
            self.assertTrue((link_path / "commit-message" / "SKILL.md").is_file())

    def test_install_skills_symlink_is_idempotent(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            agents_home = root / "agents"
            link_home = root / "claude"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
agents_home = "{agents_home}"
skill_link = "{link_home}"
mode = "list"
skills = ["commit-message"]
no_backup = true
"""
            config_path = root / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            run_cli("-config", str(config_path))
            result = run_cli("-config", str(config_path))

            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            self.assertTrue((link_home / "skills").is_dir())

    def test_install_skills_no_symlink_when_skill_link_absent(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            agents_home = root / "agents"
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[install_skills]
agents_home = "{agents_home}"
mode = "list"
skills = ["commit-message"]
"""
            config_path = root / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

            result = run_cli("-config", str(config_path))

            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            self.assertFalse(
                any(
                    p.is_symlink()
                    for p in (agents_home / "skills").iterdir()
                    if p.is_symlink()
                )
                if (agents_home / "skills").exists()
                else False
            )


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