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 PlaybookCliTests(unittest.TestCase):
    def test_help_shows_usage(self):
        result = run_cli("-h")
        self.assertEqual(result.returncode, 0)
        self.assertIn("Usage:", result.stdout + result.stderr)

    def test_record_spec_is_removed(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            progress = root / "memory-bank" / "progress.md"
            progress.parent.mkdir(parents=True)
            progress.write_text("# 当前进展\n", encoding="utf-8")

            result = run_cli(
                "-record-spec",
                "docs/superpowers/specs/2026-05-18-demo-design.md",
                "-progress",
                str(progress),
            )

            self.assertEqual(result.returncode, 2)
            self.assertIn("-record-spec has been removed", result.stderr)
            text = progress.read_text(encoding="utf-8")
            self.assertNotIn("workflow-state", text)
            self.assertNotIn("2026-05-18-demo-design.md", text)

    def test_record_plan_appends_pending_plan_status(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            progress = root / "memory-bank" / "progress.md"
            progress.parent.mkdir(parents=True)
            progress.write_text(
                "\n".join(
                    [
                        "# 当前进展",
                        "",
                        "## Plan Status",
                        "",
                        "<!-- plan-status:start -->",
                        "<!-- plan-status:end -->",
                    ]
                )
                + "\n",
                encoding="utf-8",
            )

            result = run_cli(
                "-record-plan",
                "docs/superpowers/plans/2026-05-18-demo.md",
                "-progress",
                str(progress),
            )

            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            text = progress.read_text(encoding="utf-8")
            self.assertNotIn("workflow-state", text)
            self.assertIn("- [ ] `2026-05-18-demo.md` pending", text)

    def test_record_plan_appends_pending_plan_status_after_existing_entries(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            progress = root / "memory-bank" / "progress.md"
            progress.parent.mkdir(parents=True)
            progress.write_text(
                "\n".join(
                    [
                        "# 当前进展",
                        "",
                        "## Plan Status",
                        "",
                        "<!-- plan-status:start -->",
                        "- [ ] `2026-05-18-first.md` pending",
                        "<!-- plan-status:end -->",
                    ]
                )
                + "\n",
                encoding="utf-8",
            )

            result = run_cli(
                "-record-plan",
                "docs/superpowers/plans/2026-05-18-second.md",
                "-progress",
                str(progress),
            )

            self.assertEqual(result.returncode, 0, msg=result.stdout + result.stderr)
            text = progress.read_text(encoding="utf-8")
            self.assertIn("- [ ] `2026-05-18-first.md` pending", text)
            self.assertIn("- [ ] `2026-05-18-second.md` pending", text)
            self.assertLess(
                text.index("`2026-05-18-first.md`"),
                text.index("`2026-05-18-second.md`"),
            )

    def test_missing_config_is_error(self):
        result = run_cli()
        self.assertNotEqual(result.returncode, 0)
        self.assertIn("-config", result.stdout + result.stderr)

    def test_action_order(self):
        config_body = f"""
[playbook]
project_root = "."
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[format_md]

[sync_standards]
langs = ["tsl"]
"""
        with tempfile.TemporaryDirectory() as tmp_dir:
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")
            result = run_cli("-config", str(config_path))

        self.assertEqual(result.returncode, 0)
        output = result.stdout + result.stderr
        self.assertIn("sync_standards", output)
        self.assertIn("format_md", output)

    def test_format_md_only_does_not_require_playbook_root(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"

[format_md]
"""
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

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

        self.assertEqual(result.returncode, 0)

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

[vendor]
langs = ["tsl"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

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

            self.assertNotEqual(result.returncode, 0)
            self.assertIn("[vendor]", result.stdout + result.stderr)

    def test_deploy_root_is_rejected(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
deploy_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "snapshot"

[sync_standards]
langs = ["tsl"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

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

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

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

[sync_standards]
langs = ["tsl"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

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

            snapshot = root / CUSTOM_DEPLOY_ROOT / "SOURCE.md"
            self.assertEqual(result.returncode, 0)
            self.assertTrue(snapshot.is_file())

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

[sync_standards]
langs = ["tsl"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

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

            docs_index = root / CUSTOM_DEPLOY_ROOT / "docs/index.md"
            self.assertEqual(result.returncode, 0)
            text = docs_index.read_text(encoding="utf-8")
            self.assertIn("`tsl/index.md`", text)
            self.assertIn("`tsl/syntax/index.md`", text)
            self.assertIn("`tsl/reference/catalog/datawarehouse.md`", text)
            self.assertIn("`tsl/modules/index.md`", text)
            self.assertIn("`tsl/reference/index.md`", text)
            self.assertNotIn("`tsl/syntax_book/index.md`", text)

    def test_external_clone_requires_explicit_playbook_root(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
install_mode = "snapshot"

[sync_standards]
langs = ["tsl"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

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

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

    def test_subtree_mode_requires_project_local_script(self):
        with tempfile.TemporaryDirectory() as tmp_dir:
            root = Path(tmp_dir)
            config_body = f"""
[playbook]
project_root = "{tmp_dir}"
playbook_root = "{CUSTOM_DEPLOY_ROOT}"
install_mode = "subtree"

[sync_standards]
langs = ["tsl"]
"""
            config_path = write_config(root, "playbook.toml", config_body)

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

            self.assertNotEqual(result.returncode, 0)
            self.assertIn("project-local Playbook script", result.stdout + result.stderr)

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

[sync_memory_bank]
project_name = "Demo"
"""
            config_path = Path(tmp_dir) / "playbook.toml"
            config_path.write_text(config_body, encoding="utf-8")

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

            memory_bank = Path(tmp_dir) / "memory-bank/project-brief.md"
            self.assertEqual(result.returncode, 0)
            self.assertTrue(memory_bank.is_file())

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