"""
Unit tests for WhatsApp business-function scoping gate.

Tests CHAN-04: Business-function scoping enforces Meta 2026 policy.

Two-tier gate:
  Tier 1: is_clearly_off_topic — keyword overlap check (no LLM call)
  Tier 2: Borderline messages pass to LLM with scoping in system prompt

Covers:
- is_clearly_off_topic returns False when message has keyword overlap
- is_clearly_off_topic returns True when message has zero keyword overlap
- is_clearly_off_topic returns False when allowed_functions is empty (no scoping)
- Canned redirect message format includes agent name and allowed topics
- Borderline messages (partial overlap) pass through tier 1
- Edge cases: empty text, case insensitivity
"""

from __future__ import annotations

import pytest


class TestIsClearlyOffTopic:
    """Tests for the tier 1 keyword scoping gate."""

    def test_matching_keywords_returns_false(self) -> None:
        """Message with keyword overlap must NOT be considered off-topic."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["order tracking", "customer support", "returns"]
        text = "I need help with my order"
        assert is_clearly_off_topic(text, allowed) is False

    def test_zero_overlap_returns_true(self) -> None:
        """Message with zero keyword overlap must be considered off-topic."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["order tracking", "customer support", "returns"]
        text = "Can you write me a poem about cats?"
        assert is_clearly_off_topic(text, allowed) is True

    def test_empty_allowed_functions_returns_false(self) -> None:
        """Empty allowed_functions means no scoping — nothing is off-topic."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        assert is_clearly_off_topic("anything goes", []) is False
        assert is_clearly_off_topic("write me a poem", []) is False

    def test_case_insensitive_matching(self) -> None:
        """Keyword matching must be case-insensitive."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["Order Tracking", "Customer Support"]
        text = "CUSTOMER needs SUPPORT with their order"
        assert is_clearly_off_topic(text, allowed) is False

    def test_empty_message_returns_false(self) -> None:
        """Empty message should not be considered clearly off-topic."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["customer support"]
        assert is_clearly_off_topic("", allowed) is False
        assert is_clearly_off_topic("   ", allowed) is False

    def test_single_word_overlap_returns_false(self) -> None:
        """Single keyword match is enough to pass tier 1."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["billing", "payment", "invoice"]
        text = "I need help with my billing"
        assert is_clearly_off_topic(text, allowed) is False

    def test_off_topic_politics_returns_true(self) -> None:
        """Clearly political message is off-topic for a customer support agent."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["customer support", "order tracking", "returns", "billing"]
        text = "What do you think about the election?"
        assert is_clearly_off_topic(text, allowed) is True

    def test_off_topic_entertainment_returns_true(self) -> None:
        """Entertainment request is off-topic for a support agent."""
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["customer support", "order status", "refunds"]
        text = "Tell me a joke please"
        assert is_clearly_off_topic(text, allowed) is True

    def test_borderline_message_passes_through(self) -> None:
        """
        A borderline message with any keyword overlap must pass tier 1.
        The LLM handles judgment at tier 2 via system prompt.
        """
        from gateway.channels.whatsapp import is_clearly_off_topic

        allowed = ["customer support", "product questions", "order tracking"]
        # "product" appears in allowed_functions — passes tier 1
        text = "I have a question about your product pricing strategy"
        assert is_clearly_off_topic(text, allowed) is False


class TestOffTopicReply:
    """Tests for the canned off-topic redirect message."""

    def test_reply_contains_agent_name(self) -> None:
        """Canned redirect must include the agent's name."""
        from gateway.channels.whatsapp import build_off_topic_reply

        reply = build_off_topic_reply("Mara", ["customer support", "order tracking"])
        assert "Mara" in reply

    def test_reply_contains_allowed_functions(self) -> None:
        """Canned redirect must mention the allowed functions/topics."""
        from gateway.channels.whatsapp import build_off_topic_reply

        allowed = ["customer support", "order tracking"]
        reply = build_off_topic_reply("Mara", allowed)
        assert "customer support" in reply
        assert "order tracking" in reply

    def test_reply_is_non_empty_string(self) -> None:
        """Canned redirect must be a non-empty string."""
        from gateway.channels.whatsapp import build_off_topic_reply

        reply = build_off_topic_reply("AI", ["support"])
        assert isinstance(reply, str)
        assert len(reply) > 0

    def test_reply_empty_allowed_functions_graceful(self) -> None:
        """build_off_topic_reply must not crash with empty allowed_functions."""
        from gateway.channels.whatsapp import build_off_topic_reply

        reply = build_off_topic_reply("Mara", [])
        assert isinstance(reply, str)
        assert "Mara" in reply

    def test_reply_multiple_topics_separated(self) -> None:
        """Multiple topics in canned redirect must be clearly separated."""
        from gateway.channels.whatsapp import build_off_topic_reply

        allowed = ["billing", "invoicing", "payments"]
        reply = build_off_topic_reply("Alex", allowed)
        # All topics must appear in the reply
        for topic in allowed:
            assert topic in reply
