"""ORCH-073 FR-5 — main-integrity regression guard wired into _handle_merge_verify.

Covers TC-13..16 / AC-3 / AC-5 / AC-6 / INV-1. Calls the under-gate handler directly
with mocked merge_gate primitives + side effects (Plane/Telegram). Asserts the
return contract: False == advance to `done`, True == HOLD (alert, NOT done).
"""

import os
import tempfile

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

from unittest.mock import MagicMock  # noqa: E402

import pytest  # noqa: E402

from src import stage_engine, image_freshness  # noqa: E402
from src.stage_engine import AdvanceResult, _handle_merge_verify  # noqa: E402

REPO = "orchestrator"
WI = "ORCH-073"
BRANCH = "feature/ORCH-073-x"


@pytest.fixture(autouse=True)
def _wire(monkeypatch):
    # Under-gate is in scope for the self-hosting repo; guard enabled.
    monkeypatch.setattr(stage_engine.merge_gate, "merge_verify_applies", lambda r: True)
    monkeypatch.setattr(stage_engine.settings, "regression_guard_enabled", True)
    monkeypatch.setattr(image_freshness, "validated_revision", lambda r, b: "deadbeef")
    monkeypatch.setattr(stage_engine.merge_gate, "merge_pr", lambda r, b: (True, "merged PR #1"))
    # Silence Plane/Telegram side effects (assert on .called where relevant).
    for name in ("set_issue_blocked", "plane_add_comment", "send_telegram", "link_for"):
        monkeypatch.setattr(stage_engine, name, MagicMock())
    monkeypatch.setattr(
        stage_engine.self_deploy, "record_merged_to_main", MagicMock(return_value=True)
    )


# ---------------------------------------------------------------------------
# TC-13 (AC-6): SHA in main AND markers intact -> advance (return False), no alert.
# ---------------------------------------------------------------------------
def test_tc13_confirmed_and_intact_advances(monkeypatch):
    monkeypatch.setattr(stage_engine.merge_gate, "verify_merged_to_main", lambda r, b, s: True)
    monkeypatch.setattr(stage_engine.merge_gate, "check_main_regression", lambda r, b: (True, "markers intact (4)"))

    res = AdvanceResult()
    intervened = _handle_merge_verify(1, REPO, WI, BRANCH, res)

    assert intervened is False  # advance to done
    assert res.alerted is False
    assert not stage_engine.set_issue_blocked.called


# ---------------------------------------------------------------------------
# TC-14 (AC-3): SHA NOT in main (docs-only merge) -> HOLD + alert + Blocked.
# ---------------------------------------------------------------------------
def test_tc14_sha_not_in_main_holds(monkeypatch):
    monkeypatch.setattr(stage_engine.merge_gate, "verify_merged_to_main", lambda r, b, s: False)
    # Guard must never even run when SHA is not confirmed.
    monkeypatch.setattr(
        stage_engine.merge_gate, "check_main_regression",
        lambda r, b: (_ for _ in ()).throw(AssertionError("guard must not run when not confirmed")),
    )

    res = AdvanceResult()
    intervened = _handle_merge_verify(1, REPO, WI, BRANCH, res)

    assert intervened is True  # HOLD
    assert res.advanced is False
    assert res.note == "merge-not-verified-hold"
    assert stage_engine.set_issue_blocked.called
    assert stage_engine.send_telegram.called


# ---------------------------------------------------------------------------
# TC-15 (AC-5): SHA in main BUT a marker missing -> HOLD + 'main regressed' alert.
# ---------------------------------------------------------------------------
def test_tc15_marker_missing_holds(monkeypatch):
    monkeypatch.setattr(stage_engine.merge_gate, "verify_merged_to_main", lambda r, b, s: True)
    monkeypatch.setattr(
        stage_engine.merge_gate, "check_main_regression",
        lambda r, b: (False, "main regressed: ORCH-067 code missing (plane_issue_link @ src/notifications.py)"),
    )

    res = AdvanceResult()
    intervened = _handle_merge_verify(1, REPO, WI, BRANCH, res)

    assert intervened is True  # HOLD, NOT done
    assert res.advanced is False
    assert res.note == "main-regressed-hold"
    assert stage_engine.set_issue_blocked.called
    assert stage_engine.send_telegram.called


# ---------------------------------------------------------------------------
# TC-16 (INV-1): an internal verifier error -> HOLD + alert, no exception escapes.
# ---------------------------------------------------------------------------
def test_tc16_internal_error_holds_never_raises(monkeypatch):
    def boom(r, b, s):
        raise RuntimeError("verifier exploded")

    monkeypatch.setattr(stage_engine.merge_gate, "verify_merged_to_main", boom)

    res = AdvanceResult()
    # Must NOT raise.
    intervened = _handle_merge_verify(1, REPO, WI, BRANCH, res)

    assert intervened is True  # HOLD
    assert res.advanced is False
    assert res.alerted is True
    assert "merge-verify-error" in (res.note or "")
