"""Unit tests for PaymentOrchestrator."""

import unittest
from unittest.mock import Mock, patch, MagicMock
from payment_orchestrator.core.orchestrator import PaymentOrchestrator


class TestPaymentOrchestrator(unittest.TestCase):
    """Test cases for PaymentOrchestrator class."""
    
    @patch('payment_orchestrator.core.orchestrator.PaymentValidator')
    @patch('payment_orchestrator.core.orchestrator.FraudDetector')
    @patch('payment_orchestrator.core.orchestrator.PaymentEncryptor')
    @patch('payment_orchestrator.core.orchestrator.SecretFetcher')
    @patch('payment_orchestrator.core.orchestrator.PaymentNotifier')
    @patch('payment_orchestrator.core.orchestrator.PaymentMailer')
    @patch('payment_orchestrator.core.orchestrator.RetryQueueManager')
    @patch('payment_orchestrator.core.orchestrator.TransactionStore')
    def setUp(self, mock_store, mock_queue, mock_mailer, mock_notifier,
              mock_secret, mock_encryptor, mock_fraud, mock_validator):
        """Set up test fixtures with mocked dependencies."""
        # Mock secret fetcher to return API key
        mock_secret_instance = Mock()
        mock_secret_instance.get_api_key.return_value = "test_api_key"
        mock_secret.return_value = mock_secret_instance
        
        # Initialize orchestrator with mocked dependencies
        self.orchestrator = PaymentOrchestrator(
            kms_key_id="test-key",
            secret_name="test-secret",
            sns_topic_arn="arn:aws:sns:us-east-1:123456789012:test",
            sqs_queue_url="https://sqs.us-east-1.amazonaws.com/123456789012/test",
            dynamodb_table="TestTable",
            sender_email="test@example.com",
            region="us-east-1"
        )
        
        # Store mocks for assertions
        self.mock_validator = self.orchestrator.validator
        self.mock_fraud_detector = self.orchestrator.fraud_detector
        self.mock_encryptor = self.orchestrator.encryptor
        self.mock_transaction_store = self.orchestrator.transaction_store
        self.mock_notifier = self.orchestrator.notifier
        self.mock_mailer = self.orchestrator.mailer
        self.mock_queue_manager = self.orchestrator.queue_manager
    
    def test_successful_payment_flow(self):
        """Test complete successful payment flow."""
        # Setup mocks
        self.mock_validator.validate.return_value = (True, None)
        self.mock_fraud_detector.check_fraud.return_value = (False, None)
        self.mock_encryptor.encrypt.side_effect = ["encrypted_card", "encrypted_cvv"]
        self.mock_transaction_store.save_transaction.return_value = True
        
        # Mock processor
        with patch('payment_orchestrator.core.orchestrator.PaymentProcessor') as mock_proc:
            mock_proc_instance = Mock()
            mock_proc_instance.process.return_value = (True, "Payment approved")
            mock_proc.return_value = mock_proc_instance
            
            payment_data = {
                "cardholder_name": "John Doe",
                "card_number": "4532015112830366",
                "expiry_month": 12,
                "expiry_year": 2027,
                "cvv": "123",
                "amount": 1999,
                "currency": "USD",
                "email": "test@example.com"
            }
            
            result = self.orchestrator.process_payment(payment_data)
            
            # Assertions
            self.assertTrue(result["success"])
            self.assertEqual(result["status"], "SUCCESS")
            self.mock_notifier.notify_success.assert_called_once()
            self.mock_mailer.send_receipt.assert_called_once()
    
    def test_validation_failure(self):
        """Test payment fails validation."""
        self.mock_validator.validate.return_value = (False, "Invalid amount")
        
        payment_data = {"amount": -100}
        result = self.orchestrator.process_payment(payment_data)
        
        self.assertFalse(result["success"])
        self.assertIn("Invalid amount", result["message"])
    
    def test_fraud_detection(self):
        """Test fraud detection blocks payment."""
        self.mock_validator.validate.return_value = (True, None)
        self.mock_fraud_detector.check_fraud.return_value = (True, "High amount")
        
        payment_data = {
            "cardholder_name": "John Doe",
            "card_number": "4532015112830366",
            "expiry_month": 12,
            "expiry_year": 2027,
            "cvv": "123",
            "amount": 2000000,
            "currency": "USD",
            "email": "test@example.com"
        }
        
        result = self.orchestrator.process_payment(payment_data)
        
        self.assertFalse(result["success"])
        self.assertIn("Fraud detected", result["message"])


if __name__ == "__main__":
    unittest.main()
