# #region Test.SupersetContextPII [C:2] [TYPE Module] [SEMANTICS test, superset, pii, mask, sanitize]
# @BRIEF Tests for _pii.py — mask_pii_value, sanitize_imported_filter_for_assistant, _mask_sensitive_text.
# @RELATION BINDS_TO -> [SupersetContextExtractorPII]
# @TEST_CONTRACT: [value:Any] -> [tuple[Any, bool]]
# @TEST_SCENARIO: email_mask -> replaces local part with ***
# @TEST_SCENARIO: uuid_mask -> preserves last 12 chars
# @TEST_SCENARIO: long_digit_mask -> preserves last 2 chars
# @TEST_SCENARIO: mixed_identifier_mask -> preserves first+last 2 chars
# @TEST_EDGE: nested_structure -> recurses into list/dict
# @TEST_EDGE: non_string_value -> passthrough with masked=False

from __future__ import annotations

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))

import pytest

from src.core.utils.superset_context_extractor._pii import (
    _mask_sensitive_text,
    mask_pii_value,
    sanitize_imported_filter_for_assistant,
)


# ──────────────────────────────────────────────
# _mask_sensitive_text
# ──────────────────────────────────────────────


class TestMaskSensitiveText:
    """_mask_sensitive_text — redact PII substrings from text."""

    def test_email_masked(self):
        """Email local-part replaced with ***."""
        result, masked = _mask_sensitive_text("user@example.com")
        assert masked is True
        assert "@example.com" in result
        assert result.startswith("***")

    def test_email_no_match(self):
        """Text without email returns unchanged."""
        result, masked = _mask_sensitive_text("hello world")
        assert masked is False
        assert result == "hello world"

    def test_uuid_masked(self):
        """UUID replaced with asterisk pattern, last 12 chars preserved before long-digit pass."""
        uuid_str = "550e8400-e29b-41d4-a716-446655440000"
        result, masked = _mask_sensitive_text(uuid_str)
        assert masked is True
        # UUID pattern replaces with "********-****-****-****-" + token[-12:]
        # Then LONG_DIGIT_PATTERN hits the digit portion -> preserves last 2
        assert result.startswith("********-****-****-****-")
        assert result != uuid_str
        # The last part gets further masked by long-digit pattern
        assert result.count("*") >= 20

    def test_long_digits_masked(self):
        """Long digit string preserves last 2 chars."""
        result, masked = _mask_sensitive_text("1234567890")
        assert masked is True
        assert result.endswith("90")
        assert len(result) == len("1234567890")

    def test_short_digits_not_masked(self):
        """Short digit string (<6 chars) is not masked."""
        result, masked = _mask_sensitive_text("12345")
        assert masked is False
        assert result == "12345"

    def test_mixed_identifier_masked(self):
        """Mixed alphanumeric identifier masked."""
        result, masked = _mask_sensitive_text("abc123xyz789")
        assert masked is True
        # First 2 + *** + last 2
        assert "ab" in result and "89" in result

    def test_mixed_identifier_short_uppercase(self):
        """Short uppercase identifier (<5) not masked."""
        result, masked = _mask_sensitive_text("ABC12")
        assert masked is False

    def test_email_and_uuid_both_masked(self):
        """Multiple sensitive patterns in one string."""
        result, masked = _mask_sensitive_text(
            "Contact: user@test.com, token=550e8400-e29b-41d4-a716-446655440000"
        )
        assert masked is True
        assert "***@test.com" in result
        assert "********" in result  # UUID masking present

    def test_empty_string(self):
        """Empty string returns unmasked."""
        result, masked = _mask_sensitive_text("")
        assert masked is False
        assert result == ""


# ──────────────────────────────────────────────
# mask_pii_value
# ──────────────────────────────────────────────


class TestMaskPiiValue:
    """mask_pii_value — redact PII from nested structures."""

    def test_string_with_email(self):
        """String with email is masked."""
        result, masked = mask_pii_value("email: user@test.com")
        assert masked is True
        assert "***@test.com" in result

    def test_non_string_passthrough(self):
        """Non-string value returns unchanged, masked=False."""
        result, masked = mask_pii_value(42)
        assert masked is False
        assert result == 42

        result, masked = mask_pii_value(None)
        assert masked is False
        assert result is None

        result, masked = mask_pii_value(True)
        assert masked is False
        assert result is True

    def test_list_with_sensitive_items(self):
        """List with email items is masked."""
        result, masked = mask_pii_value(["user@test.com", "hello"])
        assert masked is True
        assert "***@test.com" in result[0]
        assert result[1] == "hello"

    def test_list_no_sensitive_items(self):
        """List without sensitive items returns unmasked."""
        result, masked = mask_pii_value(["hello", "world"])
        assert masked is False
        assert result == ["hello", "world"]

    def test_dict_with_sensitive_value(self):
        """Dict with email value is masked."""
        result, masked = mask_pii_value({"email": "user@test.com", "name": "John"})
        assert masked is True
        assert "***@test.com" in result["email"]
        assert result["name"] == "John"

    def test_dict_no_sensitive_values(self):
        """Dict without sensitive values returns unmasked."""
        result, masked = mask_pii_value({"a": 1, "b": "hello"})
        assert masked is False

    def test_nested_dict_in_list(self):
        """Nested structure is recursed."""
        result, masked = mask_pii_value(
            {"users": [{"email": "admin@test.com"}], "count": 5}
        )
        assert masked is True
        assert "***@test.com" in result["users"][0]["email"]

    def test_empty_list(self):
        """Empty list returns unmasked."""
        result, masked = mask_pii_value([])
        assert masked is False
        assert result == []

    def test_empty_dict(self):
        """Empty dict returns unmasked."""
        result, masked = mask_pii_value({})
        assert masked is False
        assert result == {}


# ──────────────────────────────────────────────
# sanitize_imported_filter_for_assistant
# ──────────────────────────────────────────────


class TestSanitizeImportedFilterForAssistant:
    """sanitize_imported_filter_for_assistant — build assistant-safe filter payload."""

    def test_sanitizes_raw_value_with_email(self):
        """Raw value with email is masked and flag set."""
        result = sanitize_imported_filter_for_assistant(
            {"filter_name": "email_filter", "raw_value": "user@test.com"}
        )
        assert result["raw_value_masked"] is True
        assert "***@test.com" in result["raw_value"]

    def test_passthrough_non_sensitive(self):
        """Non-sensitive value passes through with mask=False."""
        result = sanitize_imported_filter_for_assistant(
            {"filter_name": "country", "raw_value": "US"}
        )
        assert result["raw_value_masked"] is False
        assert result["raw_value"] == "US"

    def test_preserves_existing_raw_value_masked(self):
        """Existing raw_value_masked flag is preserved."""
        result = sanitize_imported_filter_for_assistant(
            {
                "filter_name": "f1",
                "raw_value": "US",
                "raw_value_masked": True,
            }
        )
        assert result["raw_value_masked"] is True

    def test_does_not_mutate_original(self):
        """Original dict is not mutated (deepcopy)."""
        original = {"filter_name": "f1", "raw_value": "user@test.com"}
        result = sanitize_imported_filter_for_assistant(original)
        assert original["raw_value"] == "user@test.com"
        assert result["raw_value"] != original["raw_value"]

    def test_none_raw_value(self):
        """None raw_value handled gracefully."""
        result = sanitize_imported_filter_for_assistant(
            {"filter_name": "f1", "raw_value": None}
        )
        assert result["raw_value_masked"] is False
        assert result["raw_value"] is None
# #endregion Test.SupersetContextPII
