import unittest
from pathlib import Path

from gzkit.cli import main
from tests.commands.common import CliRunner, _quick_init


class TestSpecifyCommand(unittest.TestCase):
    """Tests for gz specify command."""

    def test_specify_creates_obpi_file(self) -> None:
        """specify creates OBPI file."""
        runner = CliRunner()
        with runner.isolated_filesystem():
            _quick_init()
            runner.invoke(main, ["plan", "create", "f", "--kind", "feature"])
            result = runner.invoke(
                main, ["specify", "core-feature", "--parent", "ADR-0.1.0-f", "--item", "1"]
            )
            self.assertEqual(result.exit_code, 0)
            obpi_path = Path(
                "design/adr/pre-release/ADR-0.1.0-f/obpis/OBPI-0.1.0-01-core-feature.md"
            )
            self.assertTrue(obpi_path.exists())
            content = obpi_path.read_text(encoding="utf-8")
            self.assertIn('Checklist Item:** #1 - "OBPI-0.1.0-01:', content)
            self.assertNotIn('Checklist Item:** #1 - "TBD"', content)

    def test_specify_rejects_pool_parent(self) -> None:
        """specify blocks pool ADR parents until promotion."""
        runner = CliRunner()
        with runner.isolated_filesystem():
            _quick_init()
            result = runner.invoke(
                main,
                ["specify", "core-feature", "--parent", "ADR-pool.sample", "--item", "1"],
            )
            self.assertNotEqual(result.exit_code, 0)
            self.assertIn("Pool ADRs cannot receive OBPIs until promoted", result.output)

    def test_specify_rejects_out_of_range_item(self) -> None:
        """specify rejects checklist item numbers outside scorecard-backed checklist range."""
        runner = CliRunner()
        with runner.isolated_filesystem():
            _quick_init()
            runner.invoke(main, ["plan", "create", "f", "--kind", "feature"])
            result = runner.invoke(
                main, ["specify", "core-feature", "--parent", "ADR-0.1.0-f", "--item", "2"]
            )
            self.assertNotEqual(result.exit_code, 0)
            self.assertIn("out of range", result.output)

    def test_specify_ignores_withdrawn_checklist_items_for_live_target(self) -> None:
        """Withdrawn checklist identities remain addressable history, not live target count."""
        runner = CliRunner()
        with runner.isolated_filesystem():
            _quick_init()
            runner.invoke(main, ["plan", "create", "f", "--kind", "feature"])
            adr_path = Path("design/adr/pre-release/ADR-0.1.0-f/ADR-0.1.0-f.md")
            content = adr_path.read_text(encoding="utf-8")
            content = content.replace(
                "- [ ] OBPI-0.1.0-01: Define scope, constraints, and acceptance criteria",
                "\n".join(
                    [
                        "- [ ] OBPI-0.1.0-01: Define scope, constraints, and acceptance criteria",
                        "- [ ] OBPI-0.1.0-02: Superseded historical slot "
                        "[withdrawn; replaced by OBPI-0.1.0-03]",
                    ]
                ),
            )
            adr_path.write_text(content, encoding="utf-8")

            live_result = runner.invoke(
                main, ["specify", "core-feature", "--parent", "ADR-0.1.0-f", "--item", "1"]
            )
            self.assertEqual(live_result.exit_code, 0)

            withdrawn_result = runner.invoke(
                main, ["specify", "old-feature", "--parent", "ADR-0.1.0-f", "--item", "2"]
            )
            self.assertNotEqual(withdrawn_result.exit_code, 0)
            self.assertIn("withdrawn", withdrawn_result.output)

    def test_specify_warns_about_template_defaults(self) -> None:
        """specify reports ADR-derived seeding and avoids scaffold placeholders."""
        runner = CliRunner()
        with runner.isolated_filesystem():
            _quick_init()
            runner.invoke(main, ["plan", "create", "f", "--kind", "feature"])
            result = runner.invoke(
                main, ["specify", "core-feature", "--parent", "ADR-0.1.0-f", "--item", "1"]
            )
            self.assertEqual(result.exit_code, 0)
            self.assertIn("populated from ADR content", result.output)
            self.assertIn("Review allowed paths", result.output)
            obpi_path = Path(
                "design/adr/pre-release/ADR-0.1.0-f/obpis/OBPI-0.1.0-01-core-feature.md"
            )
            content = obpi_path.read_text(encoding="utf-8")
            self.assertNotIn("command --to --verify", content)
            self.assertNotIn("path/to/prerequisite", content)
            self.assertNotIn("Given/When/Then behavior criterion", content)

    def test_specify_author_creates_authored_ready_brief(self) -> None:
        """specify --author produces a brief that passes authored validation."""
        runner = CliRunner()
        with runner.isolated_filesystem():
            _quick_init()
            runner.invoke(main, ["plan", "create", "f", "--kind", "feature"])
            result = runner.invoke(
                main,
                ["specify", "core-feature", "--parent", "ADR-0.1.0-f", "--item", "1", "--author"],
            )
            self.assertEqual(result.exit_code, 0)
            self.assertIn("validated for pipeline entry", result.output)

            obpi_path = Path(
                "design/adr/pre-release/ADR-0.1.0-f/obpis/OBPI-0.1.0-01-core-feature.md"
            )
            content = obpi_path.read_text(encoding="utf-8")
            self.assertNotIn("<!--", content)

            validate_result = runner.invoke(
                main,
                ["obpi", "validate", str(obpi_path), "--authored"],
            )
            self.assertEqual(validate_result.exit_code, 0)
