"""Tests for root checkout guard (#475)."""

from __future__ import annotations

import os
import sys
import unittest
from pathlib import Path
from unittest.mock import patch

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

import gitea_mcp_server as srv  # noqa: E402
import root_checkout_guard as rcg  # noqa: E402

current_file_path = Path(__file__).resolve()
if "branches" in current_file_path.parts:
    CONTROL_ROOT = str(current_file_path.parents[3])
    BRANCHES_WORKTREE = str(current_file_path.parents[1])
else:
    CONTROL_ROOT = str(current_file_path.parents[1])
    BRANCHES_WORKTREE = str(current_file_path.parents[1] / "branches" / "mock-worktree")
MASTER_SHA = "a" * 40
OTHER_SHA = "b" * 40


class TestAssessRootCheckoutGuard(unittest.TestCase):
    def _assess(self, **kwargs):
        defaults = {
            "workspace_path": CONTROL_ROOT,
            "canonical_repo_root": CONTROL_ROOT,
            "current_branch": "master",
            "head_sha": MASTER_SHA,
            "porcelain_status": "",
            "remote_master_sha": MASTER_SHA,
            "resolved_role": "author",
        }
        defaults.update(kwargs)
        return rcg.assess_root_checkout_guard(**defaults)

    def test_clean_master_control_checkout_allowed(self):
        result = self._assess()
        self.assertTrue(result["proven"])
        self.assertFalse(result["block"])

    def test_branches_worktree_allowed_for_author(self):
        result = self._assess(
            workspace_path=BRANCHES_WORKTREE,
            current_branch="feat/issue-475-root-checkout-guard",
            head_sha=OTHER_SHA,
            resolved_role="author",
        )
        self.assertTrue(result["proven"])

    def test_branches_worktree_allowed_for_reviewer(self):
        result = self._assess(
            workspace_path=f"{CONTROL_ROOT}/branches/review-pr-1",
            current_branch="review-pr-1",
            resolved_role="reviewer",
        )
        self.assertTrue(result["proven"])

    def test_reconciler_always_allowed(self):
        result = self._assess(
            current_branch="feat/some-branch",
            head_sha=OTHER_SHA,
            porcelain_status=" M gitea_mcp_server.py\n",
            resolved_role="reconciler",
        )
        self.assertTrue(result["proven"])

    def test_feature_branch_on_control_checkout_blocked(self):
        result = self._assess(
            current_branch="feat/issue-99-example",
            head_sha=OTHER_SHA,
        )
        self.assertTrue(result["block"])
        self.assertIn("not a stable base branch", result["reasons"][0])

    def test_detached_head_blocked(self):
        result = self._assess(current_branch=None)
        self.assertTrue(result["block"])
        self.assertIn("detached HEAD", result["reasons"][0])

    def test_dirty_control_checkout_blocked(self):
        result = self._assess(porcelain_status=" M gitea_mcp_server.py\n")
        self.assertTrue(result["block"])
        self.assertIn("tracked local edits", result["reasons"][0])

    def test_head_behind_prgs_master_blocked(self):
        result = self._assess(
            head_sha=OTHER_SHA,
            remote_master_sha=MASTER_SHA,
        )
        self.assertTrue(result["block"])
        self.assertIn("does not match prgs/master", result["reasons"][0])

    def test_merger_requires_clean_control_checkout(self):
        result = self._assess(
            workspace_path=BRANCHES_WORKTREE,
            current_branch="feat/issue-475-root-checkout-guard",
            head_sha=OTHER_SHA,
            resolved_role="merger",
        )
        self.assertTrue(result["block"])


class TestVerifyPreflightRootGuardIntegration(unittest.TestCase):
    def setUp(self):
        srv._preflight_whoami_called = True
        srv._preflight_capability_called = True
        srv._preflight_resolved_role = "reviewer"
        srv._preflight_whoami_violation = False
        srv._preflight_capability_violation = False
        self._orig_in_test = srv._preflight_in_test_mode
        srv._preflight_in_test_mode = lambda: False

    def tearDown(self):
        srv._preflight_in_test_mode = self._orig_in_test

    @patch("gitea_mcp_server._get_workspace_porcelain", return_value="")
    @patch("gitea_mcp_server.root_checkout_guard.resolve_remote_master_sha", return_value=MASTER_SHA)
    @patch("gitea_mcp_server.issue_lock_worktree.read_worktree_git_state")
    @patch("gitea_mcp_server._resolve_author_mutation_context")
    def test_reviewer_from_contaminated_root_blocked(
        self, mock_ctx, mock_git, _remote_sha, _porcelain,
    ):
        srv._preflight_capability_baseline_porcelain = ""
        mock_ctx.return_value = {
            "workspace_path": CONTROL_ROOT,
            "canonical_repo_root": CONTROL_ROOT,
            "process_project_root": CONTROL_ROOT,
        }
        mock_git.return_value = {
            "current_branch": "feat/hijacked-root",
            "head_sha": OTHER_SHA,
            "porcelain_status": "",
        }
        with self.assertRaises(RuntimeError) as ctx:
            srv.verify_preflight_purity("prgs", worktree_path=CONTROL_ROOT)
        self.assertIn("Root checkout guard (#475)", str(ctx.exception))
        self.assertIn(rcg.REMEDIATION, str(ctx.exception))

    @patch("os.path.isdir", return_value=True)
    @patch("os.path.exists", return_value=True)
    @patch("subprocess.run")
    @patch("gitea_mcp_server._get_workspace_porcelain", return_value="")
    @patch("gitea_mcp_server.root_checkout_guard.resolve_remote_master_sha", return_value=MASTER_SHA)
    @patch("gitea_mcp_server.issue_lock_worktree.read_worktree_git_state")
    @patch("gitea_mcp_server._resolve_author_mutation_context")
    def test_reviewer_from_branches_worktree_allowed(
        self, mock_ctx, mock_git, _remote_sha, _porcelain, mock_run, _exists, _isdir,
    ):
        import unittest.mock
        mock_run.return_value = unittest.mock.MagicMock(
            returncode=0,
            stdout=f"{CONTROL_ROOT}/.git\n",
        )
        srv._preflight_capability_baseline_porcelain = ""
        mock_ctx.return_value = {
            "workspace_path": BRANCHES_WORKTREE,
            "canonical_repo_root": CONTROL_ROOT,
            "process_project_root": BRANCHES_WORKTREE,
        }
        mock_git.return_value = {
            "current_branch": "feat/issue-475-root-checkout-guard",
            "head_sha": OTHER_SHA,
            "porcelain_status": "",
        }
        srv.verify_preflight_purity("prgs", worktree_path=BRANCHES_WORKTREE)

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