"""Tests for PredicateTermination."""

import pytest

from agentbyte.messages import AssistantMessage, UserMessage
from agentbyte.termination.predicate import PredicateTermination


class TestPredicateTermination:
    def test_terminates_when_predicate_returns_true(self):
        term = PredicateTermination(lambda msgs: any("stop" in str(m.content) for m in msgs))

        stop = term.check([AssistantMessage(content="please stop now", source="agent")])
        assert stop is not None
        assert stop.content == "Predicate condition met"

    def test_no_termination_when_predicate_returns_false(self):
        term = PredicateTermination(lambda msgs: False)

        assert term.check([UserMessage(content="keep going", source="user")]) is None

    def test_custom_reason_appears_in_stop_message(self):
        term = PredicateTermination(lambda msgs: True, reason="Quality threshold reached")

        stop = term.check([AssistantMessage(content="output", source="agent")])
        assert stop is not None
        assert stop.content == "Quality threshold reached"

    def test_predicate_receives_delta_messages(self):
        received: list = []

        def capture(msgs):
            received.extend(msgs)
            return False

        term = PredicateTermination(capture)
        msgs = [UserMessage(content="a", source="user"), AssistantMessage(content="b", source="agent")]
        term.check(msgs)
        assert len(received) == 2

    def test_empty_message_list_does_not_raise(self):
        term = PredicateTermination(lambda msgs: False)
        assert term.check([]) is None

    def test_predicate_with_stateful_closure(self):
        call_count = {"n": 0}

        def after_two(msgs):
            call_count["n"] += 1
            return call_count["n"] >= 2

        term = PredicateTermination(after_two)
        assert term.check([UserMessage(content="x", source="user")]) is None
        stop = term.check([UserMessage(content="y", source="user")])
        assert stop is not None

    def test_invalid_non_callable_raises(self):
        with pytest.raises(ValueError, match="callable"):
            PredicateTermination("not_a_function")  # type: ignore

    def test_invalid_empty_reason_raises(self):
        with pytest.raises(ValueError, match="reason"):
            PredicateTermination(lambda msgs: True, reason="")
