"""Tests for reviewer final-report schema verification (#391)."""
import sys
import unittest
from pathlib import Path

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

from review_final_report_schema import assess_review_final_report_schema  # noqa: E402


def _minimal_review_report(**overrides):
    lines = [
        "## Controller Handoff",
        "",
        "- Task: review PR #203",
        "- Repo: Scaled-Tech-Consulting/Gitea-Tools",
        "- Role: reviewer",
        "- Identity: sysadmin / prgs-reviewer",
        "- Issue/PR: #182 / PR #203",
        "- Branch/SHA: feat/x @ 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
        "- Files changed: review_proofs.py",
        "- Validation: pass: pytest tests/test_review_proofs.py -q in branches/review-203",
        "- Reviewed head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
        "- Final live head SHA before approval: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
        "- Final live head SHA before merge: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
        "- Push occurred during validation: no",
        "- Mutations: review only",
        "- File edits by reviewer: none",
        "- Worktree/index mutations: none",
        "- Git ref mutations: git fetch prgs master",
        "- MCP/Gitea mutations: review submitted",
        "- Review mutations: request_changes submitted",
        "- Merge mutations: none",
        "- Cleanup mutations: none",
        "- External-state mutations: none",
        "- Read-only diagnostics: gitea_view_pr, gitea_view_issue",
        "- Current status: PR open",
        "- Next actor: author",
        "- Next action: Fix",
        "- Next prompt: Fix",
        "- Blockers: none",
        "- Next: await author",
        "- Safety: no self-review; no self-merge",
        "- Selected PR: #203",
        "- Reviewer eligibility: eligible",
        "- Candidate head SHA: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9",
        "- Worktree path: branches/review-203",
        "- Worktree dirty: clean",
        "- Pinned reviewed head: none",
        "- Scratch worktree used: none",
        "- Unrelated local mutations: none",
        "- Review decision: request_changes",
        "- Merge result: not attempted",
        "- Linked issue: #182",
        "- Linked issue live status: open (gitea_view_issue)",
        "- Cleanup status: none",
    ]
    text = "\n".join(lines)
    for key, value in overrides.items():
        prefix = f"- {key}:"
        replaced = False
        new_lines = []
        for line in text.splitlines():
            if line.strip().startswith(prefix):
                new_lines.append(f"{prefix} {value}")
                replaced = True
            else:
                new_lines.append(line)
        text = "\n".join(new_lines)
        if not replaced:
            text += f"\n{prefix} {value}"
    return text


class TestReviewFinalReportSchema(unittest.TestCase):
    def test_clean_report_passes(self):
        result = assess_review_final_report_schema(
            _minimal_review_report(),
            linked_issue_lock={"issue_number": 182, "pr_number": 203},
        )
        self.assertFalse(result["blocked"])
        self.assertIn(result["grade"], ("A", "downgraded"))

    def test_legacy_pinned_reviewed_head_blocks(self):
        report = _minimal_review_report(**{"Pinned reviewed head": "abc123"})
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.legacy_stale_field", rule_ids)

    def test_reviewed_head_without_validation_blocks(self):
        report = _minimal_review_report().replace(
            "- Validation: pass: pytest tests/test_review_proofs.py -q in branches/review-203",
            "- Validation: not run",
        )
        report += "\n- Pinned reviewed head: 0fdc8f582026b72a229d59a172c0a63ac4aaeaf9"
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.reviewed_head_without_validation", rule_ids)

    def test_merged_without_proof_blocks(self):
        report = _minimal_review_report() + "\n\nPR #203 merged successfully."
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.merged_without_proof", rule_ids)

    def test_issue_closed_without_live_proof_blocks(self):
        report = _minimal_review_report(
            **{
                "Linked issue live status": "closed",
                "Read-only diagnostics": "gitea_view_pr only",
            }
        )
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.issue_closed_without_live_proof", rule_ids)

    def test_full_suite_pass_with_ignored_tests_blocks(self):
        report = (
            _minimal_review_report()
            + "\nFull test suite passed with 0 failed; some tests ignored."
        )
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.full_suite_pass_ignored_tests", rule_ids)

    def test_blocked_handoff_replay_blocks(self):
        report = (
            _minimal_review_report(**{"Blockers": "capability stop"})
            + "\nSafe next action: run gitea_merge_pr to finish."
        )
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.blocked_handoff_replay", rule_ids)

    def test_narrative_handoff_drift_blocks(self):
        report = (
            _minimal_review_report()
            + "\n## Summary\nVerdict: APPROVE this PR."
        )
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.narrative_handoff_drift", rule_ids)

    def test_pending_vs_approved_blocks(self):
        report = _minimal_review_report(
            **{"Review decision": "PENDING official review submitted approve"}
        )
        result = assess_review_final_report_schema(report)
        rule_ids = [f["rule_id"] for f in result["findings"]]
        self.assertIn("reviewer.pending_vs_approved", rule_ids)

    def test_exported_from_review_proofs(self):
        from review_proofs import assess_review_final_report_schema as exported

        self.assertTrue(callable(exported))


class TestMcpValidateReviewFinalReport(unittest.TestCase):
    def test_mcp_tool_callable(self):
        import gitea_mcp_server

        result = gitea_mcp_server.gitea_validate_review_final_report(
            _minimal_review_report()
        )
        self.assertIn("grade", result)
        self.assertIn("findings", result)
        self.assertFalse(result["blocked"])