<?php
// Payment Security Configuration
// PCI DSS Compliance and Security Measures

// PCI DSS Compliance Settings
define('PCI_COMPLIANCE_LEVEL', 'SAQ_A'); // Self-Assessment Questionnaire A (for merchants not storing card data)

// Security Headers for Payment Pages
define('PAYMENT_SECURITY_HEADERS', [
    'Strict-Transport-Security' => 'max-age=31536000; includeSubDomains; preload',
    'X-Content-Type-Options' => 'nosniff',
    'X-Frame-Options' => 'DENY',
    'X-XSS-Protection' => '1; mode=block',
    'Referrer-Policy' => 'strict-origin-when-cross-origin',
    'Content-Security-Policy' => "default-src 'self'; script-src 'self' 'unsafe-inline' https://js.paypal.com https://www.paypal.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; frame-src https://www.paypal.com https://www.sandbox.paypal.com;",
]);

// Rate Limiting Settings
define('PAYMENT_RATE_LIMIT_REQUESTS', 10); // Max requests per window
define('PAYMENT_RATE_LIMIT_WINDOW', 300);  // 5 minutes in seconds
define('PAYMENT_RATE_LIMIT_BLOCK_TIME', 900); // 15 minutes block

// Input Validation Rules
define('PAYMENT_VALIDATION_RULES', [
    'amount' => [
        'required' => true,
        'type' => 'numeric',
        'min' => 0.01,
        'max' => 10000.00,
        'decimal_places' => 2
    ],
    'currency' => [
        'required' => true,
        'type' => 'string',
        'allowed_values' => ['USD', 'EUR', 'GBP', 'ZAR', 'ZWD']
    ],
    'discount_code' => [
        'required' => false,
        'type' => 'string',
        'max_length' => 50,
        'pattern' => '/^[A-Z0-9_-]+$/i'
    ],
    'gateway' => [
        'required' => true,
        'type' => 'string',
        'allowed_values' => ['paypal', 'paynow']
    ]
]);

// Data Sanitization Functions
class PaymentSecurity {
    /**
     * Sanitize payment input data
     */
    public static function sanitizeInput($data, $rules) {
        $sanitized = [];

        foreach ($rules as $field => $rule) {
            if (!isset($data[$field])) {
                if ($rule['required']) {
                    throw new Exception("Required field missing: {$field}");
                }
                continue;
            }

            $value = $data[$field];
            $sanitized[$field] = self::sanitizeValue($value, $rule);
        }

        return $sanitized;
    }

    /**
     * Sanitize individual value based on rules
     */
    private static function sanitizeValue($value, $rule) {
        // Trim whitespace
        $value = trim($value);

        // Type validation and conversion
        switch ($rule['type']) {
            case 'numeric':
                if (!is_numeric($value)) {
                    $fieldName = isset($rule['field']) ? $rule['field'] : 'unknown';
                    throw new Exception("Invalid numeric value for field: {$fieldName}");
                }
                $value = (float) $value;

                // Range validation
                if (isset($rule['min']) && $value < $rule['min']) {
                    throw new Exception("Value below minimum: {$rule['min']}");
                }
                if (isset($rule['max']) && $value > $rule['max']) {
                    throw new Exception("Value above maximum: {$rule['max']}");
                }

                // Decimal places validation
                if (isset($rule['decimal_places'])) {
                    $decimalPlaces = strlen(substr(strrchr($value, "."), 1));
                    if ($decimalPlaces > $rule['decimal_places']) {
                        throw new Exception("Too many decimal places. Maximum: {$rule['decimal_places']}");
                    }
                }
                break;

            case 'string':
                $value = filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);

                // Length validation
                if (isset($rule['max_length']) && strlen($value) > $rule['max_length']) {
                    throw new Exception("Value too long. Maximum length: {$rule['max_length']}");
                }

                // Pattern validation
                if (isset($rule['pattern']) && !preg_match($rule['pattern'], $value)) {
                    throw new Exception("Value does not match required pattern");
                }
                break;
        }

        // Allowed values validation
        if (isset($rule['allowed_values']) && !in_array($value, $rule['allowed_values'])) {
            throw new Exception("Value not in allowed list");
        }

        return $value;
    }

    /**
     * Validate CSRF token for payment forms
     */
    public static function validateCSRFToken($token) {
        if (!isset($_SESSION['csrf_token'])) {
            return false;
        }

        if (!hash_equals($_SESSION['csrf_token'], $token)) {
            // Log potential CSRF attack
            self::logSecurityEvent('csrf_attempt', [
                'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
                'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
                'session_id' => session_id()
            ]);
            return false;
        }

        return true;
    }

    /**
     * Generate CSRF token
     */
    public static function generateCSRFToken() {
        if (!isset($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }

    /**
     * Check rate limiting for payment requests
     */
    public static function checkRateLimit($userId = null) {
        $identifier = $userId ?: ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
        $cacheKey = "payment_rate_limit_{$identifier}";

        // Simple file-based rate limiting (in production, use Redis or similar)
        $cacheFile = sys_get_temp_dir() . "/{$cacheKey}.cache";
        $now = time();

        if (file_exists($cacheFile)) {
            $data = json_decode(file_get_contents($cacheFile), true);

            if ($data['block_until'] > $now) {
                // Still blocked
                throw new Exception('Too many payment requests. Please try again later.');
            }

            if ($data['window_start'] + PAYMENT_RATE_LIMIT_WINDOW > $now) {
                // Within window
                $data['requests']++;

                if ($data['requests'] > PAYMENT_RATE_LIMIT_REQUESTS) {
                    // Block user
                    $data['block_until'] = $now + PAYMENT_RATE_LIMIT_BLOCK_TIME;
                    file_put_contents($cacheFile, json_encode($data));

                    self::logSecurityEvent('rate_limit_exceeded', [
                        'identifier' => $identifier,
                        'requests' => $data['requests']
                    ]);

                    throw new Exception('Too many payment requests. Please try again later.');
                }
            } else {
                // New window
                $data = [
                    'window_start' => $now,
                    'requests' => 1,
                    'block_until' => 0
                ];
            }
        } else {
            // First request
            $data = [
                'window_start' => $now,
                'requests' => 1,
                'block_until' => 0
            ];
        }

        file_put_contents($cacheFile, json_encode($data));
        return true;
    }

    /**
     * Set security headers for payment pages
     */
    public static function setSecurityHeaders() {
        foreach (PAYMENT_SECURITY_HEADERS as $header => $value) {
            header("{$header}: {$value}");
        }
    }

    /**
     * Validate payment environment (HTTPS required)
     */
    public static function validateEnvironment() {
        // Check if HTTPS is required for payments
        if (PAYMENT_SECURITY_HEADERS['Strict-Transport-Security'] && !isset($_SERVER['HTTPS'])) {
            throw new Exception('HTTPS is required for payment processing');
        }
    }

    /**
     * Log security events
     */
    public static function logSecurityEvent($event, $data = []) {
        $db = getDB();
        $stmt = $db->prepare("
            INSERT INTO payment_logs (action, level, message, context, ip_address, user_agent, created_at)
            VALUES (?, 'warning', ?, ?, ?, ?, NOW())
        ");

        $stmt->execute([
            'security_' . $event,
            "Security event: {$event}",
            json_encode($data),
            $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
        ]);
    }

    /**
     * Encrypt sensitive data (for temporary storage only)
     */
    public static function encryptData($data) {
        $key = hash('sha256', 'PAYMENT_ENCRYPTION_KEY_' . date('Y-m-d'));
        $iv = substr(hash('sha256', 'PAYMENT_IV_' . session_id()), 0, 16);

        return openssl_encrypt(
            json_encode($data),
            'AES-256-CBC',
            $key,
            0,
            $iv
        );
    }

    /**
     * Decrypt sensitive data
     */
    public static function decryptData($encryptedData) {
        $key = hash('sha256', 'PAYMENT_ENCRYPTION_KEY_' . date('Y-m-d'));
        $iv = substr(hash('sha256', 'PAYMENT_IV_' . session_id()), 0, 16);

        $decrypted = openssl_decrypt(
            $encryptedData,
            'AES-256-CBC',
            $key,
            0,
            $iv
        );

        return json_decode($decrypted, true);
    }

    /**
     * Mask sensitive data for logging
     */
    public static function maskSensitiveData($data) {
        $masked = $data;

        // Mask credit card numbers (keep last 4 digits)
        if (isset($masked['card_number'])) {
            $masked['card_number'] = '****-****-****-' . substr($masked['card_number'], -4);
        }

        // Mask CVV
        if (isset($masked['cvv'])) {
            $masked['cvv'] = '***';
        }

        return $masked;
    }

    /**
     * Validate payment gateway credentials
     */
    public static function validateGatewayCredentials($gateway, $credentials) {
        // Basic validation - check required fields are present and not empty
        $requiredFields = [];

        switch ($gateway) {
            case 'paypal':
                $requiredFields = ['api_key', 'api_secret'];
                break;
            case 'paynow':
                $requiredFields = ['api_key', 'merchant_id'];
                break;
        }

        foreach ($requiredFields as $field) {
            if (empty($credentials[$field])) {
                throw new Exception("Missing required credential: {$field}");
            }

            // Basic format validation
            if ($field === 'api_key' || $field === 'api_secret') {
                if (strlen($credentials[$field]) < 10) {
                    throw new Exception("Invalid credential format: {$field}");
                }
            }
        }

        return true;
    }
}

/**
 * PCI DSS Compliance Checklist Functions
 */
class PCICompliance {
    /**
     * Check if system meets basic PCI DSS requirements
     */
    public static function checkCompliance() {
        $issues = [];

        // Check HTTPS
        if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
            $issues[] = 'HTTPS not enabled';
        }

        // Check security headers
        $requiredHeaders = ['Strict-Transport-Security', 'X-Frame-Options', 'X-Content-Type-Options'];
        foreach ($requiredHeaders as $header) {
            $headerSent = false;
            foreach (headers_list() as $sentHeader) {
                if (stripos($sentHeader, $header) === 0) {
                    $headerSent = true;
                    break;
                }
            }
            if (!$headerSent) {
                $issues[] = "Missing security header: {$header}";
            }
        }

        // Check if storing sensitive card data (should not be doing this)
        $db = getDB();
        $stmt = $db->query("SHOW TABLES LIKE 'payment_transactions'");
        if ($stmt->fetch()) {
            // Check if any transaction has card data stored
            $stmt = $db->query("SELECT COUNT(*) as count FROM payment_transactions WHERE gateway_response LIKE '%card%' OR gateway_response LIKE '%number%'");
            $result = $stmt->fetch();
            if ($result['count'] > 0) {
                $issues[] = 'Potential sensitive card data storage detected';
            }
        }

        return $issues;
    }

    /**
     * Generate PCI DSS compliance report
     */
    public static function generateComplianceReport() {
        $issues = self::checkCompliance();

        $report = [
            'compliance_level' => PCI_COMPLIANCE_LEVEL,
            'check_date' => date('Y-m-d H:i:s'),
            'issues' => $issues,
            'compliant' => empty($issues)
        ];

        // Log compliance check
        $db = getDB();
        $stmt = $db->prepare("
            INSERT INTO payment_logs (action, level, message, context, created_at)
            VALUES ('pci_compliance_check', 'info', ?, ?, NOW())
        ");
        $stmt->execute([
            'PCI DSS compliance check completed',
            json_encode($report)
        ]);

        return $report;
    }
}