"""Tests for QppgMonitor PII scrubbing hook."""
import pytest
from qppg_service.monitor import QppgMonitor, _default_pii_scrub


class TestDefaultScrubber:
    def test_scrubs_email(self):
        result = _default_pii_scrub("Contact me at alice@example.com today.")
        assert "alice@example.com" not in result
        assert "[EMAIL]" in result

    def test_scrubs_phone_us(self):
        result = _default_pii_scrub("Call 555-867-5309 for info.")
        assert "555-867-5309" not in result
        assert "[PHONE]" in result

    def test_scrubs_ssn(self):
        result = _default_pii_scrub("SSN is 123-45-6789.")
        assert "123-45-6789" not in result
        assert "[SSN]" in result

    def test_no_pii_unchanged(self):
        text = "The capital of France is Paris."
        assert _default_pii_scrub(text) == text


class TestQppgMonitorScrubber:
    def test_default_scrubber_applied_in_track(self):
        """PII in question should be scrubbed before scoring."""
        monitor = QppgMonitor()
        # Intercept what scorer.score() receives
        received = {}
        original_score = monitor.scorer.score
        def capturing_score(q, steps, ans, *args, **kwargs):
            received["question"] = q
            return original_score(q, steps, ans, *args, **kwargs)
        monitor.scorer.score = capturing_score

        monitor.track(
            question="Email me at test@example.com please",
            steps=[],
            final_answer="Sure, I'll email test@example.com.",
        )
        assert "test@example.com" not in received.get("question", "")
        assert "[EMAIL]" in received.get("question", "")

    def test_custom_scrubber_used_when_provided(self):
        """Custom pii_scrubber should override the default."""
        calls = []
        def my_scrubber(text):
            calls.append(text)
            return text.replace("secret", "[REDACTED]")

        monitor = QppgMonitor(pii_scrubber=my_scrubber)
        monitor.track(
            question="This is secret info",
            steps=[],
            final_answer="answer",
        )
        assert len(calls) >= 1
        assert any("secret" in c for c in calls)

    def test_step_observations_scrubbed(self):
        """PII in step observations should be scrubbed."""
        monitor = QppgMonitor()
        received_steps = {}
        original_score = monitor.scorer.score
        def capturing_score(q, steps, ans, *args, **kwargs):
            received_steps["steps"] = steps
            return original_score(q, steps, ans, *args, **kwargs)
        monitor.scorer.score = capturing_score

        monitor.track(
            question="test",
            steps=[{"action_type": "Search", "action_arg": "q",
                    "observation": "Found user email bob@corp.org"}],
            final_answer="answer",
        )
        obs = received_steps["steps"][0]["observation"]
        assert "bob@corp.org" not in obs
        assert "[EMAIL]" in obs

    def test_no_pii_scrubber_doesnt_break_track(self):
        """track() without any PII should work normally."""
        monitor = QppgMonitor()
        result = monitor.track("What is 2+2?", [], "4")
        # No assertion on result — just shouldn't raise


class TestPresidioFallback:
    def test_presidio_integration_hint_documented(self):
        """Presidio can be wired in via pii_scrubber parameter."""
        # This test documents the pattern, not a live presidio call
        # (presidio is an optional dep, not installed in test env)
        monitor = QppgMonitor(
            pii_scrubber=lambda text: text  # identity — user would plug presidio here
        )
        assert monitor._pii_scrubber is not None
