<?php
require_once __DIR__ . '/../../config.php';

class ExternalAPIService {
    private $network;
    private $conn;
    private $api_config;

    public function __construct($network = null) {
        global $conn;
        $this->network = $network;
        $this->conn = $conn;
        $this->loadApiConfig();
    }

    public function getApiEndpoint() {
        return $this->api_config['api_endpoint'] ?? 'Unknown';
    }

    private function loadApiConfig() {
        if (!$this->network) return;
        
        $stmt = $this->conn->prepare("SELECT * FROM api_config WHERE network_type = ? AND is_active = 1");
        $stmt->bind_param("s", $this->network);
        $stmt->execute();
        $result = $stmt->get_result();
        $this->api_config = $result->fetch_assoc();
        $stmt->close();
    }

    public function convertPackageSize($bundleLabel) {
        // Enhanced parser: extracts numbers from package names and converts to MB
        $bundleLabel = trim($bundleLabel);
        
        // Try to extract number from the package name
        if (preg_match('/(\d+(?:\.\d+)?)\s*GB/i', $bundleLabel, $matches)) {
            // Found GB - convert to MB
            $gb = floatval($matches[1]);
            return (int) round($gb * 1024);
        }
        
        if (preg_match('/(\d+(?:\.\d+)?)\s*MB/i', $bundleLabel, $matches)) {
            // Found MB - return as MB
            return (int) round(floatval($matches[1]));
        }
        
        // Try to extract any number and assume it's GB if no unit specified
        if (preg_match('/(\d+(?:\.\d+)?)/', $bundleLabel, $matches)) {
            $number = floatval($matches[1]);
            // If the number is small (less than 100), assume it's GB
            if ($number < 100) {
                return (int) round($number * 1024);
            } else {
                // If large, assume it's already in MB
                return (int) round($number);
            }
        }
        
        return 0;
    }

    public function validatePhoneNumber($phone) {
        // Minimal sanitization; return digits only if plausible
        $digits = preg_replace('/\D+/', '', (string)$phone);
        return strlen($digits) >= 9 ? $digits : null;
    }

    public function purchaseData($msisdn, $network, $capacityMb, $paymentMethod = 'wallet', $localOrderId = null) {
        // Check if global API is enabled
        if (!$this->isGlobalApiEnabled()) {
            return [
                'success' => false,
                'error' => 'Global API integration is disabled',
                'data' => null,
            ];
        }

        // Check if API config exists for this network
        if (!$this->api_config) {
            return [
                'success' => false,
                'error' => "No active API configuration found for network: {$network}",
                'data' => null,
            ];
        }

        // Validate endpoint URL
        $endpoint = $this->api_config['api_endpoint'] ?? '';
        if (empty($endpoint)) {
            return [
                'success' => false,
                'error' => "API endpoint is not configured for network: {$network}",
                'data' => null,
            ];
        }
        
        // Basic URL validation
        if (!filter_var($endpoint, FILTER_VALIDATE_URL)) {
            return [
                'success' => false,
                'error' => "Invalid API endpoint URL: {$endpoint}",
                'data' => null,
            ];
        }

        // Prepare request data
        $requestData = $this->prepareRequestData($msisdn, $network, $capacityMb, $paymentMethod, $localOrderId);
        
        // Make API call
        $startTime = microtime(true);
        $response = $this->makeApiCall($requestData);
        $executionTime = round((microtime(true) - $startTime) * 1000);

        // Log API call
        $this->logApiCall($localOrderId, $requestData, $response, $executionTime);

        return $response;
    }

    private function isGlobalApiEnabled() {
        $stmt = $this->conn->prepare("SELECT config_value FROM payment_config WHERE config_key = 'api_enabled'");
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        $stmt->close();
        
        return $row && (bool)$row['config_value'];
    }

    private function prepareRequestData($msisdn, $network, $capacityMb, $paymentMethod, $localOrderId) {
        $template = $this->api_config['request_body_template'];
        
        // Convert MB to GB for capacity
        $capacityGb = round($capacityMb / 1024, 2);
        
        // Generate a valid reference (minimum 6 characters as required by Hubnet API)
        $reference = $localOrderId;
        if (empty($reference) || strlen($reference) < 6) {
            $reference = 'ORDER-' . time() . '-' . rand(100, 999);
        }
        
        // Replace placeholders in template
        $data = str_replace([
            '{phone}', '{package}', '{amount}', '{network}', '{payment_method}', '{order_id}', '{capacity}', '{mb}',
            '{volume}', '{reference}', '{referrer}', '{webhook}'
        ], [
            $msisdn, $capacityMb . 'MB', $capacityMb, $network, $paymentMethod, $localOrderId, $capacityGb, $capacityMb,
            $capacityMb, $reference, $msisdn, ''
        ], $template);

        return json_decode($data, true);
    }

    private function makeApiCall($requestData) {
        $endpoint = $this->api_config['api_endpoint'];
        $method = $this->api_config['request_method'];
        $headers = json_decode($this->api_config['request_headers'], true) ?: [];
        $timeout = intval($this->api_config['timeout_seconds'] ?? 30);
        
        // Validate timeout - ensure it's reasonable
        if ($timeout <= 0 || $timeout > 300) {
            $timeout = 30; // Default to 30 seconds if invalid
        }
        
        // Connection timeout should be shorter than total timeout
        $connectTimeout = min(10, max(5, $timeout / 3)); // 5-10 seconds for connection

        // Replace API key placeholder in headers
        foreach ($headers as $key => $value) {
            $headers[$key] = str_replace('{api_key}', $this->api_config['api_key'], $value ?? '');
        }

        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $endpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $timeout, // Total timeout for entire operation
            CURLOPT_CONNECTTIMEOUT => $connectTimeout, // Timeout for connection establishment
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $this->formatHeaders($headers),
            CURLOPT_POSTFIELDS => json_encode($requestData),
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 3,
            CURLOPT_VERBOSE => false, // Set to true for debugging if needed
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        
        // Get detailed connection info for diagnostics
        $curlInfo = [
            'total_time' => curl_getinfo($ch, CURLINFO_TOTAL_TIME),
            'connect_time' => curl_getinfo($ch, CURLINFO_CONNECT_TIME),
            'namelookup_time' => curl_getinfo($ch, CURLINFO_NAMELOOKUP_TIME),
            'starttransfer_time' => curl_getinfo($ch, CURLINFO_STARTTRANSFER_TIME),
            'primary_ip' => curl_getinfo($ch, CURLINFO_PRIMARY_IP),
            'primary_port' => curl_getinfo($ch, CURLINFO_PRIMARY_PORT),
            'local_ip' => curl_getinfo($ch, CURLINFO_LOCAL_IP),
            'local_port' => curl_getinfo($ch, CURLINFO_LOCAL_PORT),
            'size_upload' => curl_getinfo($ch, CURLINFO_SIZE_UPLOAD),
            'size_download' => curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD),
        ];
        
        curl_close($ch);

        if ($error) {
            $errorDetails = [
                'success' => false,
                'error' => "cURL Error: {$error}",
                'error_type' => 'curl_error',
                'data' => null,
                'http_code' => 0,
                'raw_response' => null,
                'curl_info' => $curlInfo, // Include diagnostic info
            ];
            
            // Log detailed error with diagnostic information
            $diagnosticInfo = json_encode([
                'network' => $this->network,
                'endpoint' => $endpoint,
                'error' => $error,
                'timeout_setting' => $timeout,
                'connect_timeout_setting' => $connectTimeout,
                'curl_info' => $curlInfo,
                'request_data_size' => strlen(json_encode($requestData)),
            ]);
            error_log("API cURL Error - {$diagnosticInfo}");
            
            return $errorDetails;
        }

        $responseData = json_decode($response, true);
        
        // Check response based on configured success field
        $successField = $this->api_config['response_success_field'];
        $isSuccess = isset($responseData[$successField]) ? (bool)$responseData[$successField] : ($httpCode >= 200 && $httpCode < 300);

        // Enhanced error handling for AT orders
        $errorMessage = null;
        $errorType = 'unknown';
        
        if (!$isSuccess) {
            // Extract detailed error information
            if ($httpCode >= 400 && $httpCode < 500) {
                $errorType = 'client_error';
                $errorMessage = "HTTP {$httpCode}: " . ($responseData['reason'] ?? $responseData['message'] ?? $responseData['error'] ?? 'Client error');
            } elseif ($httpCode >= 500) {
                $errorType = 'server_error';
                $errorMessage = "HTTP {$httpCode}: " . ($responseData['reason'] ?? $responseData['message'] ?? $responseData['error'] ?? 'Server error');
            } elseif (isset($responseData['reason'])) {
                $errorType = 'api_error';
                $errorMessage = $responseData['reason'];
            } elseif (isset($responseData['message'])) {
                $errorType = 'api_message';
                $errorMessage = $responseData['message'];
            } elseif (isset($responseData['error'])) {
                $errorType = 'api_error';
                $errorMessage = $responseData['error'];
            } else {
                $errorType = 'unknown_error';
                $errorMessage = "API call failed - HTTP {$httpCode}";
            }
            
            // Log detailed error for AT orders
            error_log("AT API Error - Network: {$this->network}, HTTP: {$httpCode}, Type: {$errorType}, Message: {$errorMessage}, Response: " . substr($response, 0, 500));
        }

        return [
            'success' => $isSuccess,
            'data' => $responseData,
            'http_code' => $httpCode,
            'raw_response' => $response,
            'error' => $errorMessage,
            'error_type' => $errorType,
        ];
    }

    private function formatHeaders($headers) {
        $formatted = [];
        foreach ($headers as $key => $value) {
            $formatted[] = "{$key}: {$value}";
        }
        return $formatted;
    }

    private function logApiCall($localOrderId, $requestData, $response, $executionTime) {
        $orderId = null;
        $agentOrderId = null;
        
        // Determine if this is a regular order or agent order
        if ($localOrderId) {
            $stmt = $this->conn->prepare("SELECT id FROM orders WHERE id = ?");
            $stmt->bind_param("i", $localOrderId);
            $stmt->execute();
            $result = $stmt->get_result();
            if ($result->fetch_assoc()) {
                $orderId = $localOrderId;
            } else {
                $agentOrderId = $localOrderId;
            }
            $stmt->close();
        }

        $stmt = $this->conn->prepare("INSERT INTO api_logs 
            (order_id, agent_order_id, network_type, api_endpoint, request_data, response_data, 
             response_code, success, error_message, execution_time_ms) 
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
        
        // Prepare variables for bind_param (expressions cannot be passed by reference)
        $requestDataJson = json_encode($requestData);
        $responseDataJson = json_encode($response['data']);
        $successFlag = $response['success'] ? 1 : 0;
        
        // Enhanced error message for AT orders
        $errorMessage = null;
        if (!$response['success']) {
            $errorType = $response['error_type'] ?? 'unknown';
            $baseError = $response['error'] ?? $response['message'] ?? 'Unknown error';
            $httpCode = $response['http_code'] ?? 0;
            
            // Create detailed error message
            $errorMessage = "[{$errorType}] HTTP {$httpCode}: {$baseError}";
            
            // Add network-specific context for AT orders
            if ($this->network === 'airtel_tigo') {
                $errorMessage = "AT API - " . $errorMessage;
            }
        }
        
        $stmt->bind_param("iissssisii", 
            $orderId, $agentOrderId, $this->network, $this->api_config['api_endpoint'],
            $requestDataJson, $responseDataJson,
            $response['http_code'], $successFlag,
            $errorMessage, $executionTime
        );
        
        $stmt->execute();
        $stmt->close();
    }

    /**
     * Check transaction status from external API
     */
    public function checkTransactionStatus($externalTransactionId) {
        // Check if global API is enabled
        if (!$this->isGlobalApiEnabled()) {
            return [
                'success' => false,
                'error' => 'Global API integration is disabled',
                'data' => null,
            ];
        }

        // Check if API config exists for this network
        if (!$this->api_config) {
            return [
                'success' => false,
                'error' => "No active API configuration found for network: {$this->network}",
                'data' => null,
            ];
        }

        // Prepare status check request
        $requestData = $this->prepareStatusCheckRequest($externalTransactionId);
        
        // Make API call
        $startTime = microtime(true);
        $response = $this->makeStatusCheckCall($requestData);
        $executionTime = round((microtime(true) - $startTime) * 1000);

        // Log API call
        $this->logApiCall(null, $requestData, $response, $executionTime);

        return $response;
    }

    /**
     * Get transaction status (alias for checkTransactionStatus)
     */
    public function getTransactionStatus($externalTransactionId) {
        return $this->checkTransactionStatus($externalTransactionId);
    }

    /**
     * Prepare status check request data
     */
    private function prepareStatusCheckRequest($externalTransactionId) {
        $requestData = [
            'transaction_id' => $externalTransactionId,
            'api_key' => $this->api_config['api_key'] ?? '',
            'api_secret' => $this->api_config['api_secret'] ?? ''
        ];

        // Replace placeholders in request data
        $requestData = array_map(function($value) use ($externalTransactionId) {
            if (is_string($value)) {
                $value = str_replace('{transaction_id}', $externalTransactionId, $value);
                $value = str_replace('{api_key}', $this->api_config['api_key'] ?? '', $value);
                $value = str_replace('{api_secret}', $this->api_config['api_secret'] ?? '', $value);
            }
            return $value;
        }, $requestData);

        return $requestData;
    }

    /**
     * Make status check API call
     */
    private function makeStatusCheckCall($requestData) {
        $ch = curl_init();
        
        // Use status check endpoint if configured, otherwise use main endpoint
        $endpoint = $this->api_config['status_endpoint'] ?? $this->api_config['api_endpoint'];
        
        curl_setopt_array($ch, [
            CURLOPT_URL => $endpoint,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_CUSTOMREQUEST => $this->api_config['request_method'] ?? 'POST',
            CURLOPT_HTTPHEADER => $this->formatHeaders($this->api_config['request_headers'] ?? '{}'),
            CURLOPT_POSTFIELDS => json_encode($requestData)
        ]);
        
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curl_error = curl_error($ch);
        
        curl_close($ch);
        
        if ($response === false) {
            return [
                'success' => false,
                'error' => 'Connection failed: ' . $curl_error,
                'data' => null,
                'http_code' => $http_code,
                'raw_response' => $response
            ];
        }
        
        $data = json_decode($response, true);
        
        if ($http_code >= 200 && $http_code < 300) {
            return [
                'success' => true,
                'data' => $data,
                'error' => null,
                'http_code' => $http_code,
                'raw_response' => $response
            ];
        } else {
            return [
                'success' => false,
                'error' => $data['message'] ?? $data['error'] ?? 'API request failed',
                'data' => $data,
                'http_code' => $http_code,
                'raw_response' => $response
            ];
        }
    }
}

?>


