"""Main payment orchestration engine."""

import logging
import uuid
import json
from typing import Dict, Any, List, Optional
from datetime import datetime

from payment_orchestrator.models.payment import Payment
from payment_orchestrator.models.transaction import Transaction
from payment_orchestrator.core.validator import PaymentValidator
from payment_orchestrator.core.fraud_detector import FraudDetector
from payment_orchestrator.core.processor import PaymentProcessor
from payment_orchestrator.services.encryptor import PaymentEncryptor
from payment_orchestrator.services.idempotency_manager import IdempotencyManager
from payment_orchestrator.services.email_notifier import EmailNotifier
from payment_orchestrator.services.queue_manager import RetryQueueManager
from payment_orchestrator.services.db_manager import TransactionStore

logger = logging.getLogger(__name__)


class PaymentOrchestrator:
    """
    Main orchestrator implementing the facade pattern.
    
    This class coordinates all payment processing services and implements
    the complete payment flow from validation to notification.
    """
    
    def __init__(self, secret_name: str,
                 sqs_queue_url: str, dynamodb_table: str,
                 region: str = "us-east-1", email_api_endpoint: str = None,
                 redis_endpoint: str = None):
        """
        Initialize the PaymentOrchestrator with all service dependencies.
        
        Args:
            secret_name: Secrets Manager secret name
            sqs_queue_url: SQS queue URL for retries
            dynamodb_table: DynamoDB table name
            region: AWS region
            email_api_endpoint: Lambda email API endpoint
            redis_endpoint: ElastiCache Redis endpoint for idempotency
        """
        self.region = region
        
        # Initialize all service classes
        self.validator = PaymentValidator()
        self.fraud_detector = FraudDetector()
        self.encryptor = PaymentEncryptor("none", region)  # No-op encryptor
        self.queue_manager = RetryQueueManager(sqs_queue_url, region)
        self.transaction_store = TransactionStore(dynamodb_table, region)
        
        # Initialize email notifier with Lambda API
        if email_api_endpoint:
            self.email_notifier = EmailNotifier(email_api_endpoint)
        else:
            self.email_notifier = EmailNotifier()  # Uses default endpoint
        
        # Initialize idempotency manager if Redis endpoint provided
        if redis_endpoint:
            self.idempotency_manager = IdempotencyManager(redis_endpoint)
        else:
            self.idempotency_manager = None
            logger.warning("Redis endpoint not provided - idempotency checks disabled")
        
        logger.info("PaymentOrchestrator initialized successfully with email notifications")
    
    def _process_payment_internal(self, payment_data: dict, payment_api_endpoint: str, transaction_id: str) -> Dict[str, Any]:
        """
        Internal payment processing without idempotency check (used by background processing).
        
        Args:
            payment_data: Payment request dictionary (decrypted)
            payment_api_endpoint: Lambda API endpoint for payment processing
            transaction_id: Pre-generated transaction ID
            
        Returns:
            Dictionary with transaction result
        """
        logger.info(f"Starting internal payment processing: {transaction_id}")
        
        try:
            # Step 1: Validate payment
            is_valid, error = self.validator.validate(payment_data)
            if not is_valid:
                logger.error(f"Validation failed: {error}")
                return self._create_error_response(transaction_id, error)
            
            # Step 2: Run fraud check
            is_fraud, fraud_reason = self.fraud_detector.check_fraud(payment_data)
            if is_fraud:
                logger.error(f"Fraud detected: {fraud_reason}")
                
                # Send fraud alert email via Lambda API
                self.email_notifier.notify_fraud_alert(
                    transaction_id, payment_data.get("amount", 0), 
                    payment_data.get("currency", "USD"),
                    payment_data.get("cardholder_name", "Customer"),
                    payment_data.get("email", ""), fraud_reason
                )
                
                return self._create_error_response(transaction_id, f"Fraud detected: {fraud_reason}")
            
            # Step 3: Encrypt card number and CVV for DynamoDB storage
            encrypted_card = self.encryptor.encrypt(payment_data["card_number"])
            encrypted_cvv = self.encryptor.encrypt(payment_data["cvv"])
            
            if not encrypted_card or not encrypted_cvv:
                error = "Encryption failed"
                logger.error(error)
                return self._create_error_response(transaction_id, error)
            
            # Create payment object
            payment = Payment(
                cardholder_name=payment_data["cardholder_name"],
                card_number=payment_data["card_number"],
                expiry_month=payment_data["expiry_month"],
                expiry_year=payment_data["expiry_year"],
                cvv=payment_data["cvv"],
                amount=payment_data["amount"],
                currency=payment_data["currency"],
                email=payment_data["email"],
                transaction_id=transaction_id,
                timestamp=datetime.utcnow().isoformat()
            )
            
            # Step 4: Save transaction with status PENDING to DynamoDB
            transaction_record = {
                "transaction_id": transaction_id,
                "status": "PENDING",
                "amount": payment.amount,
                "currency": payment.currency,
                "cardholder_name": payment.cardholder_name,
                "masked_card": payment.get_masked_card(),
                "email": payment.email,
                "timestamp": payment.timestamp,
                "encrypted_card": encrypted_card,
                "encrypted_cvv": encrypted_cvv,
                "retry_count": 0
            }
            
            if not self.transaction_store.save_transaction(transaction_record):
                error = "Failed to save transaction"
                logger.error(error)
                return self._create_error_response(transaction_id, error)
            
            logger.info(f"✅ Transaction saved to DynamoDB: {transaction_id}")
            
            # Step 5: Process payment using PaymentProcessor
            processor = PaymentProcessor(payment_api_endpoint)
            success, message = processor.process(
                payment.card_number,
                payment.cvv,
                payment.amount,
                payment.currency,
                payment.cardholder_name,
                payment.expiry_month,
                payment.expiry_year,
                transaction_id
            )
            
            # Step 6: Update transaction status in DynamoDB
            if success:
                # SUCCESS path
                self.transaction_store.update_transaction_status(
                    transaction_id, "SUCCESS"
                )
                
                # Send success email via Lambda API
                self.email_notifier.notify_payment_success(
                    transaction_id, payment.amount, payment.currency,
                    payment.cardholder_name, payment.email
                )
                
                logger.info(f"Payment processed successfully: {transaction_id}")
                return {
                    "success": True,
                    "transaction_id": transaction_id,
                    "status": "SUCCESS",
                    "message": message
                }
            else:
                # FAILED path
                self.transaction_store.update_transaction_status(
                    transaction_id, "FAILED", message
                )
                
                # Send to SQS retry queue
                self.queue_manager.send_retry_message(payment_data, retry_count=0)
                
                # Send failure email via Lambda API
                self.email_notifier.notify_payment_failure(
                    transaction_id, payment.amount, payment.currency,
                    payment.cardholder_name, payment.email, message
                )
                
                logger.warning(f"Payment failed: {transaction_id}")
                return {
                    "success": False,
                    "transaction_id": transaction_id,
                    "status": "FAILED",
                    "message": message
                }
        
        except Exception as e:
            error = f"Unexpected error during payment processing: {str(e)}"
            logger.error(error)
            return self._create_error_response(transaction_id, error)
    
    def process_payment(self, payment_data: dict, payment_api_endpoint: str) -> Dict[str, Any]:
        """
        Process payment following the complete orchestration flow.
        
        Flow:
        1. Check idempotency (if payment already processed)
        2. Validate payment
        3. Run fraud check
        4. Encrypt sensitive data
        5. Save transaction as PENDING
        6. Process payment via Lambda API
        7. Update transaction status
        8. Send notifications (SNS + SES) or queue for retry
        
        Args:
            payment_data: Payment request dictionary
            payment_api_endpoint: Lambda API endpoint for payment processing
            
        Returns:
            Dictionary with transaction result
        """
        transaction_id = str(uuid.uuid4())
        logger.info(f"Starting payment processing: {transaction_id}")
        
        try:
            # Step 1: Check idempotency using Redis
            if self.idempotency_manager:
                idempotency_key = self.idempotency_manager.generate_idempotency_key(payment_data)
                
                # Prepare transaction data for idempotency check
                transaction_data = {
                    "transaction_id": transaction_id,
                    "amount": payment_data["amount"],
                    "currency": payment_data["currency"],
                    "cardholder_name": payment_data["cardholder_name"],
                    "email": payment_data["email"],
                    "timestamp": datetime.utcnow().isoformat()
                }
                
                # Check if payment already processed and set as processing if not
                existing_transaction = self.idempotency_manager.check_and_set_processing(
                    idempotency_key, transaction_data
                )
                
                if existing_transaction:
                    logger.info(f"Idempotent request detected: {existing_transaction['transaction_id']}")
                    return {
                        "success": existing_transaction["status"] == "SUCCESS",
                        "transaction_id": existing_transaction["transaction_id"],
                        "status": existing_transaction["status"],
                        "message": f"Payment already processed (idempotent) - Status: {existing_transaction['status']}"
                    }
            else:
                idempotency_key = None
            
            # Step 2: Validate payment
            is_valid, error = self.validator.validate(payment_data)
            if not is_valid:
                logger.error(f"Validation failed: {error}")
                return self._create_error_response(transaction_id, error)
            
            # Step 3: Run fraud check
            is_fraud, fraud_reason = self.fraud_detector.check_fraud(payment_data)
            if is_fraud:
                logger.error(f"Fraud detected: {fraud_reason}")
                
                # Send fraud alert email via Lambda API
                self.email_notifier.notify_fraud_alert(
                    transaction_id, payment_data.get("amount", 0), 
                    payment_data.get("currency", "USD"),
                    payment_data.get("cardholder_name", "Customer"),
                    payment_data.get("email", ""), fraud_reason
                )
                
                return self._create_error_response(transaction_id, f"Fraud detected: {fraud_reason}")
            
            # Step 4: Encrypt card number and CVV using KMS
            encrypted_card = self.encryptor.encrypt(payment_data["card_number"])
            encrypted_cvv = self.encryptor.encrypt(payment_data["cvv"])
            
            if not encrypted_card or not encrypted_cvv:
                error = "Encryption failed"
                logger.error(error)
                return self._create_error_response(transaction_id, error)
            
            # Create payment object
            payment = Payment(
                cardholder_name=payment_data["cardholder_name"],
                card_number=payment_data["card_number"],
                expiry_month=payment_data["expiry_month"],
                expiry_year=payment_data["expiry_year"],
                cvv=payment_data["cvv"],
                amount=payment_data["amount"],
                currency=payment_data["currency"],
                email=payment_data["email"],
                transaction_id=transaction_id,
                timestamp=datetime.utcnow().isoformat()
            )
            
            # Step 5: Save transaction with status PENDING to DynamoDB
            transaction_record = {
                "transaction_id": transaction_id,
                "status": "PENDING",
                "amount": payment.amount,
                "currency": payment.currency,
                "cardholder_name": payment.cardholder_name,
                "masked_card": payment.get_masked_card(),
                "email": payment.email,
                "timestamp": payment.timestamp,
                "encrypted_card": encrypted_card,
                "encrypted_cvv": encrypted_cvv,
                "retry_count": 0
            }
            
            if not self.transaction_store.save_transaction(transaction_record):
                error = "Failed to save transaction"
                logger.error(error)
                return self._create_error_response(transaction_id, error)
            
            # Step 6: Process payment using PaymentProcessor
            processor = PaymentProcessor(payment_api_endpoint)
            success, message = processor.process(
                payment.card_number,
                payment.cvv,
                payment.amount,
                payment.currency,
                payment.cardholder_name,
                payment.expiry_month,
                payment.expiry_year,
                transaction_id
            )
            
            # Step 7: Update transaction status in DynamoDB
            if success:
                # Step 8a: SUCCESS path
                self.transaction_store.update_transaction_status(
                    transaction_id, "SUCCESS"
                )
                
                # Update idempotency status in Redis
                if self.idempotency_manager and idempotency_key:
                    self.idempotency_manager.update_transaction_status(
                        idempotency_key, "SUCCESS", {"payment_message": message}
                    )
                
                # Send success email via Lambda API
                self.email_notifier.notify_payment_success(
                    transaction_id, payment.amount, payment.currency,
                    payment.cardholder_name, payment.email
                )
                
                logger.info(f"Payment processed successfully: {transaction_id}")
                return {
                    "success": True,
                    "transaction_id": transaction_id,
                    "status": "SUCCESS",
                    "message": message
                }
            else:
                # Step 8b: FAILED path
                self.transaction_store.update_transaction_status(
                    transaction_id, "FAILED", message
                )
                
                # Update idempotency status in Redis
                if self.idempotency_manager and idempotency_key:
                    self.idempotency_manager.update_transaction_status(
                        idempotency_key, "FAILED", {"error_message": message}
                    )
                
                # Send to SQS retry queue
                self.queue_manager.send_retry_message(payment_data, retry_count=0)
                
                # Send failure email via Lambda API
                self.email_notifier.notify_payment_failure(
                    transaction_id, payment.amount, payment.currency,
                    payment.cardholder_name, payment.email, message
                )
                
                logger.warning(f"Payment failed: {transaction_id}")
                return {
                    "success": False,
                    "transaction_id": transaction_id,
                    "status": "FAILED",
                    "message": message
                }
        
        except Exception as e:
            error = f"Unexpected error during payment processing: {str(e)}"
            logger.error(error)
            
            # Update idempotency status to FAILED in Redis
            if self.idempotency_manager and 'idempotency_key' in locals():
                self.idempotency_manager.update_transaction_status(
                    idempotency_key, "FAILED", {"error_message": error}
                )
            
            return self._create_error_response(transaction_id, error)
    
    def retry_failed_payment(self, payment_data: dict, retry_count: int, payment_api_endpoint: str) -> Dict[str, Any]:
        """
        Retry a failed payment from the queue.
        
        Args:
            payment_data: Original payment data
            retry_count: Current retry attempt number
            payment_api_endpoint: Lambda API endpoint for payment processing
            
        Returns:
            Dictionary with retry result
        """
        logger.info(f"Retrying payment, attempt {retry_count + 1}")
        
        # Maximum 3 retries
        if retry_count >= 3:
            logger.error("Maximum retry attempts reached")
            return {
                "success": False,
                "message": "Maximum retry attempts exceeded"
            }
        
        # Process payment again
        result = self.process_payment(payment_data, payment_api_endpoint)
        
        # If still failed and under retry limit, send back to queue
        if not result.get("success") and retry_count < 2:
            self.queue_manager.send_retry_message(payment_data, retry_count + 1)
        
        return result
    
    def get_transaction_history(self, email: Optional[str] = None) -> List[Dict[str, Any]]:
        """
        Retrieve transaction history.
        
        Args:
            email: Optional email filter
            
        Returns:
            List of transaction dictionaries
        """
        if email:
            transactions = self.transaction_store.query_transactions_by_email(email)
        else:
            transactions = self.transaction_store.get_all_transactions()
        
        logger.info(f"Retrieved {len(transactions)} transactions")
        return transactions
    
    def _create_error_response(self, transaction_id: str, error: str) -> Dict[str, Any]:
        """
        Create standardized error response.
        
        Args:
            transaction_id: Transaction ID
            error: Error message
            
        Returns:
            Error response dictionary
        """
        return {
            "success": False,
            "transaction_id": transaction_id,
            "status": "ERROR",
            "message": error
        }
    def _create_error_response(self, transaction_id: str, error: str) -> Dict[str, Any]:
        """Create standardized error response."""
        return {
            "success": False,
            "transaction_id": transaction_id,
            "status": "FAILED",
            "error": error
        }
    def process_payment_async_with_encryption(self, payment_data: dict, payment_api_endpoint: str, idempotency_key: str) -> Dict[str, Any]:
        """
        Process payment asynchronously with Redis encryption handling.
        
        This method handles:
        1. Encrypting card data before Redis storage
        2. Decrypting card data during processing
        3. Removing sensitive data after processing
        
        Args:
            payment_data: Payment request dictionary (plaintext)
            payment_api_endpoint: Lambda API endpoint for payment processing
            idempotency_key: Redis idempotency key
            
        Returns:
            Dictionary with transaction result
        """
        transaction_id = str(uuid.uuid4())
        logger.info(f"Starting async payment processing with encryption: {transaction_id}")
        
        try:
            # Step 1: Encrypt sensitive data for Redis storage
            encrypted_card = self.encryptor.encrypt(payment_data["card_number"])
            encrypted_cvv = self.encryptor.encrypt(payment_data["cvv"])
            
            if not encrypted_card or not encrypted_cvv:
                error = "Encryption failed"
                logger.error(error)
                return self._create_error_response(transaction_id, error)
            
            # Step 2: Store encrypted data in Redis with INITIALIZED status
            encrypted_payment_data = {
                **payment_data,
                "card_number": encrypted_card,  # Encrypted
                "cvv": encrypted_cvv           # Encrypted
            }
            
            transaction_data = {
                "transaction_id": transaction_id,
                "payment_data": encrypted_payment_data,
                "status": "INITIALIZED",
                "amount": payment_data["amount"],
                "currency": payment_data["currency"],
                "email": payment_data["email"],
                "timestamp": datetime.utcnow().isoformat()
            }
            
            # Store in Redis
            if self.idempotency_manager:
                success = self.idempotency_manager.redis_client.set(
                    idempotency_key,
                    json.dumps(transaction_data),
                    ssl=True,
                    ex=86400  # 24 hours
                )
                
                if not success:
                    error = "Failed to store encrypted payment data"
                    logger.error(error)
                    return self._create_error_response(transaction_id, error)
            
            return {
                "success": True,
                "transaction_id": transaction_id,
                "idempotency_key": idempotency_key,
                "status": "INITIALIZED",
                "message": "Payment initialized with encryption"
            }
            
        except Exception as e:
            error = f"Unexpected error during async payment initialization: {str(e)}"
            logger.error(error)
            return self._create_error_response(transaction_id, error)
    
    def process_encrypted_payment_from_redis(self, idempotency_key: str, payment_api_endpoint: str) -> Dict[str, Any]:
        """
        Process payment from encrypted Redis data.
        
        Args:
            idempotency_key: Redis key containing encrypted payment data
            payment_api_endpoint: Lambda API endpoint for payment processing
            
        Returns:
            Dictionary with transaction result
        """
        logger.info(f"Processing encrypted payment from Redis: {idempotency_key}")
        
        try:
            # Step 1: Get encrypted data from Redis
            if not self.idempotency_manager:
                error = "Idempotency manager not available"
                logger.error(error)
                return self._create_error_response("unknown", error)
            
            stored_data = self.idempotency_manager.redis_client.get(idempotency_key)
            if not stored_data:
                error = "Payment data not found in Redis"
                logger.error(error)
                return self._create_error_response("unknown", error)
            
            transaction_data = json.loads(stored_data)
            encrypted_payment_data = transaction_data["payment_data"]
            transaction_id = transaction_data["transaction_id"]
            
            # Step 2: Decrypt sensitive data
            decrypted_card = self.encryptor.decrypt(encrypted_payment_data["card_number"])
            decrypted_cvv = self.encryptor.decrypt(encrypted_payment_data["cvv"])
            
            if not decrypted_card or not decrypted_cvv:
                error = "Decryption failed"
                logger.error(error)
                return self._create_error_response(transaction_id, error)
            
            # Step 3: Create decrypted payment data for processing
            decrypted_payment_data = {
                **encrypted_payment_data,
                "card_number": decrypted_card,  # Decrypted
                "cvv": decrypted_cvv           # Decrypted
            }
            
            # Step 4: Update Redis status to PROCESSING
            transaction_data["status"] = "PROCESSING"
            transaction_data["processing_started"] = datetime.utcnow().isoformat()
            
            ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
            self.idempotency_manager.redis_client.set(
                idempotency_key,
                json.dumps(transaction_data),
                ex=ttl if ttl > 0 else 86400
            )
            
            # Step 5: Process payment with decrypted data
            result = self.process_payment(decrypted_payment_data, payment_api_endpoint)
            
            # Step 6: Update Redis with final status and remove sensitive data
            final_status = "SUCCESS" if result["success"] else "FAILED"
            
            # Remove sensitive payment_data from Redis
            if "payment_data" in transaction_data:
                del transaction_data["payment_data"]
            
            transaction_data["status"] = final_status
            transaction_data["completed_at"] = datetime.utcnow().isoformat()
            
            if result["success"]:
                transaction_data["payment_message"] = result.get("message", "Payment completed successfully")
            else:
                transaction_data["error_message"] = result.get("message", "Payment failed")
            
            # Update Redis with cleaned data
            ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
            self.idempotency_manager.redis_client.set(
                idempotency_key,
                json.dumps(transaction_data),
                ex=ttl if ttl > 0 else 86400
            )
            
            return result
            
        except Exception as e:
            error = f"Unexpected error during encrypted payment processing: {str(e)}"
            logger.error(error)
            
            # Update Redis with error status
            if self.idempotency_manager and 'transaction_data' in locals():
                if "payment_data" in transaction_data:
                    del transaction_data["payment_data"]  # Remove sensitive data
                transaction_data["status"] = "FAILED"
                transaction_data["error_message"] = error
                transaction_data["completed_at"] = datetime.utcnow().isoformat()
                
                ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
                self.idempotency_manager.redis_client.set(
                    idempotency_key,
                    json.dumps(transaction_data),
                    ex=ttl if ttl > 0 else 86400
                )
            
            return self._create_error_response(
                transaction_data.get("transaction_id", "unknown") if 'transaction_data' in locals() else "unknown", 
                error
            )
    def init_payment_async(self, payment_data: dict) -> Dict[str, Any]:
        """
        Initialize payment asynchronously - handles all Redis and encryption logic.
        
        Args:
            payment_data: Payment request dictionary (plaintext)
            
        Returns:
            Dictionary with idempotency_key and transaction_id
        """
        logger.info("Initializing async payment")
        
        try:
            # Check if idempotency manager is available
            if not self.idempotency_manager:
                error = "Idempotency service not available - Redis not configured"
                logger.error(error)
                return {"success": False, "error": error}
            
            # Check if Redis client is connected
            if not self.idempotency_manager.redis_client:
                error = "Redis connection failed - idempotency service unavailable"
                logger.error(error)
                return {"success": False, "error": error}
            
            idempotency_key = self.idempotency_manager.generate_idempotency_key(payment_data)
            transaction_id = str(uuid.uuid4())
            
            # Encrypt sensitive data
            encrypted_card = self.encryptor.encrypt(payment_data["card_number"])
            encrypted_cvv = self.encryptor.encrypt(payment_data["cvv"])
            
            if not encrypted_card or not encrypted_cvv:
                error = "Encryption failed"
                logger.error(error)
                return {"success": False, "error": error}
            
            # Store encrypted data in Redis
            encrypted_payment_data = {
                **payment_data,
                "card_number": encrypted_card,
                "cvv": encrypted_cvv
            }
            
            transaction_data = {
                "transaction_id": transaction_id,
                "payment_data": encrypted_payment_data,
                "status": "INITIALIZED",
                "amount": payment_data["amount"],
                "currency": payment_data["currency"],
                "email": payment_data["email"],
                "timestamp": datetime.utcnow().isoformat()
            }
            
            success = self.idempotency_manager.redis_client.set(
                idempotency_key,
                json.dumps(transaction_data),
                ex=86400  # 24 hours
            )
            
            if not success:
                error = "Failed to store payment data"
                logger.error(error)
                return {"success": False, "error": error}
            
            logger.info(f"Payment initialized successfully: {transaction_id}")
            return {
                "success": True,
                "idempotency_key": idempotency_key,
                "transaction_id": transaction_id,
                "message": "Payment initialized with encryption"
            }
            
        except Exception as e:
            error = f"Unexpected error during payment initialization: {str(e)}"
            logger.error(error)
            return {"success": False, "error": error}
    
    def process_payment_async(self, idempotency_key: str, payment_api_endpoint: str) -> Dict[str, Any]:
        """
        Process payment asynchronously using idempotency key.
        
        Args:
            idempotency_key: Redis key containing encrypted payment data
            payment_api_endpoint: Lambda API endpoint for payment processing
            
        Returns:
            Dictionary with processing status
        """
        logger.info(f"Processing async payment: {idempotency_key}")
        
        try:
            if not self.idempotency_manager:
                error = "Idempotency service not available"
                logger.error(error)
                return {"success": False, "error": error}
            
            # Get data from Redis
            stored_data = self.idempotency_manager.redis_client.get(idempotency_key)
            if not stored_data:
                error = "Payment not found or expired"
                logger.error(error)
                return {"success": False, "error": error}
            
            transaction_data = json.loads(stored_data)
            current_status = transaction_data.get("status")
            
            # Check current status
            if current_status == "PROCESSING":
                return {
                    "success": True,
                    "transaction_id": transaction_data["transaction_id"],
                    "status": "PROCESSING",
                    "message": "Payment is already being processed"
                }
            elif current_status == "SUCCESS":
                return {
                    "success": True,
                    "transaction_id": transaction_data["transaction_id"],
                    "status": "SUCCESS",
                    "message": "Payment already completed successfully"
                }
            elif current_status == "FAILED":
                return {
                    "success": False,
                    "transaction_id": transaction_data["transaction_id"],
                    "status": "FAILED",
                    "message": transaction_data.get("error_message", "Payment already failed")
                }
            
            # Update status to PROCESSING
            transaction_data["status"] = "PROCESSING"
            transaction_data["processing_started"] = datetime.utcnow().isoformat()
            
            ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
            success = self.idempotency_manager.redis_client.set(
                idempotency_key,
                json.dumps(transaction_data),
                ex=ttl if ttl > 0 else 86400
            )
            
            if not success:
                error = "Failed to update payment status"
                logger.error(error)
                return {"success": False, "error": error}
            
            logger.info(f"Payment processing started: {transaction_data['transaction_id']}")
            return {
                "success": True,
                "transaction_id": transaction_data["transaction_id"],
                "status": "PROCESSING",
                "message": "Payment processing started",
                "idempotency_key": idempotency_key,
                "payment_api_endpoint": payment_api_endpoint
            }
            
        except Exception as e:
            error = f"Unexpected error during payment processing: {str(e)}"
            logger.error(error)
            return {"success": False, "error": error}
    
    def get_payment_status(self, idempotency_key: str) -> Dict[str, Any]:
        """
        Get payment status using idempotency key.
        
        Args:
            idempotency_key: Redis key for payment
            
        Returns:
            Dictionary with payment status
        """
        logger.info(f"Getting payment status: {idempotency_key}")
        
        try:
            if not self.idempotency_manager:
                error = "Idempotency service not available"
                logger.error(error)
                return {"success": False, "error": error}
            
            stored_data = self.idempotency_manager.redis_client.get(idempotency_key)
            if not stored_data:
                error = "Payment not found or expired"
                logger.error(error)
                return {"success": False, "error": error}
            
            transaction_data = json.loads(stored_data)
            
            return {
                "success": True,
                "transaction_id": transaction_data.get("transaction_id"),
                "status": transaction_data.get("status", "UNKNOWN"),
                "message": transaction_data.get("payment_message") or transaction_data.get("error_message", ""),
                "amount": transaction_data.get("amount"),
                "currency": transaction_data.get("currency")
            }
            
        except Exception as e:
            error = f"Error retrieving payment status: {str(e)}"
            logger.error(error)
            return {"success": False, "error": error}
    def process_payment_background(self, idempotency_key: str, payment_api_endpoint: str) -> Dict[str, Any]:
        """
        Background processing method that handles the complete payment flow with encryption/decryption.
        
        Args:
            idempotency_key: Redis key containing encrypted payment data
            payment_api_endpoint: Lambda API endpoint for payment processing
            
        Returns:
            Dictionary with processing result
        """
        logger.info(f"🔄 Starting background payment processing: {idempotency_key}")
        logger.info(f"📍 Payment API endpoint: {payment_api_endpoint}")
        
        try:
            if not self.idempotency_manager:
                error = "Idempotency service not available"
                logger.error(error)
                return {"success": False, "error": error}
            
            # Get data from Redis
            logger.info(f"📥 Fetching data from Redis...")
            stored_data = self.idempotency_manager.redis_client.get(idempotency_key)
            if not stored_data:
                error = "Payment data not found"
                logger.error(error)
                return {"success": False, "error": error}
            
            transaction_data = json.loads(stored_data)
            current_status = transaction_data.get("status")
            transaction_id = transaction_data["transaction_id"]
            
            logger.info(f"✅ Retrieved transaction data: {transaction_id}, Status: {current_status}")
            
            # Check current status
            if current_status == "PROCESSING":
                logger.info(f"⚠️ Payment already being processed: {transaction_id}")
                return {
                    "success": False,
                    "transaction_id": transaction_id,
                    "status": "PROCESSING",
                    "message": "Payment is already being processed"
                }
            elif current_status == "SUCCESS":
                logger.info(f"✅ Payment already completed: {transaction_id}")
                return {
                    "success": True,
                    "transaction_id": transaction_id,
                    "status": "SUCCESS",
                    "message": transaction_data.get("payment_message", "Payment already completed")
                }
            elif current_status == "FAILED":
                logger.info(f"❌ Payment already failed: {transaction_id}")
                return {
                    "success": False,
                    "transaction_id": transaction_id,
                    "status": "FAILED",
                    "message": transaction_data.get("error_message", "Payment already failed")
                }
            elif current_status != "INITIALIZED":
                error = f"Invalid payment status: {current_status}"
                logger.error(error)
                return {"success": False, "error": error, "transaction_id": transaction_id}
            
            # Status is INITIALIZED - proceed with processing
            logger.info(f"✅ Status is INITIALIZED, proceeding with payment processing")
            
            # Update status to PROCESSING
            transaction_data["status"] = "PROCESSING"
            transaction_data["processing_started"] = datetime.utcnow().isoformat()
            
            ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
            self.idempotency_manager.redis_client.set(
                idempotency_key,
                json.dumps(transaction_data),
                ex=ttl if ttl > 0 else 86400
            )
            logger.info(f"✅ Status updated to PROCESSING")
            
            # Get encrypted payment data
            encrypted_payment_data = transaction_data.get("payment_data")
            if not encrypted_payment_data:
                error = "Payment data missing from Redis"
                logger.error(error)
                self._update_redis_status(idempotency_key, "FAILED", {"error_message": error})
                return {"success": False, "error": error, "transaction_id": transaction_id}
            
            # Decrypt card data for processing
            logger.info(f"🔓 Decrypting payment data...")
            decrypted_card = self.encryptor.decrypt(encrypted_payment_data["card_number"])
            decrypted_cvv = self.encryptor.decrypt(encrypted_payment_data["cvv"])
            
            if not decrypted_card or not decrypted_cvv:
                error = "Decryption failed"
                logger.error(error)
                self._update_redis_status(idempotency_key, "FAILED", {"error_message": error})
                return {"success": False, "error": error, "transaction_id": transaction_id}
            
            logger.info(f"✅ Decryption successful")
            
            # Create decrypted payment data
            decrypted_payment_data = {
                **encrypted_payment_data,
                "card_number": decrypted_card,
                "cvv": decrypted_cvv
            }
            
            # Process payment with decrypted data (bypass idempotency check)
            logger.info(f"💳 Processing payment via API: {payment_api_endpoint}")
            result = self._process_payment_internal(decrypted_payment_data, payment_api_endpoint, transaction_id)
            logger.info(f"💳 Payment processing result: {result}")
            
            # Update Redis with final status and remove sensitive data
            final_status = "SUCCESS" if result["success"] else "FAILED"
            
            update_data = {
                "status": final_status,
                "completed_at": datetime.utcnow().isoformat()
            }
            
            if result["success"]:
                update_data["payment_message"] = result.get("message", "Payment completed successfully")
            else:
                update_data["error_message"] = result.get("message", "Payment failed")
            
            # Remove sensitive payment_data and update status
            logger.info(f"📝 Updating Redis with final status: {final_status}")
            self._update_redis_status_and_cleanup(idempotency_key, update_data)
            
            logger.info(f"✅ Background payment processing completed: {transaction_id} - {final_status}")
            return result
            
        except Exception as e:
            error = f"Background processing error: {str(e)}"
            logger.error(error)
            import traceback
            logger.error(f"Traceback: {traceback.format_exc()}")
            
            # Try to update Redis with error
            if 'idempotency_key' in locals() and 'transaction_id' in locals():
                self._update_redis_status(idempotency_key, "FAILED", {"error_message": error})
            
            return {
                "success": False, 
                "error": error,
                "transaction_id": transaction_id if 'transaction_id' in locals() else None
            }

    
    def _update_redis_status(self, idempotency_key: str, status: str, additional_data: Dict[str, Any]) -> bool:
        """Update Redis status with additional data."""
        try:
            stored_data = self.idempotency_manager.redis_client.get(idempotency_key)
            if stored_data:
                transaction_data = json.loads(stored_data)
                transaction_data["status"] = status
                transaction_data.update(additional_data)
                
                ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
                return self.idempotency_manager.redis_client.set(
                    idempotency_key,
                    json.dumps(transaction_data),
                    ex=ttl if ttl > 0 else 86400
                )
            return False
        except Exception as e:
            logger.error(f"Error updating Redis status: {e}")
            return False
    
    def _update_redis_status_and_cleanup(self, idempotency_key: str, update_data: Dict[str, Any]) -> bool:
        """Update Redis status and remove sensitive payment_data."""
        try:
            stored_data = self.idempotency_manager.redis_client.get(idempotency_key)
            if stored_data:
                transaction_data = json.loads(stored_data)
                
                # Remove sensitive payment_data
                if "payment_data" in transaction_data:
                    del transaction_data["payment_data"]
                
                # Update with new data
                transaction_data.update(update_data)
                
                ttl = self.idempotency_manager.redis_client.ttl(idempotency_key)
                return self.idempotency_manager.redis_client.set(
                    idempotency_key,
                    json.dumps(transaction_data),
                    ex=ttl if ttl > 0 else 86400
                )
            return False
        except Exception as e:
            logger.error(f"Error updating Redis with cleanup: {e}")
            return False