"""Tests for Canonical Thread Handoff (CTH) protocol (#505)."""

from __future__ import annotations

import sys
import unittest
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

import canonical_thread_handoff as cth  # noqa: E402

REPO_ROOT = Path(__file__).resolve().parent.parent
RUNBOOK = REPO_ROOT / "docs" / "llm-workflow-runbooks.md"
PROTOCOL_DOC = REPO_ROOT / "docs" / "canonical-thread-handoff.md"
TEMPLATE = REPO_ROOT / "skills" / "llm-project-workflow/templates" / "canonical-thread-handoff.md"
REVIEW_WORKFLOW = REPO_ROOT / "skills" / "llm-project-workflow/workflows" / "review-merge-pr.md"
WORK_WORKFLOW = REPO_ROOT / "skills" / "llm-project-workflow/workflows" / "work-issue.md"
REVIEW_TEMPLATE = REPO_ROOT / "skills" / "llm-project-workflow/templates" / "review-pr.md"
START_TEMPLATE = REPO_ROOT / "skills" / "llm-project-workflow/templates" / "start-issue.md"
MERGE_TEMPLATE = REPO_ROOT / "skills" / "llm-project-workflow/templates" / "merge-pr.md"


class TestCthModule(unittest.TestCase):
    def test_defines_cth_term_and_types(self):
        self.assertEqual(cth.CTH_ABBREV, "CTH")
        self.assertIn("State Handoff", cth.CTH_TYPES)
        self.assertIn("Reviewer Handoff", cth.CTH_TYPES)
        self.assertIn("Blocker", cth.CTH_TYPES)

    def test_format_and_parse_round_trip(self):
        body = cth.format_cth_body(
            cth_type="Author Handoff",
            status="implementation_complete",
            next_owner="reviewer",
            current_blocker="none",
            decision="PR opened",
            proof="pytest passed",
            next_action="review PR #9",
            ready_to_paste_prompt="Review PR #9 for issue #5",
        )
        parsed = cth.parse_cth_comment(body)
        self.assertIsNotNone(parsed)
        self.assertEqual(parsed["cth_type"], "Author Handoff")
        self.assertEqual(parsed["fields"]["status"], "implementation_complete")
        self.assertEqual(parsed["fields"]["next owner"], "reviewer")

    def test_valid_cth_passes_assessment(self):
        body = cth.format_cth_body(
            cth_type="Reviewer Handoff",
            status="approved",
            next_owner="merger",
            current_blocker="none",
            decision="APPROVE",
            proof="review id 42",
            next_action="merge if gates pass",
            ready_to_paste_prompt="Merge PR #12 with pinned head abcdef0123456789abcdef0123456789abcdef01",
        )
        result = cth.assess_cth_comment(body)
        self.assertFalse(result["block"])
        self.assertTrue(result["valid"])

    def test_missing_fields_fail_closed(self):
        body = "## CTH: Blocker\n\nStatus: blocked\n"
        result = cth.assess_cth_comment(body)
        self.assertTrue(result["block"])
        self.assertIn("missing required fields", result["reasons"][0])

    def test_find_latest_cth_prefers_newer_comment(self):
        older = cth.format_cth_body(
            cth_type="State Handoff",
            status="old",
            next_owner="author",
            current_blocker="none",
            decision="old",
            proof="old",
            next_action="old",
            ready_to_paste_prompt="old prompt text here",
        )
        newer = cth.format_cth_body(
            cth_type="Reviewer Handoff",
            status="new",
            next_owner="merger",
            current_blocker="none",
            decision="approve",
            proof="new",
            next_action="merge",
            ready_to_paste_prompt="merge PR #3 now with pinned head",
        )
        comments = [
            {"id": 1, "created_at": "2026-07-01T10:00:00Z", "body": older},
            {"id": 2, "created_at": "2026-07-02T10:00:00Z", "body": newer},
        ]
        latest = cth.find_latest_cth(comments)
        self.assertEqual(latest["comment_id"], 2)
        self.assertEqual(latest["cth_type"], "Reviewer Handoff")

    def test_cth_does_not_replace_formal_reviews_documented_in_protocol(self):
        text = PROTOCOL_DOC.read_text(encoding="utf-8")
        self.assertIn("do not replace", text.lower())
        self.assertIn("formal Gitea review", text)

    def test_examples_cover_required_scenarios(self):
        text = PROTOCOL_DOC.read_text(encoding="utf-8")
        expected_phrases = (
            "PR approved and ready for merger",
            "request-changes back to author",
            "superseded PR closure",
            "dirty root/worktree",
            "Stale head requiring fresh review",
            "Issue implementation handoff",
        )
        for phrase in expected_phrases:
            self.assertIn(phrase, text)


class TestCthDocumentationChecks(unittest.TestCase):
    def test_runbook_references_cth_discovery_and_posting(self):
        text = RUNBOOK.read_text(encoding="utf-8")
        self.assertIn("Canonical Thread Handoff", text)
        self.assertIn("Find the latest CTH comment", text)
        self.assertIn("Post a new CTH", text)
        self.assertIn("canonical-thread-handoff.md", text)

    def test_workflows_reference_cth_rules(self):
        for path in (REVIEW_WORKFLOW, WORK_WORKFLOW):
            text = path.read_text(encoding="utf-8")
            self.assertIn("latest CTH comment", text)
            self.assertIn("canonical-thread-handoff.md", text)

    def test_prompt_templates_reference_cth_rules(self):
        for path in (REVIEW_TEMPLATE, START_TEMPLATE, MERGE_TEMPLATE, TEMPLATE):
            text = path.read_text(encoding="utf-8")
            self.assertIn("CTH", text)
            self.assertIn("canonical-thread-handoff", text)


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