"""Tests for live PR head re-pin before conflict-fix classification (#522)."""

from __future__ import annotations

import unittest

from conflict_fix_classification import (
    CLASSIFICATION_CONFLICT_FIX_NEEDED,
    CLASSIFICATION_INCOMPLETE,
    CLASSIFICATION_LIVE_MERGEABLE,
    CLASSIFICATION_STALE_INVENTORY_SKIP,
    assess_conflict_fix_classification,
    assess_conflict_fix_classification_final_report,
)


def _sha(prefix: str) -> str:
    return (prefix + "0" * 40)[:40]


class TestConflictFixClassification(unittest.TestCase):
    def test_stale_inventory_mergeable_skip(self):
        """PR #508 style: inventory mergeable:false/stale head, live mergeable:true."""
        result = assess_conflict_fix_classification(
            pr_number=508,
            inventory_head_sha=_sha("dad1dc8"),
            inventory_mergeable=False,
            live_head_sha=_sha("3f3d6cb"),
            live_mergeable=True,
        )
        self.assertEqual(result["classification"], CLASSIFICATION_STALE_INVENTORY_SKIP)
        self.assertTrue(result["skip_author_mutation"])
        self.assertFalse(result["worktree_allowed"])
        self.assertTrue(result["inventory_stale_head"])
        self.assertTrue(result["inventory_stale_mergeable"])
        self.assertEqual(result["pinned_head_sha"], _sha("3f3d6cb"))

    def test_stale_inventory_head_only_live_mergeable_true(self):
        """PR #493 style: head moved; live still mergeable."""
        result = assess_conflict_fix_classification(
            pr_number=493,
            inventory_head_sha=_sha("685e627"),
            inventory_mergeable=True,
            live_head_sha=_sha("4561d7a"),
            live_mergeable=True,
        )
        self.assertEqual(result["classification"], CLASSIFICATION_STALE_INVENTORY_SKIP)
        self.assertTrue(result["skip_author_mutation"])
        self.assertFalse(result["worktree_allowed"])
        self.assertTrue(result["inventory_stale_head"])
        self.assertEqual(result["pinned_head_sha"], _sha("4561d7a"))

    def test_live_conflict_allows_worktree_on_pinned_head(self):
        result = assess_conflict_fix_classification(
            pr_number=99,
            inventory_head_sha=_sha("aaaaaaa"),
            inventory_mergeable=False,
            live_head_sha=_sha("bbbbbbb"),
            live_mergeable=False,
        )
        self.assertEqual(result["classification"], CLASSIFICATION_CONFLICT_FIX_NEEDED)
        self.assertTrue(result["worktree_allowed"])
        self.assertFalse(result["skip_author_mutation"])
        self.assertTrue(result["inventory_stale_head"])
        self.assertEqual(result["pinned_head_sha"], _sha("bbbbbbb"))

    def test_matching_inventory_live_mergeable_skip(self):
        head = _sha("cccccccc")
        result = assess_conflict_fix_classification(
            pr_number=10,
            inventory_head_sha=head,
            inventory_mergeable=True,
            live_head_sha=head,
            live_mergeable=True,
        )
        self.assertEqual(result["classification"], CLASSIFICATION_LIVE_MERGEABLE)
        self.assertFalse(result["worktree_allowed"])
        self.assertTrue(result["skip_author_mutation"])
        self.assertFalse(result["inventory_stale_head"])

    def test_missing_live_head_incomplete(self):
        result = assess_conflict_fix_classification(
            pr_number=1,
            inventory_head_sha=_sha("ddddddd"),
            inventory_mergeable=False,
            live_head_sha=None,
            live_mergeable=False,
        )
        self.assertEqual(result["classification"], CLASSIFICATION_INCOMPLETE)
        self.assertFalse(result["worktree_allowed"])
        self.assertTrue(result["skip_author_mutation"])
        self.assertTrue(any("live PR head" in r for r in result["reasons"]))

    def test_short_sha_rejected(self):
        result = assess_conflict_fix_classification(
            pr_number=1,
            inventory_head_sha="abc1234",
            inventory_mergeable=False,
            live_head_sha="def5678",
            live_mergeable=False,
        )
        self.assertEqual(result["classification"], CLASSIFICATION_INCOMPLETE)
        self.assertFalse(result["worktree_allowed"])


class TestConflictFixClassificationFinalReport(unittest.TestCase):
    def test_non_conflict_report_not_applicable(self):
        result = assess_conflict_fix_classification_final_report(
            "Implemented feature without merge issues."
        )
        self.assertTrue(result["proven"])
        self.assertFalse(result["applicable"])

    def test_conflict_report_requires_tool_live_head_classification(self):
        result = assess_conflict_fix_classification_final_report(
            "Did conflict-fix work on PR #99."
        )
        self.assertFalse(result["proven"])
        self.assertTrue(result["applicable"])
        joined = " ".join(result["reasons"])
        self.assertIn("gitea_assess_conflict_fix_classification", joined)
        self.assertIn("Live head SHA", joined)
        self.assertIn("classification", joined.lower())

    def test_good_conflict_report_passes(self):
        live = _sha("3f3d6cb")
        inv = _sha("dad1dc8")
        text = f"""
Conflict-fix classification: stale_inventory_skip
Called gitea_assess_conflict_fix_classification before worktree creation.
Inventory head SHA: {inv}
Live head SHA: {live}
Use live head only; skip author mutation.
"""
        result = assess_conflict_fix_classification_final_report(text)
        self.assertTrue(result["proven"], msg=result.get("reasons"))
        self.assertEqual(result["live_head_sha"], live)
        self.assertEqual(result["inventory_head_sha"], inv)


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