"""
Compliance Validator Regex Audit — tests/test_compliance_validator.py

Audits HARM_PATTERNS and PII_PATTERNS in pulse/daemons/compliance_validator.py.

Coverage:
  - True positives: each gate catches malicious content it should block
  - False positives: known over-broad patterns that flag benign content
  - Edge cases: case-insensitivity, partial-word matching, boundary behavior
  - validate() integration: correct violation codes are returned

Findings summary:
  FIXED:
  1. `rce`       — was matching substrings in "source", "force", "coerce". Fixed: \brce\b word boundary.
  2. `payload`   — was matching legitimate JSON field names. Fixed: removed from MALICIOUS_EXPLOIT.

  OPEN (still xfail — tracked for future improvement):
  3. `exploit`   — matches "exploit the potential" (missing word boundary context)
  4. `bomb`      — matches "time bomb", "logic bomb" (software terms)
  5. `weapon`    — matches "weapon of choice" (idiomatic phrase, low-harm)
  6. CREDIT_CARD — matches any 13-19 digit integer literal (too broad)
  7. IP_ADDRESS  — matches software version strings like "1.2.3.4"
  8. PHONE       — matches section/document reference numbers
"""
import sys
import re
import pytest
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(PROJECT_ROOT))

from pulse.daemons.runtime.compliance_validator import HARM_PATTERNS, PII_PATTERNS, ComplianceValidator, SYSTEM_FILES


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def harm_matches(pattern_name: str, text: str) -> bool:
    return bool(HARM_PATTERNS[pattern_name].search(text))


def pii_matches(pii_type: str, text: str) -> bool:
    return bool(PII_PATTERNS[pii_type].search(text))


# ---------------------------------------------------------------------------
# HARM PATTERNS — True Positives (must catch)
# ---------------------------------------------------------------------------

class TestHarmPatternsTruePositives:
    """Safety gate must catch clearly malicious content."""

    def test_sql_injection_caught(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "Execute SQL injection on the login form")

    def test_buffer_overflow_caught(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "Trigger buffer overflow to crash the service")

    def test_privilege_escalation_caught(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "Perform privilege escalation to gain root")

    def test_zero_day_caught(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "Weaponize this zero-day vulnerability")

    def test_rce_uppercase_caught(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "Use RCE to execute arbitrary commands")

    def test_rce_lowercase_caught(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "rce exploit targeting the web server")

    def test_phishing_caught(self):
        assert harm_matches("FRAUD_HARM", "Launch a phishing campaign targeting employees")

    def test_social_engineering_caught(self):
        assert harm_matches("FRAUD_HARM", "Use social engineering to obtain credentials")

    def test_fraud_caught(self):
        assert harm_matches("FRAUD_HARM", "Commit credit card fraud using stolen data")

    def test_identity_theft_caught(self):
        assert harm_matches("FRAUD_HARM", "Facilitate identity theft through data breach")

    def test_hate_speech_caught(self):
        assert harm_matches("SYSTEMIC_OPPRESSION", "Generate incitement and hate speech content")

    def test_supremacy_caught(self):
        assert harm_matches("SYSTEMIC_OPPRESSION", "Promote white supremacy ideology")

    def test_explosive_caught(self):
        assert harm_matches("LETHAL_FORCE", "Instructions for building an explosive device")

    def test_assassination_caught(self):
        assert harm_matches("LETHAL_FORCE", "Assassination target and coordinates provided")

    def test_lethal_weapon_caught(self):
        assert harm_matches("LETHAL_FORCE", "Convert this to a lethal weapon")

    def test_case_insensitive_sql(self):
        assert harm_matches("MALICIOUS_EXPLOIT", "SQL INJECTION attack in uppercase")

    def test_case_insensitive_phishing(self):
        assert harm_matches("FRAUD_HARM", "PHISHING email template")

    def test_case_insensitive_bomb(self):
        assert harm_matches("LETHAL_FORCE", "BOMB construction manual")


# ---------------------------------------------------------------------------
# HARM PATTERNS — False Positives (known over-broad matches)
# These tests document current defects via pytest.mark.xfail.
# When the regex is tightened, flip to plain asserts.
# ---------------------------------------------------------------------------

class TestHarmPatternsFalsePositives:
    """Document patterns that flag benign content — these are current defects."""

    def test_rce_false_positive_source(self):
        # "source" contains "rce" as a substring — fixed with \brce\b word boundary
        assert not harm_matches("MALICIOUS_EXPLOIT", "Please check the data source for accuracy")

    def test_rce_false_positive_open_source(self):
        assert not harm_matches("MALICIOUS_EXPLOIT", "Use an open source library for this task")

    def test_rce_false_positive_coerce(self):
        assert not harm_matches("MALICIOUS_EXPLOIT", "Coerce the value to an integer type")

    def test_payload_false_positive_json_field(self):
        # Normal task dispatch JSON — 'payload' removed from MALICIOUS_EXPLOIT pattern
        assert not harm_matches("MALICIOUS_EXPLOIT", '{"memory_data": {"payload": "extract knowledge"}}')

    def test_payload_false_positive_api_context(self):
        assert not harm_matches("MALICIOUS_EXPLOIT", "The API sends a JSON payload to the endpoint")

    def test_exploit_false_positive_potential(self):
        # FIXED: negative lookahead excludes "exploit the potential" etc.
        assert not harm_matches("MALICIOUS_EXPLOIT", "We can exploit the potential of this architecture")

    def test_bomb_false_positive_time_bomb(self):
        # FIXED: negative lookbehind excludes "time bomb", "logic bomb", "fork bomb"
        assert not harm_matches("LETHAL_FORCE", "Avoid time bomb antipatterns in production code")

    def test_bomb_false_positive_logic_bomb(self):
        assert not harm_matches("LETHAL_FORCE", "This git commit introduced a logic bomb pattern")

    def test_weapon_false_positive_weapon_of_choice(self):
        # FIXED: negative lookahead excludes "weapon of choice"
        assert not harm_matches("LETHAL_FORCE", "Python is the weapon of choice for data science")


# ---------------------------------------------------------------------------
# PII PATTERNS — True Positives (must catch)
# ---------------------------------------------------------------------------

class TestPIIPatternsTruePositives:
    """PII gate must detect sensitive personal information."""

    def test_email_caught(self):
        assert pii_matches("EMAIL", "Contact user@example.com for support")

    def test_email_subdomain_caught(self):
        assert pii_matches("EMAIL", "Send to admin@mail.company.org immediately")

    def test_phone_dashes_caught(self):
        assert pii_matches("PHONE", "Call 555-867-5309 for assistance")

    def test_phone_dots_caught(self):
        assert pii_matches("PHONE", "Reach out at 800.555.1212")

    def test_ssn_caught(self):
        assert pii_matches("SSN", "SSN on file: 123-45-6789")

    def test_credit_card_caught(self):
        assert pii_matches("CREDIT_CARD", "Card number: 4111111111111111")

    def test_ip_address_caught(self):
        assert pii_matches("IP_ADDRESS", "Internal server at 192.168.1.100")

    def test_passport_caught(self):
        assert pii_matches("PASSPORT", "Passport number AB1234567 verified")

    def test_passport_single_letter_caught(self):
        assert pii_matches("PASSPORT", "Document ID: X123456789")


# ---------------------------------------------------------------------------
# PII PATTERNS — False Positives (known over-broad matches)
# ---------------------------------------------------------------------------

class TestPIIPatternsFalsePositives:
    """Document PII patterns that flag non-PII content."""

    def test_credit_card_false_positive_large_integer(self):
        # FIXED: require valid card IIN prefix (4x Visa, 5[1-5] MC, 3[47] Amex, 6[05] Discover)
        assert not pii_matches("CREDIT_CARD", "Processed 1234567890123456 items in queue")

    def test_ip_address_false_positive_version_string(self):
        # FIXED: negative lookbehind for "version " + valid octet ranges (0-255)
        assert not pii_matches("IP_ADDRESS", "Upgraded to version 1.2.3.4 of the package")

    def test_phone_false_positive_section_reference(self):
        # FIXED: negative lookbehind for "section " context
        assert not pii_matches("PHONE", "See section 123.456.7890 of the documentation")


# ---------------------------------------------------------------------------
# validate() Integration — end-to-end violation codes
# ---------------------------------------------------------------------------

class TestValidateIntegration:
    """Test ComplianceValidator.validate() returns correct violation codes."""

    def setup_method(self):
        self.validator = ComplianceValidator(private_key_path="nonexistent_key.pem")

    def test_clean_action_returns_no_violations(self):
        action = {"id": "test_001", "output": {"message": "Task completed successfully"}}
        violations = self.validator.validate(action)
        assert violations == []

    def test_sql_injection_returns_titan_violation(self):
        action = {"id": "test_002", "output": {"query": "SQL injection attack on login"}}
        violations = self.validator.validate(action)
        assert any("TITAN_VIOLATION:MALICIOUS_EXPLOIT" in v for v in violations)

    def test_phishing_returns_fraud_violation(self):
        action = {"id": "test_003", "output": {"content": "phishing email template for employees"}}
        violations = self.validator.validate(action)
        assert any("TITAN_VIOLATION:FRAUD_HARM" in v for v in violations)

    def test_multiple_violations_all_returned(self):
        action = {
            "id": "test_004",
            "output": {"content": "SQL injection and phishing campaign together"}
        }
        violations = self.validator.validate(action)
        violation_types = {v.split(":")[1] for v in violations if v.startswith("TITAN")}
        assert "MALICIOUS_EXPLOIT" in violation_types
        assert "FRAUD_HARM" in violation_types

    def test_violation_code_format(self):
        action = {"id": "test_005", "output": {"msg": "zero-day exploit discovered"}}
        violations = self.validator.validate(action)
        for v in violations:
            parts = v.split(":")
            assert len(parts) == 2, f"Unexpected violation format: {v}"
            assert parts[0] in ("TITAN_VIOLATION", "PII_DETECTED"), f"Unknown prefix: {parts[0]}"

    def test_empty_output_returns_no_violations(self):
        action = {"id": "test_006", "output": {}}
        violations = self.validator.validate(action)
        assert violations == []

    def test_missing_output_key_returns_no_violations(self):
        action = {"id": "test_007"}
        violations = self.validator.validate(action)
        assert violations == []

    def test_get_socratic_refusal_format(self):
        violations = ["TITAN_VIOLATION:MALICIOUS_EXPLOIT", "TITAN_VIOLATION:FRAUD_HARM"]
        refusal = self.validator.get_socratic_refusal(violations)
        assert "REFUSAL:" in refusal
        assert "MALICIOUS_EXPLOIT" in refusal
        assert "FRAUD_HARM" in refusal

    def test_get_socratic_refusal_ignores_pii_violations(self):
        violations = ["PII_DETECTED:EMAIL", "TITAN_VIOLATION:FRAUD_HARM"]
        refusal = self.validator.get_socratic_refusal(violations)
        assert "EMAIL" not in refusal  # PII violations are not in TITAN refusal
        assert "FRAUD_HARM" in refusal


# ---------------------------------------------------------------------------
# Audit Summary — boundary fix verification
# ---------------------------------------------------------------------------

class TestProposedFixes:
    """Verify that word-boundary fixes resolve the documented false positives.

    These tests use locally-patched patterns to confirm the fix is correct
    before it is applied to the production module.
    """

    def test_rce_word_boundary_fix_resolves_source(self):
        """\\brce\\b should not match 'source'."""
        fixed = re.compile(r"(?i)\brce\b")
        assert not fixed.search("data source")
        assert not fixed.search("open source library")
        assert not fixed.search("coerce the value")
        # True positive still works
        assert fixed.search("Use RCE to execute commands")
        assert fixed.search("rce exploit detected")

    def test_rce_word_boundary_fix_preserves_true_positives(self):
        fixed = re.compile(r"(?i)\brce\b")
        true_positives = [
            "RCE vulnerability in the web app",
            "rce attack vector identified",
            "Remote Code Execution (RCE) found",
        ]
        for text in true_positives:
            assert fixed.search(text), f"True positive missed after fix: {text}"


# ---------------------------------------------------------------------------
# SYSTEM_FILES Skip List — verify all root-level state files are protected
# ---------------------------------------------------------------------------

# These are the known root-level JSON files in state/ that must never be
# treated as agent actions and deleted by the compliance watcher.
_KNOWN_SYSTEM_STATE_FILES = {
    "task_board.json",
    "agent_registry.json",
    "daemon_alerts.json",
    "supervisor_alerts.json",
    "daemon_pids.json",
    "prediction_alerts.json",
    "pulse_bridge_state.json",
    "worker_pids.json",
    "homeostatic_state.json",
    "homeostatic_overrides.json",
    "hebbian_matrix.json",
    "epistemic_forager_state.json",
    "healer_state.json",
    "ghost_resonance_state.json",
    "skill_usage.json",
    "prediction_metrics.json",
    "brain_query_log.json",
}


class TestSystemFilesSkipList:
    """Verify SYSTEM_FILES protects all root-level state JSON from deletion."""

    def test_all_known_state_files_are_in_skip_list(self):
        """Every known system state file must be in SYSTEM_FILES."""
        missing = _KNOWN_SYSTEM_STATE_FILES - SYSTEM_FILES
        assert not missing, f"System state files missing from skip list: {missing}"

    def test_task_board_protected(self):
        assert "task_board.json" in SYSTEM_FILES

    def test_agent_registry_protected(self):
        assert "agent_registry.json" in SYSTEM_FILES

    def test_daemon_pids_protected(self):
        assert "daemon_pids.json" in SYSTEM_FILES

    def test_worker_pids_protected(self):
        assert "worker_pids.json" in SYSTEM_FILES

    def test_pulse_bridge_state_protected(self):
        assert "pulse_bridge_state.json" in SYSTEM_FILES

    def test_homeostatic_state_protected(self):
        assert "homeostatic_state.json" in SYSTEM_FILES

    def test_homeostatic_overrides_protected(self):
        assert "homeostatic_overrides.json" in SYSTEM_FILES

    def test_hebbian_matrix_protected(self):
        assert "hebbian_matrix.json" in SYSTEM_FILES

    def test_epistemic_forager_state_protected(self):
        assert "epistemic_forager_state.json" in SYSTEM_FILES

    def test_healer_state_protected(self):
        assert "healer_state.json" in SYSTEM_FILES

    def test_ghost_resonance_state_protected(self):
        assert "ghost_resonance_state.json" in SYSTEM_FILES

    def test_skill_usage_protected(self):
        assert "skill_usage.json" in SYSTEM_FILES

    def test_prediction_alerts_protected(self):
        assert "prediction_alerts.json" in SYSTEM_FILES

    def test_supervisor_alerts_protected(self):
        assert "supervisor_alerts.json" in SYSTEM_FILES

    def test_daemon_alerts_protected(self):
        assert "daemon_alerts.json" in SYSTEM_FILES

    def test_skip_list_is_set_type(self):
        """SYSTEM_FILES must be a set for O(1) lookup in the watcher hot path."""
        assert isinstance(SYSTEM_FILES, set)

    def test_unknown_json_not_in_skip_list(self):
        """Agent action files (not system files) must NOT be in the skip list."""
        assert "agent_action_12345.json" not in SYSTEM_FILES
        assert "dispatch_abc.json" not in SYSTEM_FILES


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
