"""
Test PCI compliance and security features for payment processing pipeline.
"""

import pytest
from atomingest.testing import SecurityTestCase
from atomingest.core import Pipeline
from atomingest.security import EncryptionManager


class TestPCICompliance(SecurityTestCase):
    pipeline_config = "pipeline.yaml"

    def test_card_number_tokenization(self):
        """Test that card numbers are properly tokenized"""
        transaction = {
            "transaction_id": "TEST_TOKEN_001",
            "card_number": "4532015112830366",
            "cardholder_name": "JOHN SMITH",
            "amount": "100.00",
        }

        result = self.pipeline.process_record(transaction)

        # Verify card number is tokenized, not stored as plaintext
        assert result.success
        stored_card = result.data["card_number"]

        # Should be tokenized (not original number)
        assert stored_card != "4532015112830366"
        assert stored_card.startswith("tok_")
        assert len(stored_card) >= 16  # Minimum token length

    def test_sensitive_data_encryption(self):
        """Test that sensitive fields are encrypted at rest"""
        transaction = {
            "transaction_id": "TEST_ENCRYPT_001",
            "card_number": "4532015112830366",
            "card_expiry": "12/28",
            "cardholder_name": "JANE DOE",
            "amount": "200.00",
        }

        result = self.pipeline.process_record(transaction)
        assert result.success

        # Check database directly to ensure encryption
        db_record = self._get_database_record("transactions", "TEST_ENCRYPT_001")

        # Encrypted fields should not contain plaintext
        assert db_record["card_expiry"] != "12/28"
        assert db_record["cardholder_name"] != "JANE DOE"

        # Should have encryption markers
        assert db_record["card_expiry"].startswith("enc:")
        assert db_record["cardholder_name"].startswith("enc:")

    def test_card_data_masking_in_logs(self):
        """Test that card data is masked in application logs"""
        transaction = {
            "transaction_id": "TEST_MASK_001",
            "card_number": "4532015112830366",
            "cardholder_name": "BOB SMITH",
            "amount": "150.00",
        }

        # Enable debug logging to capture detailed logs
        with self.capture_logs(level="DEBUG") as logs:
            result = self.pipeline.process_record(transaction)
            assert result.success

        log_content = "".join(logs)

        # Card number should be masked in logs
        assert "4532015112830366" not in log_content
        assert "****0366" in log_content or "****" in log_content

        # Cardholder name should be masked
        assert "BOB SMITH" not in log_content or "B** S****" in log_content

    def test_key_rotation_compliance(self):
        """Test encryption key rotation capability"""
        encryption_manager = EncryptionManager()

        # Test key rotation
        old_key_id = encryption_manager.current_key_id
        encryption_manager.rotate_keys()
        new_key_id = encryption_manager.current_key_id

        assert old_key_id != new_key_id

        # Verify old encrypted data can still be decrypted
        test_data = "sensitive_information"
        encrypted_old = encryption_manager.encrypt(test_data, key_id=old_key_id)
        decrypted = encryption_manager.decrypt(encrypted_old)

        assert decrypted == test_data

    def test_access_control_enforcement(self):
        """Test that field-level access controls are enforced"""
        # Test with different user roles
        transaction_data = {
            "transaction_id": "TEST_ACCESS_001",
            "card_number": "4532015112830366",
            "amount": "100.00",
        }

        # Standard user should not access sensitive fields
        with self.user_context(role="data_consumer"):
            result = self.pipeline.query_record("TEST_ACCESS_001")

            # Should not have access to PCI sensitive fields
            assert "card_number" not in result.data
            assert "card_expiry" not in result.data

            # Can access non-sensitive fields
            assert "amount" in result.data
            assert "transaction_id" in result.data

        # Compliance officer should have full access
        with self.user_context(role="compliance_officer"):
            result = self.pipeline.query_record("TEST_ACCESS_001")

            # Should have access to all fields
            assert "card_number" in result.data
            assert "amount" in result.data

    def test_audit_trail_creation(self):
        """Test that comprehensive audit trails are created"""
        transaction = {
            "transaction_id": "TEST_AUDIT_001",
            "card_number": "4532015112830366",
            "amount": "300.00",
        }

        result = self.pipeline.process_record(transaction)
        assert result.success

        # Check audit log entries
        audit_entries = self._get_audit_entries("TEST_AUDIT_001")

        assert len(audit_entries) >= 1

        audit_entry = audit_entries[0]
        assert audit_entry["operation"] == "transaction_insert"
        assert audit_entry["transaction_id"] == "TEST_AUDIT_001"
        assert audit_entry["user_id"] is not None
        assert audit_entry["timestamp"] is not None
        assert audit_entry["data_hash"] is not None

    def test_data_retention_compliance(self):
        """Test data retention policy compliance"""
        # Create old transaction (simulate 8 years old)
        from datetime import datetime, timedelta

        old_date = datetime.now() - timedelta(days=2920)  # 8 years

        transaction = {
            "transaction_id": "TEST_RETENTION_001",
            "card_number": "4532015112830366",
            "amount": "100.00",
            "processing_timestamp": old_date.isoformat(),
        }

        result = self.pipeline.process_record(transaction)
        assert result.success

        # Run retention policy check
        retention_manager = self.pipeline.get_retention_manager()
        eligible_for_deletion = retention_manager.get_eligible_records()

        # Should be eligible for deletion after 7 years
        assert "TEST_RETENTION_001" in eligible_for_deletion

    def test_pci_validation_rules(self):
        """Test PCI-specific validation rules"""
        # Test invalid card number format
        invalid_transaction = {
            "transaction_id": "TEST_PCI_001",
            "card_number": "1234567890123456",  # Invalid format
            "amount": "100.00",
        }

        result = self.pipeline.process_record(invalid_transaction)

        assert not result.success
        assert "PCI_VALIDATION_FAILED" in result.errors
        assert "INVALID_CARD_FORMAT" in result.validation_errors

    def test_secure_transmission(self):
        """Test secure transmission requirements"""
        # Verify TLS encryption for external communications
        config = self.pipeline.get_config()

        # All external endpoints should use HTTPS
        external_endpoints = config.get("external_services", {})
        for service_name, endpoint in external_endpoints.items():
            assert endpoint.startswith(
                "https://"
            ), f"Service {service_name} not using HTTPS"

    def test_cardholder_data_environment_isolation(self):
        """Test CDE (Cardholder Data Environment) isolation"""
        # Verify that card data processing is isolated
        transaction = {
            "transaction_id": "TEST_CDE_001",
            "card_number": "4532015112830366",
            "amount": "100.00",
        }

        with self.monitor_network_traffic() as traffic:
            result = self.pipeline.process_record(transaction)
            assert result.success

        # Verify no card data transmitted over unsecured connections
        for packet in traffic:
            if not packet.encrypted:
                # Should not contain card number in plaintext
                assert "4532015112830366" not in packet.payload

    def test_vulnerability_scanning_compliance(self):
        """Test that system passes basic vulnerability checks"""
        # Check for common security vulnerabilities
        security_scanner = self.get_security_scanner()

        vulnerabilities = security_scanner.scan(
            targets=["database", "application", "network"]
        )

        # Should have no high-severity vulnerabilities
        high_severity = [v for v in vulnerabilities if v.severity == "HIGH"]
        assert (
            len(high_severity) == 0
        ), f"High severity vulnerabilities found: {high_severity}"

    def test_payment_processor_integration_security(self):
        """Test secure integration with payment processors"""
        transaction = {
            "transaction_id": "TEST_PROCESSOR_001",
            "card_number": "4532015112830366",
            "amount": "100.00",
        }

        # Mock payment processor response
        with self.mock_external_service("payment_processor") as mock_service:
            mock_service.return_value = {
                "status": "approved",
                "authorization_code": "AUTH123",
                "transaction_id": "PROC_123",
            }

            result = self.pipeline.process_record(transaction)
            assert result.success

        # Verify secure communication
        requests = mock_service.get_requests()
        assert len(requests) == 1

        request = requests[0]
        # Should use secure headers
        assert "Authorization" in request.headers
        assert request.url.startswith("https://")

        # Should not send full card number
        payload = request.json()
        assert payload.get("card_number", "").startswith("tok_")


class TestSecurityIncidentResponse:
    """Test security incident detection and response"""

    def test_brute_force_attack_detection(self):
        """Test detection of brute force attacks"""
        pipeline = Pipeline("pipeline.yaml")

        # Simulate multiple failed attempts from same IP
        for i in range(100):
            invalid_transaction = {
                "transaction_id": f"BRUTE_FORCE_{i:03d}",
                "card_number": "1234567890123456",  # Invalid
                "ip_address": "192.168.1.200",
                "amount": "10.00",
            }

            result = pipeline.process_record(invalid_transaction)
            assert not result.success

        # Should trigger brute force detection
        security_alerts = self._get_security_alerts(ip_address="192.168.1.200")
        brute_force_alerts = [
            a for a in security_alerts if a["type"] == "BRUTE_FORCE_ATTACK"
        ]

        assert len(brute_force_alerts) > 0

    def test_data_breach_response(self):
        """Test data breach response procedures"""
        # Simulate data breach detection
        breach_detector = self.get_breach_detector()

        # Trigger breach simulation
        breach_detector.simulate_breach(
            affected_records=["TEST_BREACH_001", "TEST_BREACH_002"],
            breach_type="UNAUTHORIZED_ACCESS",
        )

        # Verify incident response procedures
        incident_response = self.get_incident_response_manager()

        # Should automatically trigger containment
        assert incident_response.is_containment_active()

        # Should create incident report
        incidents = incident_response.get_active_incidents()
        assert len(incidents) == 1

        incident = incidents[0]
        assert incident["type"] == "DATA_BREACH"
        assert incident["severity"] == "CRITICAL"
        assert "UNAUTHORIZED_ACCESS" in incident["description"]

    def _get_database_record(self, table, transaction_id):
        """Helper method to get raw database record"""
        # Mock database access for testing
        return {
            "card_expiry": "enc:encrypted_data",
            "cardholder_name": "enc:encrypted_name",
        }

    def _get_audit_entries(self, transaction_id):
        """Helper method to get audit log entries"""
        # Mock audit log access
        return [
            {
                "operation": "transaction_insert",
                "transaction_id": transaction_id,
                "user_id": "test_user",
                "timestamp": "2026-01-29T10:00:00Z",
                "data_hash": "sha256_hash",
            }
        ]

    def _get_security_alerts(self, **filters):
        """Helper method to get security alerts"""
        # Mock security alerts
        return [
            {
                "type": "BRUTE_FORCE_ATTACK",
                "ip_address": filters.get("ip_address"),
                "timestamp": "2026-01-29T10:00:00Z",
                "severity": "HIGH",
            }
        ]


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