from __future__ import annotations

from unittest.mock import MagicMock

from openjarvis.agents.loop_guard import LoopGuard, LoopGuardConfig, LoopVerdict


def test_warn_before_block_first_cycle_warns():
    config = LoopGuardConfig(
        enabled=True,
        max_identical_calls=2,
        warn_before_block=True,
    )
    guard = LoopGuard(config)
    # Simulate the Rust backend blocking on the second identical call
    mock_rust = MagicMock()
    mock_rust.check.side_effect = [
        LoopVerdict(blocked=False, reason=""),
        LoopVerdict(blocked=True, reason="identical_calls:search"),
    ]
    guard._rust_impl = mock_rust
    guard.check_call("search", '{"q": "test"}')
    v2 = guard.check_call("search", '{"q": "test"}')
    assert not v2.blocked
    assert v2.warned


def test_warn_before_block_second_cycle_blocks():
    config = LoopGuardConfig(
        enabled=True,
        max_identical_calls=2,
        warn_before_block=True,
    )
    guard = LoopGuard(config)
    mock_rust = MagicMock()
    mock_rust.check.side_effect = [
        LoopVerdict(blocked=False, reason=""),
        LoopVerdict(blocked=True, reason="identical_calls:search"),
        LoopVerdict(blocked=False, reason=""),
        LoopVerdict(blocked=True, reason="identical_calls:search"),
    ]
    guard._rust_impl = mock_rust
    guard.check_call("search", '{"q": "test"}')
    v_warn = guard.check_call("search", '{"q": "test"}')
    assert v_warn.warned and not v_warn.blocked
    guard.check_call("search", '{"q": "test"}')
    v_block = guard.check_call("search", '{"q": "test"}')
    assert v_block.blocked
    assert not v_block.warned


def test_default_behavior_unchanged():
    config = LoopGuardConfig(
        enabled=True,
        max_identical_calls=2,
        warn_before_block=False,
    )
    guard = LoopGuard(config)
    mock_rust = MagicMock()
    mock_rust.check.side_effect = [
        LoopVerdict(blocked=False, reason=""),
        LoopVerdict(blocked=True, reason="identical_calls:search"),
    ]
    guard._rust_impl = mock_rust
    guard.check_call("search", '{"q": "test"}')
    v = guard.check_call("search", '{"q": "test"}')
    assert v.blocked
    assert not v.warned
