<?php
/**
 * Binance P2P Order Monitor
 * Cron job script that checks for new orders and processes them
 * 
 * Run this script every 5 minutes via cron:
 * 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/bin/php [SCRIPT_PATH]
 */

// CRITICAL: Suppress ALL output BEFORE anything else (CLI only)
if (php_sapi_name() === 'cli') {
    // Disable all output immediately - MUST be first
    ini_set('display_errors', '0');
    ini_set('log_errors', '1');
    ini_set('output_buffering', '0');
    ini_set('session.auto_start', '0');
    
    // Clean any existing output buffers
    while (ob_get_level() > 0) {
        ob_end_clean();
    }
    
    // Start fresh buffer to catch ANY stray output
    ob_start();
    
    // Prevent any headers from being sent
    if (function_exists('header_remove')) {
        header_remove();
    }
}

// Prevent execution via web browser (CLI only)
// Allow execution if NOT clearly a web request (more permissive check)
$isWebRequest = (
    isset($_SERVER['HTTP_HOST']) ||
    isset($_SERVER['REQUEST_METHOD']) ||
    (isset($_SERVER['SERVER_SOFTWARE']) && php_sapi_name() !== 'cli')
);

if ($isWebRequest && php_sapi_name() !== 'cli') {
    // Only block if it's clearly a web request
    http_response_code(403);
    die('This script can only be run from command line.');
}

// Set base directory for includes
$baseDir = dirname(__DIR__);

// Temporarily disable session auto-start before loading config
if (php_sapi_name() === 'cli') {
    ini_set('session.auto_start', '0');
}

// Load required files with absolute paths
require_once $baseDir . '/includes/config.php';

// Clear any output buffer after loading config (CLI only)
if (php_sapi_name() === 'cli') {
    // Discard any output that was buffered (headers, etc.)
    if (ob_get_level() > 0) {
        ob_end_clean();
    }
    // Start fresh buffer for the rest of the script
    ob_start();
}

require_once $baseDir . '/includes/binance-api.php';
require_once $baseDir . '/includes/binance-settings.php';
require_once $baseDir . '/includes/bridge-api.php';
require_once $baseDir . '/includes/iban-validator.php';
require_once $baseDir . '/includes/functions.php';
require_once __DIR__ . '/process-payment.php';

// Suppress HTML output for CLI
ini_set('display_errors', '0');
ini_set('log_errors', '1');

// Set execution time limit
set_time_limit(300); // 5 minutes

// Log start
error_log("=== Binance P2P Order Monitor Started ===");

try {
    // Initialize settings
    $settings = new BinanceP2PSettings($pdo);
    
    // Check if auto payment is enabled
    if (!$settings->isAutoPaymentEnabled()) {
        error_log("Auto payment is disabled. Exiting.");
        
        // Clean output buffer before exit
        if (php_sapi_name() === 'cli' && ob_get_level() > 0) {
            ob_end_clean();
        }
        
        exit(0);
    }
    
    // Get Binance API credentials
    $apiKey = $settings->getBinanceApiKey();
    $secretKey = $settings->getBinanceSecretKey();
    
    if (empty($apiKey) || empty($secretKey)) {
        error_log("ERROR: Binance API credentials not configured!");
        
        // Clean output buffer before exit
        if (php_sapi_name() === 'cli' && ob_get_level() > 0) {
            ob_end_clean();
        }
        
        exit(1);
    }
    
    // Initialize Binance API
    $binance = new BinanceP2PAPI($apiKey, $secretKey);
    
    // Get ALL orders from Binance (to sync status for existing orders)
    error_log("Fetching orders from Binance...");
    $allOrdersResponse = $binance->getUserOrderList(1, 100);
    
    if (isset($allOrdersResponse['error'])) {
        error_log("ERROR fetching orders: " . $allOrdersResponse['error']);
        error_log("Full error response: " . json_encode($allOrdersResponse));
        
        // Clean output buffer before exit
        if (php_sapi_name() === 'cli' && ob_get_level() > 0) {
            ob_end_clean();
        }
        
        exit(1);
    }
    
    $allOrders = $allOrdersResponse['data'] ?? [];
    error_log("Binance API returned " . count($allOrders) . " total orders");
    
    // First, sync status for ALL existing orders in database (even if completed/cancelled)
    error_log("Syncing order statuses from Binance...");
    $ordersChecked = 0;
    $ordersSynced = 0;
    $ordersInSync = 0;
    
    foreach ($allOrders as $order) {
        $orderNo = $order['orderNumber'] ?? $order['orderNo'] ?? null;
        if (!$orderNo) continue;
        
        // Check if order exists in database
        $stmt = $pdo->prepare("SELECT id, order_status, payment_status, bridge_customer_id, bridge_external_account_id FROM binance_p2p_orders WHERE order_no = ?");
        $stmt->execute([$orderNo]);
        $existingOrder = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if ($existingOrder) {
            $ordersChecked++;
            // Sync status from Binance
            $binanceStatus = strtoupper($order['orderStatus'] ?? $order['status'] ?? 'pending');
            $currentDbStatus = strtoupper($existingOrder['order_status'] ?? 'pending');
            $currentPaymentStatus = $existingOrder['payment_status'] ?? 'pending';
            
            if ($currentDbStatus !== $binanceStatus) {
                // Status changed - update it
                $ordersSynced++;
                $newPaymentStatus = $currentPaymentStatus;
                
                // Update payment_status based on Binance status
                if (in_array($binanceStatus, ['BUYER_PAYED', 'COMPLETED'])) {
                    if (in_array($currentPaymentStatus, ['pending', 'processing', 'failed'])) {
                        $newPaymentStatus = 'completed';
                    }
                } elseif (in_array($binanceStatus, ['CANCELLED', 'CANCELLED_BY_SYSTEM'])) {
                    if (in_array($currentPaymentStatus, ['pending', 'processing'])) {
                        $newPaymentStatus = 'cancelled';
                    }
                }
                
                // If order status changed to CANCELLED, delete it from database
                if (in_array($binanceStatus, ['CANCELLED', 'CANCELLED_BY_SYSTEM'])) {
                    error_log("Order $orderNo status changed to $binanceStatus - deleting from database");
                    
                    // Delete the order
                    $deleteStmt = $pdo->prepare("DELETE FROM binance_p2p_orders WHERE id = ?");
                    $deleteStmt->execute([$existingOrder['id']]);
                    
                    error_log("Order $orderNo (ID: {$existingOrder['id']}) deleted from database due to cancellation");
                    continue; // Skip to next order
                }
                
                // If order status changed to COMPLETED, delete the specific external account used for this order
                // IMPORTANT: Only delete the external account that was used for THIS specific order
                // This allows the same customer to have multiple orders with different external accounts
                if ($binanceStatus === 'COMPLETED' && $currentDbStatus !== 'COMPLETED') {
                    $bridgeCustomerId = $existingOrder['bridge_customer_id'] ?? null;
                    $bridgeExternalAccountId = $existingOrder['bridge_external_account_id'] ?? null;
                    
                    // Verify order status is actually COMPLETED before deleting
                    if (strtoupper($binanceStatus) !== 'COMPLETED') {
                        error_log("WARNING: Order $orderNo status is '$binanceStatus' (not COMPLETED) - skipping external account deletion");
                        // Continue with status update but don't delete
                    } else if (!empty($bridgeCustomerId) && !empty($bridgeExternalAccountId)) {
                        error_log("Order $orderNo status changed to COMPLETED (user released crypto) - deleting external account $bridgeExternalAccountId for customer $bridgeCustomerId");
                        
                        try {
                            $bridge = new BridgeAPI(BRIDGE_API_KEY);
                            
                            // Delete ONLY the specific external account used for this order
                            $deleteResult = $bridge->deleteExternalAccount($bridgeCustomerId, $bridgeExternalAccountId);
                            
                            if (isset($deleteResult['error'])) {
                                error_log("ERROR: Failed to delete external account $bridgeExternalAccountId for customer $bridgeCustomerId: " . $deleteResult['error']);
                            } else {
                                error_log("SUCCESS: Deleted external account $bridgeExternalAccountId for customer $bridgeCustomerId (order: $orderNo)");
                            }
                        } catch (Exception $e) {
                            error_log("EXCEPTION: Error deleting external account $bridgeExternalAccountId for customer $bridgeCustomerId: " . $e->getMessage());
                        }
                    } else {
                        if (empty($bridgeCustomerId)) {
                            error_log("Order $orderNo has no bridge_customer_id - skipping external account deletion");
                        }
                        if (empty($bridgeExternalAccountId)) {
                            error_log("Order $orderNo has no bridge_external_account_id - skipping external account deletion (no account was used for this order)");
                        }
                    }
                }
                
                // Update database
                $stmt = $pdo->prepare("
                    UPDATE binance_p2p_orders 
                    SET order_status = ?,
                        payment_status = ?,
                        binance_raw_data = ?,
                        updated_at = NOW()
                    WHERE id = ?
                ");
                $stmt->execute([$binanceStatus, $newPaymentStatus, json_encode($order), $existingOrder['id']]);
                
                error_log("Order $orderNo status synced: $currentDbStatus -> $binanceStatus (payment_status: $currentPaymentStatus -> $newPaymentStatus)");
            } else {
                $ordersInSync++;
            }
            
            // Check if order is cancelled (even if status didn't change) and delete it
            $currentStatus = strtoupper($existingOrder['order_status'] ?? 'pending');
            if (in_array($binanceStatus, ['CANCELLED', 'CANCELLED_BY_SYSTEM']) || 
                in_array($currentStatus, ['CANCELLED', 'CANCELLED_BY_SYSTEM'])) {
                error_log("Order $orderNo is cancelled (Binance: $binanceStatus, DB: $currentStatus) - deleting from database");
                
                // Delete the order
                $deleteStmt = $pdo->prepare("DELETE FROM binance_p2p_orders WHERE id = ?");
                $deleteStmt->execute([$existingOrder['id']]);
                
                error_log("Order $orderNo (ID: {$existingOrder['id']}) deleted from database due to cancellation");
                }
            }
    }
    
    error_log("Status sync completed: $ordersChecked orders checked, $ordersSynced synced, $ordersInSync already in sync");
    
    // ========================================
    // NOTE: External account deletion is now handled above when order status changes to COMPLETED
    // We do NOT delete accounts here because:
    // 1. We only delete when status CHANGES to COMPLETED (not for already-completed orders)
    // 2. We check for other pending orders before deleting
    // 3. This prevents deleting accounts that are still needed for pending orders
    // ========================================
    
    // ========================================
    // AUTO-CANCEL DISABLED: Orders with BUYER_PAYED and payment_status = 'failed'
    // ========================================
    // Previously: System would auto-cancel orders with failed payment status
    // Now: DISABLED - orders with failed payments will be handled manually
    // Only Bridge refund auto-cancel remains active (see below)
    // error_log("=== Auto-cancel for failed payments is DISABLED - orders will be handled manually ===");
    
    // ========================================
    // NEW FEATURE: Cancel orders when Bridge returns "returned" or "refunded" status
    // ========================================
    // Check orders with Bridge liquidation addresses for refund/return status
    // ONLY cancel if:
    // 1. Order status is BUYER_PAYED (not COMPLETED or other statuses)
    // 2. Bridge drain state is "returned" or "refunded"
    // 3. Order has bridge_customer_id and bridge_transfer_id (liquidation address)
    error_log("=== Checking for orders to cancel (Bridge refunded/returned) ===");
    
    // Check if Bridge API is configured
    if (defined('BRIDGE_API_KEY') && !empty(BRIDGE_API_KEY)) {
        try {
            // Find orders with BUYER_PAYED status that have Bridge liquidation addresses
            // bridge_transfer_id stores the liquidation_address_id (see process-payment.php)
            $stmt = $pdo->prepare("
                SELECT id, order_no, order_status, payment_status, 
                       bridge_customer_id, bridge_transfer_id
                FROM binance_p2p_orders
                WHERE order_status = 'BUYER_PAYED'
                AND bridge_customer_id IS NOT NULL 
                AND bridge_customer_id != ''
                AND bridge_transfer_id IS NOT NULL 
                AND bridge_transfer_id != ''
                AND payment_status != 'cancelled'
            ");
            $stmt->execute();
            $ordersWithBridge = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            if (!empty($ordersWithBridge)) {
                error_log("Found " . count($ordersWithBridge) . " order(s) with BUYER_PAYED status and Bridge liquidation addresses to check");
                
                $bridge = new BridgeAPI(BRIDGE_API_KEY);
                
                foreach ($ordersWithBridge as $orderToCheck) {
                    $orderNo = $orderToCheck['order_no'];
                    $orderId = $orderToCheck['id'];
                    $orderStatus = $orderToCheck['order_status'];
                    $bridgeCustomerId = $orderToCheck['bridge_customer_id'];
                    $liquidationAddressId = $orderToCheck['bridge_transfer_id']; // This is actually liquidation_address_id
                    
                    // CRITICAL SAFETY CHECK: Only process BUYER_PAYED orders
                    if (strtoupper($orderStatus) !== 'BUYER_PAYED') {
                        error_log("SKIP: Order $orderNo has status '$orderStatus' (not BUYER_PAYED) - skipping Bridge refund check");
                        continue;
                    }
                    
                    try {
                        error_log("Checking Bridge drain status for order $orderNo (customer: $bridgeCustomerId, liquidation address: $liquidationAddressId)");
                        
                        // Get drains for this liquidation address
                        $drainsResponse = $bridge->getLiquidationAddressDrains($bridgeCustomerId, $liquidationAddressId);
                        
                        // Check for API errors
                        if (isset($drainsResponse['error'])) {
                            $errorMsg = is_string($drainsResponse['error']) ? $drainsResponse['error'] : json_encode($drainsResponse['error']);
                            $httpCode = $drainsResponse['http_code'] ?? null;
                            
                            // 404 means no drains found yet (crypto may not have been sent)
                            if ($httpCode === 404) {
                                error_log("INFO: No drains found for order $orderNo (liquidation address $liquidationAddressId) - crypto may not have been sent yet");
                            } else {
                                error_log("ERROR: Bridge API error checking drains for order $orderNo: $errorMsg (HTTP: $httpCode)");
                            }
                            continue;
                        }
                        
                        // Check if drains exist and get the latest drain state
                        if (is_array($drainsResponse) && isset($drainsResponse['data']) && is_array($drainsResponse['data']) && !empty($drainsResponse['data'])) {
                            // Get the latest drain (first in array)
                            $latestDrain = $drainsResponse['data'][0];
                            $drainState = isset($latestDrain['state']) ? strtolower($latestDrain['state']) : null;
                            
                            if ($drainState) {
                                error_log("Order $orderNo - Bridge drain state: '$drainState'");
                                
                                // CRITICAL: Only cancel if drain state is "returned" or "refunded"
                                if (in_array($drainState, ['returned', 'refunded'])) {
                                    // DOUBLE CHECK: Verify order status is still BUYER_PAYED before cancelling
                                    $verifyStmt = $pdo->prepare("SELECT order_status FROM binance_p2p_orders WHERE id = ?");
                                    $verifyStmt->execute([$orderId]);
                                    $currentOrder = $verifyStmt->fetch(PDO::FETCH_ASSOC);
                                    
                                    if (!$currentOrder || strtoupper($currentOrder['order_status']) !== 'BUYER_PAYED') {
                                        error_log("SKIP: Order $orderNo status changed to '{$currentOrder['order_status']}' (not BUYER_PAYED) - skipping cancellation");
                                        continue;
                                    }
                                    
                                    // Get refund reason if available
                                    $refundReason = '';
                                    if (isset($latestDrain['return_details']['reason'])) {
                                        $refundReason = $latestDrain['return_details']['reason'];
                                    }
                                    
                                    $cancelReason = "Payment refunded by Bridge";
                                    if ($refundReason) {
                                        $cancelReason .= " - " . $refundReason;
                                    }
                                    
                                    error_log("CANCELLING order $orderNo (ID: $orderId) - Bridge drain state: '$drainState'");
                                    error_log("  Refund reason: " . ($refundReason ?: 'N/A'));
                                    
                                    // Cancel the order in Binance with reason code 4 (Seller's payment method issue)
                                    $cancelResult = $binance->cancelOrder($orderNo, 4);
                                    
                                    if (isset($cancelResult['error'])) {
                                        $errorMsg = $cancelResult['error'] ?? 'Unknown error';
                                        error_log("ERROR: Failed to cancel order $orderNo in Binance: $errorMsg");
                                        
                                        // Update error message in database
                                        $updateStmt = $pdo->prepare("
                                            UPDATE binance_p2p_orders
                                            SET error_message = CONCAT(COALESCE(error_message, ''), ' | Bridge Refund Cancel Error: ', ?),
                                                updated_at = NOW()
                                            WHERE id = ?
                                        ");
                                        $updateStmt->execute(["Failed to cancel in Binance: $errorMsg", $orderId]);
                                    } else {
                                        error_log("SUCCESS: Order $orderNo cancelled in Binance due to Bridge refund (state: $drainState)");
                                        
                                        // Update order status to cancelled
                                        $updateStmt = $pdo->prepare("
                                            UPDATE binance_p2p_orders
                                            SET order_status = 'CANCELLED',
                                                payment_status = 'cancelled',
                                                error_message = CONCAT(COALESCE(error_message, ''), ' | Bridge Refund: ', ?),
                                                updated_at = NOW()
                                            WHERE id = ?
                                        ");
                                        $updateStmt->execute([$cancelReason, $orderId]);
                                        
                                        error_log("Order $orderNo (ID: $orderId) status updated to CANCELLED in database (Bridge refund: $drainState)");
                                    }
                                } else {
                                    // Drain state is not "returned" or "refunded", skip
                                    error_log("SKIP: Order $orderNo drain state is '$drainState' (not 'returned' or 'refunded') - no cancellation needed");
                                }
                            } else {
                                error_log("WARNING: Order $orderNo drain response missing 'state' field");
                            }
                        } elseif (is_array($drainsResponse) && empty($drainsResponse['data'])) {
                            // No drains found - crypto may not have been sent yet
                            error_log("INFO: No drains found for order $orderNo (liquidation address $liquidationAddressId) - crypto may not have been sent yet");
                        } else {
                            error_log("WARNING: Unexpected drains response format for order $orderNo");
                        }
                    } catch (Exception $e) {
                        error_log("EXCEPTION: Error checking Bridge drains for order $orderNo: " . $e->getMessage());
                        error_log("Stack trace: " . $e->getTraceAsString());
                        // Continue with next order instead of failing completely
                        continue;
                    } catch (Error $e) {
                        error_log("FATAL ERROR: Fatal error checking Bridge drains for order $orderNo: " . $e->getMessage());
                        // Continue with next order instead of failing completely
                        continue;
                    }
                }
            } else {
                error_log("No orders found with BUYER_PAYED status and Bridge liquidation addresses");
            }
        } catch (Exception $e) {
            error_log("EXCEPTION: Error initializing Bridge API for refund check: " . $e->getMessage());
        } catch (Error $e) {
            error_log("FATAL ERROR: Fatal error initializing Bridge API for refund check: " . $e->getMessage());
        }
    } else {
        error_log("SKIP: BRIDGE_API_KEY not configured - skipping Bridge refund check");
    }
    
    // Now get pending orders for processing
    $pendingOrders = $binance->getPendingOrders(1, 100);
    $orders = $pendingOrders['data'] ?? [];
    error_log("Found " . count($orders) . " pending orders to process");
    
    // If no orders found, try getting ALL orders to debug
    if (count($orders) === 0) {
        error_log("DEBUG: No pending orders found. Fetching ALL orders to check...");
        $allOrders = $binance->getUserOrderList(1, 100);
        if (!isset($allOrders['error']) && isset($allOrders['data'])) {
            error_log("DEBUG: Total orders from API: " . count($allOrders['data']));
            if (count($allOrders['data']) > 0) {
                $firstOrder = $allOrders['data'][0];
                error_log("DEBUG: Sample order structure: " . json_encode($firstOrder, JSON_PRETTY_PRINT));
            }
        }
    }
    
    // Process each order
    foreach ($orders as $order) {
        // Binance API uses 'orderNumber' field (not 'orderNo')
        $orderNo = $order['orderNumber'] ?? $order['orderNo'] ?? $order['order_number'] ?? null;
        
        if (!$orderNo) {
            error_log("WARNING: Order without order number, skipping...");
            continue;
        }
        
        error_log("Processing order: $orderNo");
        
        // Check if order already exists in database
        $stmt = $pdo->prepare("SELECT id, order_status, payment_status FROM binance_p2p_orders WHERE order_no = ?");
        $stmt->execute([$orderNo]);
        $existingOrder = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if ($existingOrder) {
            // Order exists - always sync status from Binance
            $orderStatus = strtoupper($order['orderStatus'] ?? $order['status'] ?? 'pending');
            $currentDbStatus = strtoupper($existingOrder['order_status'] ?? 'pending');
            $currentPaymentStatus = $existingOrder['payment_status'] ?? 'pending';
            
            $orderId = $existingOrder['id'];
            
            // Check if status has changed
            $statusChanged = ($currentDbStatus !== $orderStatus);
            
            // Determine new payment_status based on Binance order_status
            $newPaymentStatus = $currentPaymentStatus;
            
            // If order was marked as paid in Binance (status changed to BUYER_PAYED or COMPLETED)
            if (in_array($orderStatus, ['BUYER_PAYED', 'COMPLETED'])) {
                // If it was previously pending/processing, mark as completed
                if (in_array($currentPaymentStatus, ['pending', 'processing', 'failed'])) {
                    $newPaymentStatus = 'completed';
                    if ($statusChanged) {
                        error_log("Order $orderNo was marked as paid in Binance (status: $orderStatus), updating payment_status to 'completed'");
                    }
                }
                
                // If status changed to BUYER_PAYED, mark for chat message sending
                if ($statusChanged && $orderStatus === 'BUYER_PAYED') {
                    error_log("Order $orderNo status changed to BUYER_PAYED - marking for chat message sending");
                }
            }
            // If order was cancelled in Binance
            elseif (in_array($orderStatus, ['CANCELLED', 'CANCELLED_BY_SYSTEM'])) {
                if (in_array($currentPaymentStatus, ['pending', 'processing'])) {
                    $newPaymentStatus = 'cancelled';
                    if ($statusChanged) {
                        error_log("Order $orderNo was cancelled in Binance (status: $orderStatus), updating payment_status to 'cancelled'");
                    }
                }
            }
            // If order is back to TRADING (unlikely but possible)
            elseif ($orderStatus === 'TRADING' && $currentPaymentStatus === 'completed') {
                // Don't change payment_status if already completed, but update order_status
                // This handles edge cases
            }
            
            // If order status is CANCELLED, delete it from database
            if (in_array($orderStatus, ['CANCELLED', 'CANCELLED_BY_SYSTEM'])) {
                error_log("Order $orderNo status is $orderStatus - deleting from database");
                
                // Delete the order
                $deleteStmt = $pdo->prepare("DELETE FROM binance_p2p_orders WHERE id = ?");
                $deleteStmt->execute([$orderId]);
                
                error_log("Order $orderNo (ID: $orderId) deleted from database due to cancellation");
                continue; // Skip to next order
            }
            
            // Always update order_status and binance_raw_data to sync with Binance
            // If status changed to BUYER_PAYED, reset chat_messages_sent to trigger message sending
            $chatMessagesSent = ($statusChanged && $orderStatus === 'BUYER_PAYED') ? 0 : null;
            
            if ($chatMessagesSent === 0) {
                $stmt = $pdo->prepare("
                    UPDATE binance_p2p_orders 
                    SET order_status = ?,
                        payment_status = ?,
                        binance_raw_data = ?,
                        chat_messages_sent = 0,
                        updated_at = NOW()
                    WHERE id = ?
                ");
                $stmt->execute([$orderStatus, $newPaymentStatus, json_encode($order), $orderId]);
            } else {
                $stmt = $pdo->prepare("
                    UPDATE binance_p2p_orders 
                    SET order_status = ?,
                        payment_status = ?,
                        binance_raw_data = ?,
                        updated_at = NOW()
                    WHERE id = ?
                ");
                $stmt->execute([$orderStatus, $newPaymentStatus, json_encode($order), $orderId]);
            }
            
            if ($statusChanged) {
                error_log("Order $orderNo status synced from Binance: $currentDbStatus -> $orderStatus (payment_status: $currentPaymentStatus -> $newPaymentStatus)");
            }
            
            // Skip processing if order is already completed or cancelled
            if (in_array($orderStatus, ['BUYER_PAYED', 'COMPLETED', 'CANCELLED', 'CANCELLED_BY_SYSTEM'])) {
                error_log("Order $orderNo status is $orderStatus, skipping payment processing");
                continue;
            }
            
            // Skip if already processing or completed in our system
            if (in_array($currentPaymentStatus, ['completed', 'processing'])) {
                error_log("Order $orderNo payment_status is $currentPaymentStatus, skipping payment processing");
                continue;
            }
            
        } else {
            // New order - fetch FULL order details (includes payment info)
            error_log("Fetching full order details for $orderNo...");
            $orderDetailResponse = $binance->getUserOrderDetail($orderNo);
            
            if (isset($orderDetailResponse['error'])) {
                error_log("WARNING: Could not fetch order details: " . $orderDetailResponse['error']);
                error_log("Using order list data instead (may be missing payment details)");
                $fullOrderData = $order;
            } else {
                // Get the actual order detail from response
                // Response structure: {code, message, data: {order details or list}}
                $responseData = $orderDetailResponse['data'] ?? $orderDetailResponse;
                
                // The API seems to return a list even when requesting a single order
                // Check if response has numeric keys (indicating a list)
                $orderDetail = null;
                $hasNumericKeys = false;
                
                foreach (array_keys($responseData) as $key) {
                    if (is_numeric($key)) {
                        $hasNumericKeys = true;
                        // Find the matching order in the list
                        $detailOrderNo = $responseData[$key]['orderNumber'] ?? $responseData[$key]['orderNo'] ?? null;
                        if ($detailOrderNo === $orderNo) {
                            $orderDetail = $responseData[$key];
                            error_log("Found matching order in list at index $key");
                            break;
                        }
                    }
                }
                
                // If no match found but response has orderNumber at root, use root data
                if (!$orderDetail && isset($responseData['orderNumber'])) {
                    $rootOrderNo = $responseData['orderNumber'];
                    if ($rootOrderNo === $orderNo) {
                        $orderDetail = $responseData;
                        error_log("Using root-level order data");
                    }
                }
                
                // If still no match and has numeric keys, use first order (shouldn't happen)
                if (!$orderDetail && $hasNumericKeys && isset($responseData[0])) {
                    error_log("WARNING: Order not found in list, using first order");
                    $orderDetail = $responseData[0];
                }
                
                // If still no order detail, use the list order data
                if (!$orderDetail) {
                    error_log("WARNING: Could not extract order detail from response, using list data");
                    $fullOrderData = $order;
                } else {
                    // Merge detail data with list data (detail takes precedence)
                    $fullOrderData = array_merge($order, $orderDetail);
                    error_log("Full order details fetched successfully");
                    error_log("Order detail keys: " . implode(', ', array_keys($orderDetail)));
                    
                    // Log payment-related keys for debugging
                    $paymentKeys = array_filter(array_keys($orderDetail), function($key) {
                        return stripos($key, 'payment') !== false || 
                               stripos($key, 'iban') !== false || 
                               stripos($key, 'bank') !== false ||
                               stripos($key, 'field') !== false ||
                               stripos($key, 'method') !== false;
                    });
                    if (!empty($paymentKeys)) {
                        error_log("Payment-related keys found: " . implode(', ', $paymentKeys));
                    }
                }
            }
            
            // New order - insert into database
            // Binance API field names: orderNumber, orderStatus, tradeType, asset, fiat, amount, totalPrice, etc.
            $orderStatus = $fullOrderData['orderStatus'] ?? $order['orderStatus'] ?? $order['status'] ?? 'pending';
            $fiatCurrency = $fullOrderData['fiat'] ?? $order['fiat'] ?? $order['fiatCurrency'] ?? $order['fiat_currency'] ?? 'USD';
            $fiatAmount = $fullOrderData['totalPrice'] ?? $order['totalPrice'] ?? $order['fiatAmount'] ?? $order['fiat_amount'] ?? 0;
            $cryptoCurrency = $fullOrderData['asset'] ?? $order['asset'] ?? $order['cryptoCurrency'] ?? $order['crypto_currency'] ?? 'USDT';
            $cryptoAmount = $fullOrderData['amount'] ?? $order['amount'] ?? $order['cryptoAmount'] ?? $order['crypto_amount'] ?? 0;
            $buyerNickname = $fullOrderData['counterPartNickName'] ?? $order['counterPartNickName'] ?? $order['buyerNickname'] ?? $order['buyer_nickname'] ?? null;
            $buyerUserId = $fullOrderData['buyerUserId'] ?? $order['buyerUserId'] ?? $order['buyer_user_id'] ?? null;
            $paymentMethod = $fullOrderData['payMethodName'] ?? $order['payMethodName'] ?? $order['paymentMethod'] ?? $order['payment_method'] ?? null;
            
            // Extract payment details from FULL order data
            $paymentDetails = extractPaymentDetails($fullOrderData);
            
            // If payment details not found, try getting payment method by buyer userId
            if (empty($paymentDetails['iban'] ?? $paymentDetails['IBAN'] ?? '')) {
                error_log("WARNING: No IBAN found in order data. Trying to get payment method by buyer userId...");
                
                if (!empty($buyerUserId)) {
                    error_log("Attempting to get payment method for buyer userId: $buyerUserId");
                    $paymentMethodResponse = $binance->getPaymentMethodByUserId($buyerUserId);
                    
                    if (!isset($paymentMethodResponse['error']) && isset($paymentMethodResponse['data'])) {
                        error_log("Payment method response received. Keys: " . implode(', ', array_keys($paymentMethodResponse['data'])));
                        
                        // Try to extract payment details from payment method response
                        $paymentMethodData = $paymentMethodResponse['data'];
                        if (isset($paymentMethodData['paymentMethodFields']) || isset($paymentMethodData['fields'])) {
                            $fields = $paymentMethodData['paymentMethodFields'] ?? $paymentMethodData['fields'] ?? [];
                            foreach ($fields as $field) {
                                $fieldName = strtolower($field['fieldName'] ?? '');
                                $fieldValue = $field['fieldValue'] ?? '';
                                if (stripos($fieldName, 'iban') !== false && !empty($fieldValue)) {
                                    $paymentDetails['iban'] = $fieldValue;
                                    error_log("Found IBAN from payment method: " . substr($fieldValue, 0, 4) . "****");
                                    break;
                                }
                            }
                        }
                    } else {
                        error_log("Could not get payment method by userId: " . ($paymentMethodResponse['error'] ?? 'Unknown error'));
                    }
                } else {
                    error_log("Buyer userId not available, cannot query payment method");
                }
            }
            
            // Log payment details for debugging
            if (empty($paymentDetails['iban'] ?? $paymentDetails['IBAN'] ?? '')) {
                error_log("WARNING: No IBAN found in payment details after all attempts. Available keys: " . implode(', ', array_keys($paymentDetails)));
                error_log("Full order data keys: " . implode(', ', array_keys($fullOrderData)));
                
                // Log the FULL order structure (first 3000 chars) to help debug
                error_log("Full order structure (first 3000 chars): " . substr(json_encode($fullOrderData, JSON_PRETTY_PRINT), 0, 3000));
            } else {
                error_log("IBAN found: " . substr($paymentDetails['iban'] ?? $paymentDetails['IBAN'] ?? '', 0, 4) . "****");
            }
            
            // Determine if chat messages should be sent (if order status is BUYER_PAYED)
            $chatMessagesSent = ($orderStatus === 'BUYER_PAYED') ? 0 : null;
            
            $stmt = $pdo->prepare("
                INSERT INTO binance_p2p_orders 
                (order_no, binance_order_id, order_status, payment_status, fiat_currency, fiat_amount, 
                 crypto_currency, crypto_amount, buyer_nickname, buyer_user_id, payment_method, 
                 payment_details, binance_raw_data, chat_messages_sent, created_at)
                VALUES (?, ?, ?, 'pending', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())
            ");
            
            $stmt->execute([
                $orderNo,
                $fullOrderData['advNo'] ?? $order['advNo'] ?? $order['orderId'] ?? $order['id'] ?? null, // advNo is the ad/order ID
                $orderStatus,
                $fiatCurrency,
                $fiatAmount,
                $cryptoCurrency,
                $cryptoAmount,
                $buyerNickname,
                $buyerUserId,
                $paymentMethod,
                json_encode($paymentDetails),
                json_encode($fullOrderData), // Store FULL order data with payment details
                $chatMessagesSent
            ]);
            
            $orderId = $pdo->lastInsertId();
            error_log("New order inserted: ID $orderId, Order No: $orderNo");
        }
        
        // Process payment for this order using FULL order data (includes payment details)
        $orderDataForPayment = isset($fullOrderData) ? $fullOrderData : $order;
        $paymentResult = processBinanceOrderPayment($orderId, $orderNo, $orderDataForPayment, $pdo, $settings);
        
        if ($paymentResult['success']) {
            error_log("Order $orderNo payment processed successfully");
        } else {
            error_log("Order $orderNo payment processing failed: " . ($paymentResult['error'] ?? 'Unknown error'));
        }
    }
    
    // Check account balance
    checkAccountBalance($pdo, $settings);
    
    error_log("=== Binance P2P Order Monitor Completed ===");
    
    // Clean output buffer before exit
    if (php_sapi_name() === 'cli' && ob_get_level() > 0) {
        ob_end_clean();
    }
    
} catch (Exception $e) {
    error_log("FATAL ERROR in order monitor: " . $e->getMessage());
    error_log("Stack trace: " . $e->getTraceAsString());
    
    // Clean output buffer before exit
    if (php_sapi_name() === 'cli' && ob_get_level() > 0) {
        ob_end_clean();
    }
    
    exit(1);
}

/**
 * Check account balance and send notification if low
 */
function checkAccountBalance($pdo, $settings) {
    try {
        // Get Bridge customer ID
        $bridgeCustomerId = $settings->getBridgeCustomerId();
        if (empty($bridgeCustomerId)) {
            return;
        }
        
        // Initialize Bridge API
        $bridge = new BridgeAPI(BRIDGE_API_KEY);
        
        // Get customer details
        $customerDetails = $bridge->getCustomerStatus($bridgeCustomerId);
        
        if (isset($customerDetails['error'])) {
            error_log("Error getting customer details: " . $customerDetails['error']);
            return;
        }
        
        $lowBalanceThreshold = $settings->getLowBalanceThreshold();
        
        // Get wallet address from settings
        $walletAddress = $settings->get('wallet_address');
        
        if (empty($walletAddress)) {
            error_log("WARNING: Wallet address not configured. Cannot check balance.");
            return;
        }
        
        // Get USDC balance from Polygon wallet using Alchemy
        $currentBalance = getUSDCBalanceFromWallet($walletAddress);
        
        if ($currentBalance === false) {
            error_log("WARNING: Failed to check USDC balance from wallet");
            return;
        }
        
        error_log("Current USDC balance: $currentBalance (threshold: $lowBalanceThreshold)");
        
        // Check if we already notified
        if ($settings->isLowBalanceNotified()) {
            // If balance is now above threshold, reset notification
            if ($currentBalance >= $lowBalanceThreshold) {
                $settings->markLowBalanceNotified(false);
            }
            return;
        }
        
        if ($currentBalance < $lowBalanceThreshold) {
            // Create notification
            $stmt = $pdo->prepare("
                INSERT INTO binance_p2p_notifications 
                (notification_type, title, message, is_read, created_at)
                VALUES ('low_balance', 'Low Account Balance', 
                'Your account balance is below " . $lowBalanceThreshold . " USDC. Current balance: " . $currentBalance . " USDC. Please deposit funds to continue processing orders.', 
                0, NOW())
            ");
            $stmt->execute();
            
            // Mark as notified
            $settings->markLowBalanceNotified(true);
            
            error_log("WARNING: Low balance detected: $currentBalance USDC (threshold: $lowBalanceThreshold)");
        }
        
    } catch (Exception $e) {
        error_log("Error checking balance: " . $e->getMessage());
    }
}

/**
 * Get USDC balance from Polygon wallet using Alchemy API
 */
function getUSDCBalanceFromWallet($walletAddress) {
    try {
        $usdcContract = USDC_CONTRACT; // Polygon USDC contract
        $alchemyUrl = ALCHEMY_URL;
        
        // Alchemy API call to get token balance
        // Using eth_call to call balanceOf(address) on USDC contract
        $data = '0x70a08231' . str_pad(str_replace('0x', '', strtolower($walletAddress)), 64, '0', STR_PAD_LEFT);
        
        $payload = [
            'jsonrpc' => '2.0',
            'method' => 'eth_call',
            'params' => [
                [
                    'to' => $usdcContract,
                    'data' => $data
                ],
                'latest'
            ],
            'id' => 1
        ];
        
        $ch = curl_init($alchemyUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json'
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode !== 200) {
            error_log("Alchemy API error: HTTP $httpCode");
            return false;
        }
        
        $result = json_decode($response, true);
        
        if (isset($result['error'])) {
            error_log("Alchemy API error: " . $result['error']['message']);
            return false;
        }
        
        if (!isset($result['result'])) {
            error_log("Alchemy API: No result in response");
            return false;
        }
        
        // Convert hex to decimal (USDC uses 6 decimals)
        $hexBalance = str_replace('0x', '', $result['result']);
        $balanceWei = hexdec($hexBalance);
        $balanceUSDC = $balanceWei / 1000000; // USDC has 6 decimals
        
        return $balanceUSDC;
        
    } catch (Exception $e) {
        error_log("Error getting USDC balance: " . $e->getMessage());
        return false;
    }
}
