<?php
namespace App\classes;

class ApiService {
    private $conn;
    
    public function __construct($connection) {
        $this->conn = $connection;
    }
    
    /**
     * Check if API system is enabled
     */
    public function isApiEnabled() {
        $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 && $row['config_value'] == '1';
    }
    
    /**
     * Get API configuration for a specific network
     */
    public function getApiConfig($networkType) {
        $stmt = $this->conn->prepare("SELECT * FROM api_config WHERE network_type = ? AND is_active = 1");
        $stmt->bind_param("s", $networkType);
        $stmt->execute();
        $result = $stmt->get_result();
        $config = $result->fetch_assoc();
        $stmt->close();
        
        return $config;
    }
    
    /**
     * Process order through external API
     */
    public function processOrder($orderData) {
        if (!$this->isApiEnabled()) {
            return [
                'success' => false,
                'message' => 'API system is disabled'
            ];
        }
        
        $networkType = $orderData['network_type'];
        $apiConfig = $this->getApiConfig($networkType);
        
        if (!$apiConfig) {
            return [
                'success' => false,
                'message' => "No active API configuration found for network: $networkType"
            ];
        }
        
        // Prepare request data
        $requestData = $this->prepareRequestData($orderData, $apiConfig);
        
        // Make API request
        $response = $this->makeApiRequest($apiConfig, $requestData);
        
        // Log the API call
        $this->logApiCall($orderData, $apiConfig, $requestData, $response);
        
        return $response;
    }
    
    /**
     * Prepare request data by replacing placeholders
     */
    private function prepareRequestData($orderData, $apiConfig) {
        $placeholders = [
            '{phone}' => $orderData['phone_number'],
            '{package}' => $orderData['package_name'],
            '{amount}' => $orderData['amount'],
            '{network}' => strtoupper($orderData['network_type']),
            '{api_key}' => $apiConfig['api_key'],
            '{api_secret}' => $apiConfig['api_secret'],
            '{capacity}' => $this->extractCapacity($orderData['package_name']),
            '{mb}' => $this->convertToMB($orderData['package_name'])
        ];
        
        // Replace placeholders in request body template
        $requestBody = $apiConfig['request_body_template'];
        foreach ($placeholders as $placeholder => $value) {
            $requestBody = str_replace($placeholder, $value, $requestBody);
        }
        
        // Replace placeholders in request headers
        $requestHeaders = $apiConfig['request_headers'];
        foreach ($placeholders as $placeholder => $value) {
            $requestHeaders = str_replace($placeholder, $value, $requestHeaders);
        }
        
        return [
            'body' => $requestBody,
            'headers' => $requestHeaders
        ];
    }
    
    /**
     * Make API request
     */
    private function makeApiRequest($apiConfig, $requestData) {
        $ch = curl_init();
        
        // Parse headers
        $headers = json_decode($requestData['headers'], true);
        if (!$headers) {
            $headers = ['Content-Type: application/json'];
        } else {
            $headerArray = [];
            foreach ($headers as $key => $value) {
                $headerArray[] = "$key: $value";
            }
            $headers = $headerArray;
        }
        
        // Set cURL options
        curl_setopt_array($ch, [
            CURLOPT_URL => $apiConfig['api_endpoint'],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $apiConfig['timeout_seconds'],
            CURLOPT_CUSTOMREQUEST => $apiConfig['request_method'],
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_POSTFIELDS => $requestData['body'],
            CURLOPT_SSL_VERIFYPEER => false, // For development
            CURLOPT_FOLLOWLOCATION => true
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        if ($response === false) {
            return [
                'success' => false,
                'message' => 'cURL Error: ' . $error,
                'http_code' => $httpCode
            ];
        }
        
        $responseData = json_decode($response, true);
        
        // Parse response based on configured fields
        $success = $this->parseResponseField($responseData, $apiConfig['response_success_field']);
        $data = $this->parseResponseField($responseData, $apiConfig['response_data_field']);
        $errorMessage = $this->parseResponseField($responseData, $apiConfig['response_error_field']);
        
        return [
            'success' => $success && $httpCode >= 200 && $httpCode < 300,
            'data' => $data,
            'message' => $errorMessage ?: ($success ? 'API call successful' : 'API call failed'),
            'http_code' => $httpCode,
            'raw_response' => $responseData
        ];
    }
    
    /**
     * Parse response field based on configuration
     */
    private function parseResponseField($responseData, $fieldName) {
        if (empty($fieldName)) {
            return null;
        }
        
        // Handle nested fields (e.g., "data.success")
        $fields = explode('.', $fieldName);
        $value = $responseData;
        
        foreach ($fields as $field) {
            if (is_array($value) && isset($value[$field])) {
                $value = $value[$field];
            } else {
                return null;
            }
        }
        
        return $value;
    }
    
    /**
     * Extract capacity from package name (e.g., "5GB" -> "5")
     */
    private function extractCapacity($packageName) {
        if (preg_match('/(\d+(?:\.\d+)?)\s*GB/i', $packageName, $matches)) {
            return $matches[1];
        }
        return '1'; // Default
    }
    
    /**
     * Convert package to MB
     */
    private function convertToMB($packageName) {
        $capacity = $this->extractCapacity($packageName);
        return (float)$capacity * 1024;
    }
    
    /**
     * Log API call for debugging
     */
    private function logApiCall($orderData, $apiConfig, $requestData, $response) {
        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'order_id' => $orderData['id'] ?? 'unknown',
            'network' => $orderData['network_type'],
            'endpoint' => $apiConfig['api_endpoint'],
            'request_body' => $requestData['body'],
            'request_headers' => $requestData['headers'],
            'response' => $response,
            'success' => $response['success']
        ];
        
        error_log('API Call: ' . json_encode($logData));
    }
    
    /**
     * Update order status based on API response
     */
    public function updateOrderStatus($orderId, $apiResponse) {
        if ($apiResponse['success']) {
            // Move to completed
            $this->moveOrderToCompleted($orderId, $apiResponse);
        } else {
            // Move to failed or keep in processing for retry
            $this->moveOrderToFailed($orderId, $apiResponse);
        }
    }
    
    /**
     * Move order to completed status
     */
    private function moveOrderToCompleted($orderId, $apiResponse) {
        // Get order details from processing table
        $stmt = $this->conn->prepare("SELECT * FROM processing_databundle_orders WHERE id = ?");
        $stmt->bind_param("i", $orderId);
        $stmt->execute();
        $result = $stmt->get_result();
        $order = $result->fetch_assoc();
        $stmt->close();
        
        if ($order) {
            // Insert into completed table
            $insertStmt = $this->conn->prepare("INSERT INTO completed_databundle_orders 
                (original_id, verified_id, momo_name, momo_number, package, package_mb, amount_paid, 
                 reference, megabytes, received, network_type, external_transaction_id, api_response_data, 
                 status, payment_verified_at, processed_at, created_at) 
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'delivered', ?, NOW(), NOW())");
            
            $apiResponseJson = json_encode($apiResponse);
            $externalTransactionId = $apiResponse['data']['transactionReference'] ?? $apiResponse['data']['purchaseId'] ?? null;
            
            $insertStmt->bind_param("iisssdssissss", 
                $order['original_id'], $order['verified_id'], $order['momo_name'], 
                $order['momo_number'], $order['package'], $order['package_mb'], 
                $order['amount_paid'], $order['reference'], $order['megabytes'], 
                $order['received'], $order['network_type'], $externalTransactionId, 
                $apiResponseJson, $order['payment_verified_at']);
            
            $insertStmt->execute();
            $insertStmt->close();
            
            // Remove from processing table
            $deleteStmt = $this->conn->prepare("DELETE FROM processing_databundle_orders WHERE id = ?");
            $deleteStmt->bind_param("i", $orderId);
            $deleteStmt->execute();
            $deleteStmt->close();
        }
    }
    
    /**
     * Move order to failed status
     */
    private function moveOrderToFailed($orderId, $apiResponse) {
        // Update processing order with error information
        $errorData = json_encode([
            'error' => $apiResponse['message'],
            'http_code' => $apiResponse['http_code'],
            'failed_at' => date('Y-m-d H:i:s'),
            'raw_response' => $apiResponse['raw_response']
        ]);
        
        $stmt = $this->conn->prepare("UPDATE processing_databundle_orders SET api_response_data = ? WHERE id = ?");
        $stmt->bind_param("si", $errorData, $orderId);
        $stmt->execute();
        $stmt->close();
    }
}
?>
