"""ORCH-110 TC-11: the local re-test necessity contract (D4 / FR-4 / AC-6).

The chosen contract: run the local re-test IFF the pre-merge rebase actually moved
HEAD (``main`` had moved -> a real semantic-conflict risk). When the rebase is a
PROVEN no-op (HEAD unchanged -> branch already at origin/main, the CI/tester/staging-
validated commit) the re-test is SKIPPED — it would be a redundant single point of
false failure. On ANY uncertainty (an empty SHA) the re-test runs (fail-safe -> the
red-rollback contract BR-6/AC-3 is never weakened).
"""
import os
import tempfile

os.environ.setdefault("ORCH_DB_PATH", os.path.join(tempfile.gettempdir(), "test_orch110_contract.db"))
os.environ.setdefault("ORCH_REPOS_DIR", tempfile.gettempdir())
os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token")
os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token")

import pytest  # noqa: E402

from src import merge_gate  # noqa: E402
from src.qg import checks as qg  # noqa: E402

_REPO = "orchestrator"
_BRANCH = "feature/ORCH-110-x"
_WI = "ORCH-110"


@pytest.fixture
def gate(monkeypatch):
    """Real check_branch_mergeable, mocked primitives; record control flow."""
    state = {"retest": 0, "released": 0, "rebased": 0}
    monkeypatch.setattr(qg.settings, "merge_gate_enabled", True, raising=False)
    monkeypatch.setattr(qg.settings, "merge_gate_repos", "", raising=False)
    monkeypatch.setattr(qg.settings, "premerge_rebase_always", True, raising=False)
    monkeypatch.setattr(qg.settings, "merge_retest_skip_when_current_enabled", True, raising=False)
    monkeypatch.setattr(merge_gate, "acquire_merge_lease", lambda *a, **k: (True, "lease acquired"))
    monkeypatch.setattr(merge_gate, "branch_is_behind_main", lambda r, b: True)

    def _rebase(r, b):
        state["rebased"] += 1
        return True, "rebased onto origin/main"

    def _release(r, b=None):
        state["released"] += 1

    def _retest(r, b):
        state["retest"] += 1
        return True, "re-test green"

    monkeypatch.setattr(merge_gate, "auto_rebase_onto_main", _rebase)
    monkeypatch.setattr(merge_gate, "release_merge_lease", _release)
    monkeypatch.setattr(merge_gate, "retest_branch", _retest)
    return state


def _set_head_shas(monkeypatch, shas):
    seq = list(shas)
    monkeypatch.setattr(merge_gate, "head_sha", lambda r, b: seq.pop(0) if seq else "")


def test_tc11_noop_rebase_skips_retest_lease_held(gate, monkeypatch):
    """Proven no-op rebase (HEAD unchanged) -> skip re-test, PASS, lease HELD."""
    _set_head_shas(monkeypatch, ["sha_same", "sha_same"])
    ok, reason = qg.check_branch_mergeable(_REPO, _WI, _BRANCH)
    assert ok is True
    assert "re-test skipped" in reason
    assert gate["retest"] == 0          # re-test NOT run
    assert gate["released"] == 0        # lease HELD until the merge


def test_tc11_head_moved_runs_retest(gate, monkeypatch):
    """A real catch-up (HEAD moved) -> re-test RUNS (the ORCH-043 risk is real)."""
    _set_head_shas(monkeypatch, ["sha_old", "sha_new"])
    ok, reason = qg.check_branch_mergeable(_REPO, _WI, _BRANCH)
    assert ok is True
    assert reason == "rebased onto main, re-test green"
    assert gate["retest"] == 1


@pytest.mark.parametrize("shas", [["", "sha_new"], ["sha_old", ""], ["", ""]])
def test_tc11_uncertain_sha_runs_retest_failsafe(gate, monkeypatch, shas):
    """Cannot prove a no-op (empty SHA) -> re-test RUNS (fail-safe, never skips on
    uncertainty)."""
    _set_head_shas(monkeypatch, shas)
    ok, reason = qg.check_branch_mergeable(_REPO, _WI, _BRANCH)
    assert ok is True
    assert gate["retest"] == 1          # re-test still runs on uncertainty


def test_tc11_skip_bumps_observability_counter(gate, monkeypatch):
    """The skip increments the read-only observability counter (D6)."""
    merge_gate._MERGE_GATE_COUNTERS["retest_skipped_current_total"] = 0
    _set_head_shas(monkeypatch, ["sha_same", "sha_same"])
    qg.check_branch_mergeable(_REPO, _WI, _BRANCH)
    assert merge_gate._MERGE_GATE_COUNTERS["retest_skipped_current_total"] == 1
