<?php
/**
 * Bridge.xyz API Integration for Binance P2P
 * Handles all Bridge API calls for payment processing
 */

class BridgeAPI {
    private $apiKey;
    private $baseUrl;
    
    public function __construct($apiKey) {
        $this->apiKey = $apiKey;
        $this->baseUrl = BRIDGE_API_URL;
    }
    
    /**
     * Generate UUID for idempotency
     */
    private function generateUuid() {
        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
            mt_rand(0, 0xffff),
            mt_rand(0, 0x0fff) | 0x4000,
            mt_rand(0, 0x3fff) | 0x8000,
            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
        );
    }
    
    /**
     * Send HTTP request (generic method)
     */
    private function sendRequest($method, $url, $data = null, $idempotencyKey = null) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        
        $headers = [
            'Api-Key: ' . $this->apiKey,
            'Content-Type: application/json',
            'accept: application/json'
        ];
        
        if ($idempotencyKey) {
            $headers[] = 'Idempotency-Key: ' . $idempotencyKey;
        }
        
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        
        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
        } elseif ($method === 'DELETE') {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
        } elseif ($method === 'PUT') {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
        } elseif ($method === 'GET') {
            curl_setopt($ch, CURLOPT_HTTPGET, true);
        }
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);
        curl_close($ch);
        
        if ($curlError) {
            error_log("Bridge API cURL Error ($method $url): " . $curlError);
            return ['error' => 'cURL Error: ' . $curlError];
        }
        
        $responseData = json_decode($response, true);
        
        if ($httpCode >= 200 && $httpCode < 300) {
            return $responseData;
        } else {
            $errorMessage = isset($responseData['message']) ? $responseData['message'] : 'Unknown error';
            $errorDetails = isset($responseData['errors']) ? json_encode($responseData['errors']) : '';
            $fullResponse = json_encode($responseData);
            error_log("Bridge API Error ($method $url): HTTP $httpCode - " . $errorMessage);
            if ($errorDetails) {
                error_log("Bridge API Error Details: " . $errorDetails);
            }
            error_log("Bridge API Full Response: " . $fullResponse);
            return ['error' => $errorMessage, 'http_code' => $httpCode, 'errors' => $errorDetails, 'full_response' => $responseData];
        }
    }
    
    /**
     * Create a transfer (for paying buyers)
     */
    public function createTransfer($transferData) {
        $url = $this->baseUrl . '/v0/transfers';
        $idempotencyKey = $this->generateUuid();
        return $this->sendRequest('POST', $url, $transferData, $idempotencyKey);
    }
    
    /**
     * Get transfer details
     * Bridge API endpoint: GET /v0/transfers/{transfer_id}
     * Returns transfer object with 'state' field (not 'status')
     * 
     * @param string $transferId Bridge transfer ID
     * @return array Transfer object with 'state' field containing values like:
     *   - awaiting_funds: Bridge is waiting to receive funds
     *   - in_review: Transfer is under review
     *   - funds_received: Funds have been received
     *   - payment_submitted: Payment has been submitted
     *   - payment_processed: Payment has been processed
     *   - completed: Transfer completed
     *   - failed, error: Transfer failed
     *   - canceled, cancelled: Transfer cancelled
     *   - undeliverable: Transfer undeliverable
     *   - returned: Transfer returned
     *   - refunded: Transfer refunded
     *   - missing_return_policy: Missing return policy
     */
    public function getTransferDetails($transferId) {
        $url = $this->baseUrl . '/v0/transfers/' . urlencode($transferId);
        $result = $this->sendRequest('GET', $url);
        
        // Log the response for debugging
        if (isset($result['error'])) {
            error_log("Bridge API getTransferDetails error for transfer $transferId: " . json_encode($result['error']));
        } elseif (isset($result['state'])) {
            error_log("Bridge API getTransferDetails success for transfer $transferId: state = " . $result['state']);
        } else {
            error_log("Bridge API getTransferDetails warning for transfer $transferId: response missing 'state' field. Response: " . json_encode($result));
        }
        
        return $result;
    }
    
    /**
     * Get transfer (alias for getTransferDetails)
     * Bridge API endpoint: GET /v0/transfers/{transfer_id}
     * 
     * @param string $transferId Bridge transfer ID
     * @return array Transfer object with 'state' field
     */
    public function getTransfer($transferId) {
        return $this->getTransferDetails($transferId);
    }
    
    /**
     * Get customer details
     */
    public function getCustomerStatus($customerId) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId;
        return $this->sendRequest('GET', $url);
    }
    
    /**
     * Get external accounts for a customer
     */
    public function getExternalAccounts($customerId) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId . '/external_accounts';
        return $this->sendRequest('GET', $url);
    }
    
    /**
     * Get external account details by ID
     */
    public function getExternalAccountDetails($customerId, $externalAccountId) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId . '/external_accounts/' . $externalAccountId;
        return $this->sendRequest('GET', $url);
    }
    
    /**
     * Create external account for buyer
     */
    public function createExternalAccount($customerId, $accountData) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId . '/external_accounts';
        $idempotencyKey = $this->generateUuid();
        return $this->sendRequest('POST', $url, $accountData, $idempotencyKey);
    }
    
    /**
     * Delete external account
     */
    public function deleteExternalAccount($customerId, $externalAccountId) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId . '/external_accounts/' . $externalAccountId;
        return $this->sendRequest('DELETE', $url);
    }
    
    /**
     * Delete all external accounts for a customer
     * This is used when an order is completed to avoid conflicts on next order
     */
    public function deleteAllExternalAccounts($customerId) {
        // First, get all external accounts for this customer
        $accountsResponse = $this->getExternalAccounts($customerId);
        
        if (isset($accountsResponse['error'])) {
            error_log("Error getting external accounts for customer $customerId: " . $accountsResponse['error']);
            return ['error' => $accountsResponse['error']];
        }
        
        $accounts = $accountsResponse['data'] ?? [];
        
        if (empty($accounts)) {
            error_log("No external accounts found for customer $customerId");
            return ['success' => true, 'deleted_count' => 0, 'message' => 'No external accounts to delete'];
        }
        
        error_log("Found " . count($accounts) . " external account(s) for customer $customerId - deleting all");
        
        $deletedCount = 0;
        $errors = [];
        
        // Delete each external account
        foreach ($accounts as $account) {
            $externalAccountId = $account['id'] ?? null;
            if (!$externalAccountId) {
                continue;
            }
            
            error_log("Deleting external account $externalAccountId for customer $customerId");
            $deleteResult = $this->deleteExternalAccount($customerId, $externalAccountId);
            
            if (isset($deleteResult['error'])) {
                $errorMsg = $deleteResult['error'] ?? 'Unknown error';
                error_log("Error deleting external account $externalAccountId: $errorMsg");
                $errors[] = "Account $externalAccountId: $errorMsg";
            } else {
                error_log("Successfully deleted external account $externalAccountId");
                $deletedCount++;
            }
        }
        
        if (!empty($errors)) {
            return [
                'success' => false,
                'deleted_count' => $deletedCount,
                'total_count' => count($accounts),
                'errors' => $errors
            ];
        }
        
        return [
            'success' => true,
            'deleted_count' => $deletedCount,
            'total_count' => count($accounts),
            'message' => "Successfully deleted $deletedCount external account(s)"
        ];
    }
    
    /**
     * Get customer's liquidation addresses
     */
    public function getCustomerLiquidationAddresses($customerId) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId . '/liquidation_addresses';
        return $this->sendRequest('GET', $url);
    }
    
    /**
     * Create a liquidation address
     */
    public function createLiquidationAddress($customerId, $liquidationData) {
        $url = $this->baseUrl . '/v0/customers/' . $customerId . '/liquidation_addresses';
        $idempotencyKey = $this->generateUuid();
        return $this->sendRequest('POST', $url, $liquidationData, $idempotencyKey);
    }
    
    /**
     * Get liquidation address drains
     * When crypto is sent to a liquidation address, Bridge creates "drains" that convert crypto to fiat
     * Each drain has its own state field
     * 
     * @param string $customerId Bridge customer ID
     * @param string $liquidationAddressId Bridge liquidation address ID (not the address string)
     * @return array Array of drain objects, each with a 'state' field
     */
    public function getLiquidationAddressDrains($customerId, $liquidationAddressId) {
        $url = $this->baseUrl . '/v0/customers/' . urlencode($customerId) . '/liquidation_addresses/' . urlencode($liquidationAddressId) . '/drains';
        $result = $this->sendRequest('GET', $url);
        
        // Log the response for debugging
        if (isset($result['error'])) {
            error_log("Bridge API getLiquidationAddressDrains error for customer $customerId, address $liquidationAddressId: " . json_encode($result['error']));
        } elseif (is_array($result) && !empty($result)) {
            error_log("Bridge API getLiquidationAddressDrains success: Found " . count($result) . " drain(s)");
        } else {
            error_log("Bridge API getLiquidationAddressDrains warning: No drains found or unexpected response format");
        }
        
        return $result;
    }
    
    /**
     * Get exchange rate
     */
    public function getExchangeRate($fromCurrency, $toCurrency) {
        $from = ($fromCurrency === 'usdc') ? 'usd' : $fromCurrency;
        $to = ($toCurrency === 'usdc') ? 'usd' : $toCurrency;
        $url = $this->baseUrl . '/v0/exchange_rates?from=' . strtolower($from) . '&to=' . strtolower($to);
        return $this->sendRequest('GET', $url);
    }
}

