"""Payment validation service."""

import re
import logging
from datetime import datetime
from typing import Tuple, Optional

logger = logging.getLogger(__name__)


class PaymentValidator:
    """
    Validates payment request data.
    
    This class implements validation rules for payment requests including
    amount checks, card format validation, and expiry verification.
    """
    
    def __init__(self):
        """Initialize the PaymentValidator."""
        logger.info("PaymentValidator initialized")
    
    def validate(self, payment_data: dict) -> Tuple[bool, Optional[str]]:
        """
        Validate payment request.
        
        Args:
            payment_data: Payment information dictionary
            
        Returns:
            Tuple of (is_valid, error_message)
        """
        # Validate amount
        amount = payment_data.get("amount", 0)
        if not isinstance(amount, int) or amount <= 0:
            error = "Amount must be a positive integer"
            logger.warning(f"Validation failed: {error}")
            return False, error
        
        # Validate card number
        card_number = payment_data.get("card_number", "")
        if not self._is_valid_card_number(card_number):
            error = "Invalid card number format"
            logger.warning(f"Validation failed: {error}")
            return False, error
        
        # Validate expiry
        expiry_month = payment_data.get("expiry_month")
        expiry_year = payment_data.get("expiry_year")
        if not self._is_valid_expiry(expiry_month, expiry_year):
            error = "Card has expired or invalid expiry date"
            logger.warning(f"Validation failed: {error}")
            return False, error
        
        # Validate CVV
        cvv = payment_data.get("cvv", "")
        if not self._is_valid_cvv(cvv):
            error = "Invalid CVV format"
            logger.warning(f"Validation failed: {error}")
            return False, error
        
        # Validate email
        email = payment_data.get("email", "")
        if not self._is_valid_email(email):
            error = "Invalid email address"
            logger.warning(f"Validation failed: {error}")
            return False, error
        
        # Validate cardholder name
        cardholder_name = payment_data.get("cardholder_name", "")
        if not cardholder_name or len(cardholder_name.strip()) < 2:
            error = "Invalid cardholder name"
            logger.warning(f"Validation failed: {error}")
            return False, error
        
        logger.info("Payment validation passed")
        return True, None
    
    def _is_valid_card_number(self, card_number: str) -> bool:
        """
        Validate card number format (must be 13-19 digits).
        
        Args:
            card_number: Card number string
            
        Returns:
            True if valid format, False otherwise
        """
        # Remove spaces and dashes
        cleaned = re.sub(r"[\s-]", "", card_number)
        
        # Check if it's all digits and proper length
        if not re.match(r"^\d{13,19}$", cleaned):
            return False
        
        # Luhn algorithm check
        return self._luhn_check(cleaned)
    
    def _luhn_check(self, card_number: str) -> bool:
        """
        Perform Luhn algorithm validation.
        
        Args:
            card_number: Card number string (digits only)
            
        Returns:
            True if passes Luhn check, False otherwise
        """
        digits = [int(d) for d in card_number]
        checksum = 0
        
        # Process from right to left
        for i in range(len(digits) - 2, -1, -1):
            if (len(digits) - 1 - i) % 2 == 1:
                doubled = digits[i] * 2
                checksum += doubled if doubled < 10 else doubled - 9
            else:
                checksum += digits[i]
        
        return (checksum + digits[-1]) % 10 == 0
    
    def _is_valid_expiry(self, month: Optional[int], year: Optional[int]) -> bool:
        """
        Validate card expiry date.
        
        Args:
            month: Expiry month (1-12)
            year: Expiry year (YYYY)
            
        Returns:
            True if not expired and valid format, False otherwise
        """
        if not month or not year:
            return False
        
        if not (1 <= month <= 12):
            return False
        
        if year < 1000 or year > 9999:
            return False
        
        # Check if expired
        now = datetime.utcnow()
        if year < now.year:
            return False
        if year == now.year and month < now.month:
            return False
        
        return True
    
    def _is_valid_cvv(self, cvv: str) -> bool:
        """
        Validate CVV format (3 or 4 digits).
        
        Args:
            cvv: CVV string
            
        Returns:
            True if valid format, False otherwise
        """
        return bool(re.match(r"^\d{3,4}$", cvv))
    
    def _is_valid_email(self, email: str) -> bool:
        """
        Validate email format.
        
        Args:
            email: Email address string
            
        Returns:
            True if valid format, False otherwise
        """
        pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
        return bool(re.match(pattern, email))
