<?php

namespace App\Libraries;

use CodeIgniter\Config\Services;

class MobileMoneyService
{
    private $encrypter;
    private $apiBaseUrl;
    private $apiEndpoint;
    private $accountNo;
    private $encryptedApiKey;

    public function __construct()
    {
        try {
            $this->encrypter = Services::encrypter();
        } catch (\Exception $e) {
            log_message('error', 'Encryption service not available: ' . $e->getMessage());
            $this->encrypter = null;
        }
        
        $this->apiBaseUrl = $_ENV['mobile_money.api_base_url'] ?? 'https://payments.relworx.com/api';
        $this->apiEndpoint = $_ENV['mobile_money.api_endpoint'] ?? '/mobile-money/request-payment';
        $this->accountNo = $_ENV['mobile_money.account_no'] ?? 'REL4737AB23A9';
        
        // Store the API key (encrypted if encryption is available)
        $apiKey = $_ENV['mobile_money.api_key'] ?? 'c786fea736addb.WsdjDxvz5L1Aw800Q-p3fA';
        if ($this->encrypter) {
            $this->encryptedApiKey = $this->encrypter->encrypt($apiKey);
        } else {
            // Fallback: store as base64 encoded (not secure, but functional)
            $this->encryptedApiKey = base64_encode($apiKey);
        }
    }

    /**
     * Decrypt the API key for use in API calls
     */
    private function getDecryptedApiKey(): string
    {
        if ($this->encrypter) {
            return $this->encrypter->decrypt($this->encryptedApiKey);
        } else {
            // Fallback: decode from base64
            return base64_decode($this->encryptedApiKey);
        }
    }

    /**
     * Request mobile money payment
     */
    public function requestPayment(array $paymentData): array
    {
        try {
            // Validate required fields
            $requiredFields = ['msisdn', 'amount', 'currency', 'description', 'reference'];
            foreach ($requiredFields as $field) {
                if (!isset($paymentData[$field]) || empty($paymentData[$field])) {
                    return [
                        'success' => false,
                        'message' => "Missing required field: {$field}"
                    ];
                }
            }

            // Validate reference format (only alphanumeric, underscore and hyphen)
            if (!$this->validateReference($paymentData['reference'])) {
                return [
                    'success' => false,
                    'message' => 'Invalid reference format. Only alphanumeric, underscore and hyphen characters allowed.',
                    'error_code' => 400
                ];
            }

            // Prepare the payload
            $payload = [
                'account_no' => $this->accountNo,
                'reference' => $paymentData['reference'],
                'msisdn' => $paymentData['msisdn'],
                'currency' => $paymentData['currency'],
                'amount' => (float) $paymentData['amount'],
                'description' => $paymentData['description']
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->post($this->apiBaseUrl . $this->apiEndpoint, [
                'json' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/vnd.relworx.v2',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'message' => $responseData['message'],
                    'internal_reference' => $responseData['internal_reference'],
                    'reference' => $paymentData['reference']
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Payment request failed',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Mobile Money API Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Send payment (disbursement) to mobile money account
     */
    public function sendPayment(array $paymentData): array
    {
        try {
            // Validate required fields
            $requiredFields = ['msisdn', 'amount', 'currency', 'reference'];
            foreach ($requiredFields as $field) {
                if (!isset($paymentData[$field]) || empty($paymentData[$field])) {
                    return [
                        'success' => false,
                        'message' => "Missing required field: {$field}"
                    ];
                }
            }

            // Validate reference format
            if (!$this->validateReference($paymentData['reference'])) {
                return [
                    'success' => false,
                    'message' => 'Invalid reference format. Only alphanumeric, underscore and hyphen characters allowed.',
                    'error_code' => 400
                ];
            }

            // Validate phone number
            if (!$this->validatePhoneNumber($paymentData['msisdn'])) {
                return [
                    'success' => false,
                    'message' => 'Invalid phone number format'
                ];
            }

            // Prepare payload for Relworx API
            $payload = [
                'account_no' => $this->accountNo,
                'reference' => $paymentData['reference'],
                'msisdn' => $this->formatPhoneNumber($paymentData['msisdn']),
                'currency' => $paymentData['currency'],
                'amount' => (float) $paymentData['amount'],
                'description' => $paymentData['description'] ?? 'Send Payment'
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->post($this->apiBaseUrl . '/mobile-money/send-payment', [
                'json' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/vnd.relworx.v2',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'message' => $responseData['message'] ?? 'Send payment in progress',
                    'internal_reference' => $responseData['internal_reference'] ?? $paymentData['reference']
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Send payment failed',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Mobile Money Send Payment Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Validate mobile number and get customer information
     */
    public function validateMobileNumber(string $msisdn): array
    {
        try {
            // Validate phone number format first
            if (!$this->validatePhoneNumber($msisdn)) {
                return [
                    'success' => false,
                    'message' => 'Invalid phone number format'
                ];
            }

            // Prepare payload for Relworx API
            $payload = [
                'msisdn' => $this->formatPhoneNumber($msisdn)
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->post($this->apiBaseUrl . '/mobile-money/validate', [
                'json' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/vnd.relworx.v2',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'message' => $responseData['message'] ?? 'Mobile number validated successfully',
                    'customer_name' => $responseData['customer_name'] ?? null,
                    'msisdn' => $responseData['msisdn'] ?? $this->formatPhoneNumber($msisdn)
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Mobile number validation failed',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Mobile Money Validation Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Check wallet balance
     */
    public function checkWalletBalance(string $currency = 'UGX'): array
    {
        try {
            // Prepare query parameters
            $queryParams = [
                'account_no' => $this->accountNo,
                'currency' => $currency
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->get($this->apiBaseUrl . '/mobile-money/check-wallet-balance', [
                'headers' => [
                    'Accept' => 'application/vnd.relworx.v2',
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'query' => $queryParams,
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'balance' => $responseData['balance'] ?? 0.0,
                    'currency' => $currency,
                    'account_no' => $this->accountNo
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to check wallet balance',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Mobile Money Balance Check Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Check wallet balance for multiple ISO currency codes (one Relworx request per currency).
     *
     * @param list<string> $currencies
     * @return array{success: bool, account_no: string, balances: list<array<string, mixed>>}
     */
    public function checkWalletBalances(array $currencies): array
    {
        $balances = [];
        $anySuccess = false;

        foreach ($currencies as $currency) {
            $code = strtoupper(trim((string) $currency));
            if ($code === '') {
                continue;
            }

            $one = $this->checkWalletBalance($code);
            if (!empty($one['success'])) {
                $anySuccess = true;
                $balances[] = [
                    'currency' => $code,
                    'success'    => true,
                    'balance'    => $one['balance'] ?? 0.0,
                ];
            } else {
                $balances[] = [
                    'currency' => $code,
                    'success'    => false,
                    'balance'    => null,
                    'message'    => $one['message'] ?? 'Failed to check wallet balance',
                ];
            }
        }

        return [
            'success'    => $anySuccess,
            'account_no' => $this->accountNo,
            'balances'   => $balances,
        ];
    }

    /**
     * Check request status using internal reference
     */
    public function checkRequestStatus(string $internalReference): array
    {
        try {
            // Prepare query parameters
            $queryParams = [
                'internal_reference' => $internalReference,
                'account_no' => $this->accountNo
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->get($this->apiBaseUrl . '/mobile-money/check-request-status', [
                'headers' => [
                    'Accept' => 'application/vnd.relworx.v2',
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'query' => $queryParams,
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'status' => $responseData['status'] ?? 'unknown',
                    'message' => $responseData['message'] ?? 'Request status retrieved successfully',
                    'customer_reference' => $responseData['customer_reference'] ?? null,
                    'internal_reference' => $responseData['internal_reference'] ?? $internalReference,
                    'msisdn' => $responseData['msisdn'] ?? null,
                    'amount' => $responseData['amount'] ?? null,
                    'currency' => $responseData['currency'] ?? null,
                    'provider' => $responseData['provider'] ?? null,
                    'charge' => $responseData['charge'] ?? null,
                    'request_status' => $responseData['request_status'] ?? null,
                    'remote_ip' => $responseData['remote_ip'] ?? null,
                    'provider_transaction_id' => $responseData['provider_transaction_id'] ?? null,
                    'completed_at' => $responseData['completed_at'] ?? null
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to check request status',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Mobile Money Request Status Check Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Get transaction history from Relworx API
     */
    public function getTransactionHistory(): array
    {
        try {
            // Prepare query parameters
            $queryParams = [
                'account_no' => $this->accountNo
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->get($this->apiBaseUrl . '/payment-requests/transactions', [
                'headers' => [
                    'Accept' => 'application/vnd.relworx.v2',
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'query' => $queryParams,
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'transactions' => $responseData['transactions'] ?? [],
                    'count' => count($responseData['transactions'] ?? []),
                    'account_no' => $this->accountNo
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to retrieve transaction history',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Mobile Money Transaction History Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Request payment session for VISA/Mastercard
     */
    public function requestPaymentSession(array $paymentData): array
    {
        try {
            // Validate required fields
            $requiredFields = ['amount', 'currency', 'reference'];
            foreach ($requiredFields as $field) {
                if (!isset($paymentData[$field]) || empty($paymentData[$field])) {
                    return [
                        'success' => false,
                        'message' => "Missing required field: {$field}"
                    ];
                }
            }

            // Validate reference format
            if (!$this->validateReference($paymentData['reference'])) {
                return [
                    'success' => false,
                    'message' => 'Invalid reference format. Only alphanumeric, underscore and hyphen characters allowed.',
                    'error_code' => 400
                ];
            }

            // Validate amount
            if (!is_numeric($paymentData['amount']) || $paymentData['amount'] <= 0) {
                return [
                    'success' => false,
                    'message' => 'Amount must be a positive number'
                ];
            }

            // Prepare payload for Relworx API
            $payload = [
                'account_no' => $this->accountNo,
                'reference' => $paymentData['reference'],
                'currency' => $paymentData['currency'],
                'amount' => (float) $paymentData['amount'],
                'description' => $paymentData['description'] ?? 'VISA/Mastercard Payment'
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->post($this->apiBaseUrl . '/visa/request-session', [
                'json' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/vnd.relworx.v2',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'message' => $responseData['message'] ?? 'VISA/Mastercard payment session created successfully',
                    'payment_url' => $responseData['payment_url'] ?? null,
                    'reference' => $paymentData['reference']
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to create payment session',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'VISA Payment Session Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Get all available products/services from Relworx API
     */
    public function getAllProducts(): array
    {
        try {
            // Make the API request
            $client = Services::curlrequest();
            $response = $client->get($this->apiBaseUrl . '/products', [
                'headers' => [
                    'Accept' => 'application/vnd.relworx.v2',
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'products' => $responseData['products'] ?? [],
                    'count' => count($responseData['products'] ?? [])
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to retrieve products',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Products API Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Get price list for a specific product code
     * Note: This endpoint can be slow (30+ seconds), increased timeout to 60 seconds
     */
    public function getProductPriceList(string $productCode): array
    {
        try {
            // Make the API request with extended timeout
            $client = Services::curlrequest();
            $response = $client->get($this->apiBaseUrl . '/products/price-list', [
                'headers' => [
                    'Accept' => 'application/vnd.relworx.v2',
                    'Content-Type' => 'application/json',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'query' => ['code' => $productCode],
                'timeout' => 60, // Increased timeout for slow endpoint
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'product_code' => $productCode,
                    'price_list' => $responseData['price_list'] ?? [],
                    'count' => count($responseData['price_list'] ?? [])
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Failed to retrieve price list',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Price List API Error: ' . $e->getCode() . ' : ' . $e->getMessage());
            return [
                'success' => false,
                'message' => strpos($e->getMessage(), 'timed out') !== false 
                    ? 'Request timed out. Price list endpoints can take 30+ seconds. Please try again.' 
                    : 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Get categorized services with grouping logic
     */
    public function getCategorizedServices(): array
    {
        $productsResult = $this->getAllProducts();
        
        if (!$productsResult['success']) {
            return $productsResult;
        }

        $products = $productsResult['products'];
        $categorized = [];

        // Group products by category
        foreach ($products as $product) {
            $category = $product['category'];
            
            if (!isset($categorized[$category])) {
                $categorized[$category] = [
                    'category' => $category,
                    'category_name' => $this->getCategoryDisplayName($category),
                    'services' => [],
                    'count' => 0
                ];
            }

            // Extract provider from product name/code
            $provider = $this->extractProvider($product['name'], $product['code']);
            
            $categorized[$category]['services'][] = [
                'name' => $product['name'],
                'code' => $product['code'],
                'provider' => $provider,
                'has_price_list' => $product['has_price_list'],
                'has_choice_list' => $product['has_choice_list'],
                'billable' => $product['billable']
            ];
            
            $categorized[$category]['count']++;
        }

        // Sort categories by name and services within each category
        ksort($categorized);
        foreach ($categorized as &$category) {
            usort($category['services'], function($a, $b) {
                return strcmp($a['provider'], $b['provider']);
            });
        }

        return [
            'success' => true,
            'categories' => array_values($categorized),
            'total_categories' => count($categorized),
            'total_services' => count($products)
        ];
    }

    /**
     * Get category display name
     */
    private function getCategoryDisplayName(string $category): string
    {
        $categoryNames = [
            'INTERNET' => 'Internet & Data',
            'TV' => 'TV & Entertainment',
            'AIRTIME' => 'Airtime & Voice',
            'BANK_TRANSFERS' => 'Bank Transfers',
            'UTILITIES' => 'Utilities',
            'OTHERS' => 'Other Services'
        ];

        return $categoryNames[$category] ?? ucwords(strtolower(str_replace('_', ' ', $category)));
    }

    /**
     * Extract provider name from product name/code
     */
    private function extractProvider(string $name, string $code): string
    {
        // Common provider patterns
        $providers = [
            'MTN' => 'MTN',
            'AIRTEL' => 'Airtel',
            'DSTV' => 'DSTV',
            'GO_TV' => 'GOtv',
            'STARTIMES' => 'StarTimes',
            'AZAM_TV' => 'Azam TV',
            'MULTICHOICE' => 'Multichoice',
            'UTL' => 'UTL',
            'ROKE' => 'Roke Telecom',
            'UMEME' => 'Umeme',
            'NATIONAL_WATER' => 'National Water'
        ];

        foreach ($providers as $key => $displayName) {
            if (stripos($name, $key) !== false || stripos($code, $key) !== false) {
                return $displayName;
            }
        }

        // For bank transfers, extract bank name
        if (strpos($code, 'BANK') !== false || strpos($code, 'TRANSFER') !== false) {
            $bankName = str_replace(['_BANK_UGANDA_TRANSFER', '_TRANSFER', '_BANK_UGANDA_LTD_TRANSFER'], '', $code);
            $bankName = str_replace('_', ' ', $bankName);
            return ucwords(strtolower($bankName));
        }

        // Default fallback
        return 'Other';
    }

    /**
     * Validate product before purchase
     */
    public function validateProduct(array $validationData): array
    {
        try {
            // Validate required fields
            $requiredFields = ['msisdn', 'amount', 'product_code', 'contact_phone'];
            foreach ($requiredFields as $field) {
                if (!isset($validationData[$field]) || empty($validationData[$field])) {
                    return [
                        'success' => false,
                        'message' => "Missing required field: {$field}"
                    ];
                }
            }

            // Validate amount
            if (!is_numeric($validationData['amount']) || $validationData['amount'] <= 0) {
                return [
                    'success' => false,
                    'message' => 'Amount must be a positive number'
                ];
            }

            // Only validate contact_phone as phone number (msisdn could be account/meter number for utilities)
            if (!$this->validatePhoneNumber($validationData['contact_phone'])) {
                return [
                    'success' => false,
                    'message' => 'Invalid contact phone format'
                ];
            }

            // Generate or validate reference
            $reference = $validationData['reference'] ?? $this->generateReference();
            
            // Validate reference format if provided by user
            if (isset($validationData['reference']) && !$this->validateReference($validationData['reference'])) {
                return [
                    'success' => false,
                    'message' => 'Invalid reference format. Only alphanumeric, underscore and hyphen characters allowed.',
                    'error_code' => 400
                ];
            }

            // Prepare payload for Relworx API
            // Note: msisdn is sent as-is (could be phone number OR account/meter number for utilities)
            $payload = [
                'account_no' => $this->accountNo,
                'reference' => $reference,
                'msisdn' => $validationData['msisdn'], // Send as-is, could be account number
                'amount' => (float) $validationData['amount'],
                'currency' => $validationData['currency'] ?? 'UGX', // Default to UGX
                'product_code' => $validationData['product_code'],
                'contact_phone' => $this->formatPhoneNumber($validationData['contact_phone']),
                'depositor_name' => $validationData['depositor_name'] ?? 'FinFlo', // Required for bank transfers
                'account_name' => $validationData['account_name'] ?? 'FinFlo Account' // Required for bank transfers
            ];

            // Add location_id if provided (required for NATIONAL_WATER)
            if (isset($validationData['location_id']) && !empty($validationData['location_id'])) {
                $payload['location_id'] = $validationData['location_id'];
            }

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->post($this->apiBaseUrl . '/products/validate', [
                'json' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/vnd.relworx.v2',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'message' => 'Product validation successful',
                    'customer_name' => $responseData['customer_name'] ?? '',
                    'validation_reference' => $responseData['validation_reference'] ?? null,
                    'reference' => $payload['reference'],
                    'product_code' => $validationData['product_code'],
                    'msisdn' => $payload['msisdn'],
                    'amount' => $validationData['amount']
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Product validation failed',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Product Validation Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Purchase product using validation reference
     */
    public function purchaseProduct(string $validationReference): array
    {
        try {
            // Validate validation reference
            if (empty($validationReference)) {
                return [
                    'success' => false,
                    'message' => 'Validation reference is required'
                ];
            }

            // Prepare payload for Relworx API
            $payload = [
                'account_no' => $this->accountNo,
                'validation_reference' => $validationReference,
                'currency' => 'UGX' // Add currency to purchase as well
            ];

            // Make the API request
            $client = Services::curlrequest();
            $response = $client->post($this->apiBaseUrl . '/products/purchase', [
                'json' => $payload,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/vnd.relworx.v2',
                    'Authorization' => 'Bearer ' . $this->getDecryptedApiKey()
                ],
                'timeout' => 30,
                'verify' => ($_ENV['mobile_money.verify_ssl'] ?? 'false') === 'true', // SSL verification from env
                'http_errors' => false // Don't throw exceptions on HTTP errors
            ]);

            $responseData = json_decode($response->getBody(), true);

            if ($response->getStatusCode() === 200 && isset($responseData['success']) && $responseData['success']) {
                return [
                    'success' => true,
                    'message' => $responseData['message'] ?? 'Product purchase in progress',
                    'internal_reference' => $responseData['internal_reference'] ?? null,
                    'validation_reference' => $validationReference
                ];
            } else {
                return [
                    'success' => false,
                    'message' => $responseData['message'] ?? 'Product purchase failed',
                    'error_code' => $responseData['error_code'] ?? $response->getStatusCode(),
                    'raw_response' => $responseData
                ];
            }

        } catch (\Exception $e) {
            log_message('error', 'Product Purchase Error: ' . $e->getMessage());
            return [
                'success' => false,
                'message' => 'Internal server error occurred',
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Generate a unique reference for the payment
     * Relworx only accepts alphanumeric, underscore and hyphen characters
     */
    public function generateReference(): string
    {
        // Generate a unique reference without special characters
        // Format: MM_TIMESTAMP_RANDOMHEX
        return 'MM_' . time() . '_' . bin2hex(random_bytes(8));
    }

    /**
     * Validate reference format for Relworx API
     * Only alphanumeric, underscore and hyphen characters allowed
     */
    public function validateReference(string $reference): bool
    {
        // Check if reference contains only alphanumeric, underscore and hyphen
        return preg_match('/^[a-zA-Z0-9_-]+$/', $reference) === 1;
    }

    /**
     * Validate phone number format
     */
    public function validatePhoneNumber(string $msisdn): bool
    {
        // Remove any non-digit characters except +
        $cleaned = preg_replace('/[^\d+]/', '', $msisdn);
        
        // Check if it starts with + and has 10-15 digits after country code
        return preg_match('/^\+[1-9]\d{9,14}$/', $cleaned) === 1;
    }

    /**
     * Format phone number to international format
     */
    public function formatPhoneNumber(string $msisdn): string
    {
        // Remove any non-digit characters except +
        $cleaned = preg_replace('/[^\d+]/', '', $msisdn);
        
        // If it doesn't start with +, assume it's a local number and add +256 for Uganda
        if (!str_starts_with($cleaned, '+')) {
            // Remove leading 0 if present
            if (str_starts_with($cleaned, '0')) {
                $cleaned = substr($cleaned, 1);
            }
            $cleaned = '+256' . $cleaned;
        }
        
        return $cleaned;
    }

    /**
     * Map E.164 country prefix to ISO currency (UGX default).
     * Expects formatted MSISDN (e.g. from formatPhoneNumber()).
     */
    public function currencyFromMsisdn(string $msisdn): string
    {
        $cleaned = preg_replace('/[^\d+]/', '', $msisdn);

        if (str_starts_with($cleaned, '+254')) {
            return 'KES';
        }
        if (str_starts_with($cleaned, '+255')) {
            return 'TZS';
        }
        if (str_starts_with($cleaned, '+256')) {
            return 'UGX';
        }

        return 'UGX';
    }

    /**
     * Get the full API URL for a specific endpoint
     */
    public function getApiUrl(string $endpoint = null): string
    {
        if ($endpoint === null) {
            return $this->apiBaseUrl . $this->apiEndpoint;
        }
        return $this->apiBaseUrl . $endpoint;
    }

    /**
     * Get the API base URL
     */
    public function getApiBaseUrl(): string
    {
        return $this->apiBaseUrl;
    }
}
