<?php
/**
 * Auto Convert USDT to USDC and Withdraw to Polygon
 * 
 * This script:
 * 1. Checks USDC balance - if >= 150 USDC, withdraws to Polygon automatically
 * 2. Checks USDT balance on Binance
 * 3. If balance >= 200 USDT, converts USDT to USDC using Binance Convert API
 * 4. After conversion completes, withdraws USDC to Polygon network
 * 
 * Run this as a cron job (e.g., every 5 minutes)
 */

// CRITICAL: Suppress ALL output BEFORE anything else (CLI only)
if (php_sapi_name() === 'cli') {
    ini_set('display_errors', '0');
    ini_set('log_errors', '1');
    ini_set('output_buffering', '0');
    ini_set('session.auto_start', '0');
    
    while (ob_get_level() > 0) {
        ob_end_clean();
    }
    
    ob_start();
}

// Prevent execution via web browser (CLI only)
$isWebRequest = (
    isset($_SERVER['HTTP_HOST']) ||
    isset($_SERVER['REQUEST_METHOD']) ||
    (isset($_SERVER['SERVER_SOFTWARE']) && php_sapi_name() !== 'cli')
);

if ($isWebRequest && php_sapi_name() !== 'cli') {
    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
$originalSessionAutoStart = ini_get('session.auto_start');
ini_set('session.auto_start', '0');

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

// Clear any output buffer after loading config (CLI only)
if (php_sapi_name() === 'cli') {
    if (ob_get_level() > 0) {
        ob_end_clean();
    }
    ob_start();
}

require_once $baseDir . '/includes/binance-api.php';
require_once $baseDir . '/includes/binance-settings.php';
require_once $baseDir . '/includes/functions.php';

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

set_time_limit(300); // 5 minutes

error_log("=== Auto Convert USDT to USDC Started ===");

try {
    $settings = new BinanceP2PSettings($pdo);
    
    // Get Binance API credentials
    $apiKey = $settings->getBinanceApiKey();
    $secretKey = $settings->getBinanceSecretKey();
    
    if (empty($apiKey) || empty($secretKey)) {
        error_log("ERROR: Binance API credentials not configured!");
        exit(1);
    }
    
    // Get withdrawal wallet address from settings
    $withdrawalWallet = $settings->get('withdrawal_wallet_address');
    if (empty($withdrawalWallet)) {
        error_log("ERROR: Withdrawal wallet address not configured in settings!");
        error_log("Please set 'withdrawal_wallet_address' in binance_p2p_settings table");
        exit(1);
    }
    
    // Minimum thresholds
    $minUsdtBalance = 250;  // Minimum USDT to convert
    $minUsdcBalance = 200;  // Minimum USDC to withdraw
    
    $binance = new BinanceP2PAPI($apiKey, $secretKey);
    
    // ========================================
    // STEP 1: Check USDC Balance and Withdraw if >= 150
    // ========================================
    error_log("=== STEP 1: Checking USDC Balance for Auto-Withdrawal ===");
    
    $usdcBalance = $binance->getAccountBalance('USDC');
    
    if (!isset($usdcBalance['error'])) {
        $freeUsdc = floatval($usdcBalance['free'] ?? 0);
        $totalUsdc = floatval($usdcBalance['total'] ?? 0);
        $usdcAccountType = $usdcBalance['account_type'] ?? 'unknown';
        
        error_log("USDC Balance - Free: $freeUsdc, Total: $totalUsdc, Account Type: $usdcAccountType");
        
        // Check if USDC balance is sufficient for withdrawal
        if ($freeUsdc >= $minUsdcBalance) {
            error_log("USDC balance ($freeUsdc) meets withdrawal threshold ($minUsdcBalance). Proceeding with withdrawal...");
            
            // Get breakdown of funding vs spot balances
            // Handle scientific notation properly (e.g., "3.6E-7" = 0.00000036)
            $fundingBalanceRaw = $usdcBalance['funding_balance'] ?? 0;
            $fundingBalance = is_numeric($fundingBalanceRaw) ? floatval($fundingBalanceRaw) : 0;
            $spotBalance = floatval($usdcBalance['spot_balance'] ?? 0);
            
            error_log("USDC breakdown - Funding: $fundingBalance, Spot: $spotBalance");
            
            // CRITICAL: Withdrawals can ONLY be made from spot wallet
            // If there's ANY USDC in funding wallet, transfer it to spot first
            // But skip if amount is too small (less than 0.01 USDC) - not worth transferring
            $skipWithdrawal = false;
            $minTransferAmount = 0.01; // Minimum amount to transfer (avoid rounding to 0)
            
            if ($fundingBalance >= $minTransferAmount) {
                error_log("USDC found in funding account ($fundingBalance). Transferring ALL funding balance to spot account for withdrawal...");
                $transferResult = $binance->transferFundingToSpot('USDC', $fundingBalance);
                
                if (isset($transferResult['error'])) {
                    $errorMsg = $transferResult['error'] ?? 'Unknown error';
                    error_log("ERROR: Transfer from funding to spot failed: " . $errorMsg);
                    error_log("Cannot withdraw without transferring to spot first. Skipping withdrawal.");
                    $skipWithdrawal = true;
                } else {
                    error_log("Transfer successful. Waiting 5 seconds for balance to update...");
                    sleep(5);
                    
                    // Re-check balance after transfer - all should be in spot now
                    $usdcBalanceAfterTransfer = $binance->getAccountBalance('USDC');
                    $freeUsdc = floatval($usdcBalanceAfterTransfer['free'] ?? $freeUsdc);
                    $spotBalance = floatval($usdcBalanceAfterTransfer['spot_balance'] ?? $freeUsdc);
                    error_log("New USDC balance after transfer - Free: $freeUsdc, Spot: $spotBalance");
                }
            } elseif ($fundingBalance > 0 && $fundingBalance < $minTransferAmount) {
                // Funding balance is too small to transfer (dust), but we can still withdraw from spot
                error_log("Funding balance ($fundingBalance) is too small to transfer (minimum: $minTransferAmount). Proceeding with withdrawal from spot only.");
            }
            
            // IMPORTANT: Only withdraw from spot balance (withdrawals require spot wallet)
            if (!$skipWithdrawal) {
                // CRITICAL: Withdrawals can ONLY be made from spot wallet
                // We MUST use only spot balance, not total balance
                // If transfer happened, spot balance should now include the transferred funds
                // If no transfer happened (funding was 0), use spot balance only
                $availableForWithdrawal = $spotBalance; // ALWAYS use spot balance only
                error_log("Available USDC in spot wallet for withdrawal: $availableForWithdrawal (Total: $freeUsdc, Spot: $spotBalance, Funding: $fundingBalance)");
                
                // Reserve at least 1 USDC for withdrawal fees
                $minReserve = 1.0;
                $withdrawAmount = round(max(0, $availableForWithdrawal - $minReserve), 6);
                
                if ($withdrawAmount < 10) {
                    error_log("WARNING: Withdrawal amount ($withdrawAmount) is below Binance minimum (10 USDC). Skipping withdrawal.");
                    // Don't exit - continue to check USDT trading
                } else {
                    error_log("Withdrawing $withdrawAmount USDC to Polygon address: $withdrawalWallet");
                    
                    // Try withdrawal
                    $withdrawResult = $binance->withdraw('USDC', $withdrawalWallet, $withdrawAmount, 'MATIC');
                    
                    if (isset($withdrawResult['error'])) {
                        error_log("ERROR withdrawing USDC: " . $withdrawResult['error']);
                        error_log("Withdrawal response: " . json_encode($withdrawResult));
                        // Don't exit - continue to check USDT trading
                    } else {
                        $withdrawId = $withdrawResult['id'] ?? 'UNKNOWN';
                        error_log("✓ USDC withdrawal initiated successfully - ID: $withdrawId");
                        error_log("Withdrawal details: " . json_encode($withdrawResult));
                        
                        // Log the withdrawal to database
                        try {
                            $stmt = $pdo->prepare("
                                INSERT INTO binance_auto_trades 
                                (usdt_balance, usdc_received, withdraw_amount, withdraw_address, 
                                 withdraw_id, status, created_at)
                                VALUES (0, ?, ?, ?, ?, 'completed', NOW())
                            ");
                            $stmt->execute([
                                $freeUsdc, // USDC received (in this case, it's the balance before withdrawal)
                                $withdrawAmount,
                                $withdrawalWallet,
                                $withdrawId
                            ]);
                            error_log("USDC withdrawal logged to database");
                        } catch (Exception $e) {
                            error_log("WARNING: Could not log USDC withdrawal to database: " . $e->getMessage());
                        }
                        
                        error_log("=== USDC Auto-Withdrawal Completed ===");
                        // Continue to check USDT trading below
                    }
                } // Close the else block for $withdrawAmount >= 10
            } // Close the if (!$skipWithdrawal) block
        } else {
            error_log("USDC balance ($freeUsdc) is below withdrawal threshold ($minUsdcBalance). Skipping withdrawal.");
        }
    } else {
        error_log("ERROR getting USDC balance: " . json_encode($usdcBalance['error']));
        // Continue to check USDT trading even if USDC check fails
    }
    
    // ========================================
    // STEP 2: Check USDT Balance and Convert
    // ========================================
    error_log("=== STEP 2: Checking USDT Balance for Trading ===");
    
    // Step 2: Check USDT balance
    error_log("Checking USDT balance across all account types...");
    
    // First, get all balances for debugging
    error_log("=== COMPREHENSIVE BALANCE CHECK ===");
    $allBalances = $binance->getAllBalances();
    $usdtEntries = array_filter($allBalances, function($b) {
        return strtoupper($b['asset'] ?? '') === 'USDT';
    });
    
    if (!empty($usdtEntries)) {
        error_log("✓ Found USDT in comprehensive balance check:");
        foreach ($usdtEntries as $entry) {
            error_log("  - " . $entry['account'] . ": Free=" . $entry['free'] . ", Locked=" . $entry['locked'] . ", Total=" . $entry['total']);
        }
    } else {
        error_log("✗ WARNING: USDT NOT FOUND in comprehensive balance check!");
        error_log("Total assets found: " . count($allBalances));
        
        // List all unique assets found
        $uniqueAssets = array_unique(array_map(function($b) {
            return $b['asset'];
        }, $allBalances));
        error_log("Unique assets found (" . count($uniqueAssets) . "): " . implode(', ', array_slice($uniqueAssets, 0, 50)));
        
        // Check if any asset contains "USD"
        $usdAssets = array_filter($allBalances, function($b) {
            return stripos($b['asset'] ?? '', 'USD') !== false;
        });
        if (!empty($usdAssets)) {
            error_log("USD-related assets found: " . json_encode($usdAssets));
        }
    }
    
    $usdtBalance = $binance->getAccountBalance('USDT');
    
    if (isset($usdtBalance['error'])) {
        error_log("ERROR getting USDT balance: " . json_encode($usdtBalance['error']));
        error_log("Full error response: " . json_encode($usdtBalance));
        exit(1);
    }
    
    $freeUsdt = $usdtBalance['free'] ?? 0;
    $totalUsdt = $usdtBalance['total'] ?? 0;
    $accountType = $usdtBalance['account_type'] ?? 'unknown';
    $foundAsset = $usdtBalance['asset'] ?? 'UNKNOWN';
    
    // CRITICAL: Verify we actually got USDT, not another asset
    if (strtoupper($foundAsset) !== 'USDT') {
        error_log("ERROR: API returned wrong asset! Expected USDT, got: $foundAsset");
        error_log("This is a critical error - cannot proceed with wrong asset");
        exit(1);
    }
    
    error_log("USDT Balance - Free: $freeUsdt, Total: $totalUsdt, Account Type: $accountType");
    error_log("Full balance response: " . json_encode($usdtBalance));
    
    // CRITICAL: Only proceed if balance is in funding or spot (NOT margin)
    if ($accountType === 'margin') {
        error_log("ERROR: USDT is in margin account. We only use funding or spot accounts.");
        error_log("Please transfer USDT from margin to funding or spot account first.");
        exit(1);
    }
    
    // Note: Convert API can work directly from funding wallet, so no transfer needed
    // We'll use the appropriate walletType in the convert request
    
    if ($freeUsdt < $minUsdtBalance) {
        error_log("USDT balance ($freeUsdt) is below threshold ($minUsdtBalance). Skipping conversion.");
        exit(0);
    }
    
    // Step 3: Convert USDT to USDC using Convert API
    error_log("=== STEP 3: Converting USDT to USDC using Convert API ===");
    error_log("Converting $freeUsdt USDT to USDC...");
    
    // Use slightly less than free balance to account for fees
    $convertAmount = round($freeUsdt * 0.999, 2); // Use 99.9% to leave room for fees
    
    // Determine wallet type based on where USDT is located
    // Convert API supports FUNDING, SPOT, or combinations like SPOT_FUNDING
    $walletType = 'SPOT';
    if ($accountType === 'funding') {
        $walletType = 'FUNDING'; // Convert directly from funding wallet (no transfer needed)
        error_log("USDT is in funding account - will convert directly from funding wallet");
    } elseif ($accountType === 'spot') {
        $walletType = 'SPOT';
        error_log("USDT is in spot account - will convert from spot wallet");
    } else {
        // If account type is unknown or both, try SPOT_FUNDING to check both wallets
        $walletType = 'SPOT_FUNDING';
        error_log("Account type is '$accountType' - will try SPOT_FUNDING to check both wallets");
    }
    
    // Step 3a: Get quote for conversion
    error_log("Requesting convert quote: $convertAmount USDT -> USDC (wallet: $walletType)");
    $quoteResult = $binance->getConvertQuote('USDT', 'USDC', $convertAmount, null, $walletType);
    
    if (isset($quoteResult['error']) || !isset($quoteResult['quoteId'])) {
        $errorMsg = $quoteResult['error'] ?? $quoteResult['msg'] ?? 'Unknown error';
        error_log("ERROR getting convert quote: " . $errorMsg);
        error_log("Quote response: " . json_encode($quoteResult));
        exit(1);
    }
    
    $quoteId = $quoteResult['quoteId'];
    $toAmount = $quoteResult['toAmount'] ?? null;
    $ratio = $quoteResult['ratio'] ?? null;
    $validTimestamp = $quoteResult['validTimestamp'] ?? null;
    
    error_log("✓ Quote received - Quote ID: $quoteId");
    error_log("  From: $convertAmount USDT");
    error_log("  To: $toAmount USDC");
    error_log("  Ratio: $ratio");
    error_log("  Valid until: " . ($validTimestamp ? date('Y-m-d H:i:s', $validTimestamp / 1000) : 'N/A'));
    
    // Step 3b: Accept the quote
    error_log("Accepting convert quote: $quoteId");
    $acceptResult = $binance->acceptConvertQuote($quoteId);
    
    if (isset($acceptResult['error']) || !isset($acceptResult['orderId'])) {
        $errorMsg = $acceptResult['error'] ?? $acceptResult['msg'] ?? 'Unknown error';
        error_log("ERROR accepting convert quote: " . $errorMsg);
        error_log("Accept response: " . json_encode($acceptResult));
        exit(1);
    }
    
    $orderId = $acceptResult['orderId'];
    $orderStatus = $acceptResult['orderStatus'] ?? 'UNKNOWN';
    $createTime = $acceptResult['createTime'] ?? null;
    
    error_log("✓ Convert quote accepted - Order ID: $orderId, Status: $orderStatus");
    error_log("Convert details: " . json_encode($acceptResult));
    
    // Step 3c: Wait and check order status
    error_log("Waiting 5 seconds for conversion to process...");
    sleep(5);
    
    // Check order status
    $statusResult = $binance->getConvertOrderStatus($orderId);
    if (!isset($statusResult['error'])) {
        $finalStatus = $statusResult['orderStatus'] ?? $orderStatus;
        error_log("Convert order status: $finalStatus");
        
        if ($finalStatus === 'SUCCESS') {
            error_log("✓ Conversion completed successfully");
        } elseif ($finalStatus === 'PROCESS' || $finalStatus === 'ACCEPT_SUCCESS') {
            error_log("Conversion is processing...");
        } else {
            error_log("WARNING: Conversion status is: $finalStatus");
        }
    }
    
    // Step 4: Check USDC balance after conversion
    error_log("=== STEP 4: Checking USDC balance after conversion ===");
    $usdcBalanceAfterTrade = $binance->getAccountBalance('USDC');
    
    if (isset($usdcBalanceAfterTrade['error'])) {
        error_log("ERROR getting USDC balance: " . $usdcBalanceAfterTrade['error']);
        exit(1);
    }
    
    $freeUsdcAfterTrade = floatval($usdcBalanceAfterTrade['free'] ?? 0);
    $totalUsdcAfterTrade = floatval($usdcBalanceAfterTrade['total'] ?? 0);
    error_log("USDC Balance after conversion - Free: $freeUsdcAfterTrade, Total: $totalUsdcAfterTrade");
    
    if ($freeUsdcAfterTrade < 1) {
        error_log("WARNING: USDC balance is very low ($freeUsdcAfterTrade). Conversion may not have completed yet.");
        exit(0);
    }
    
    // Step 5: Withdraw USDC to Polygon
    error_log("=== STEP 5: Withdrawing USDC to Polygon ===");
    
    // Check if USDC is in funding account - may need to transfer to spot for withdrawal
    $usdcAccountType = $usdcBalanceAfterTrade['account_type'] ?? 'unknown';
    if ($usdcAccountType === 'funding' && $freeUsdcAfterTrade > 0) {
        error_log("USDC is in funding account. Transferring to spot account for withdrawal...");
        $transferResult = $binance->transferFundingToSpot('USDC', $freeUsdcAfterTrade);
        
        if (isset($transferResult['error'])) {
            $errorMsg = $transferResult['error'] ?? 'Unknown error';
            error_log("WARNING: Transfer from funding to spot failed: " . $errorMsg);
            error_log("Attempting withdrawal directly from funding wallet...");
            // Continue with withdrawal attempt - some assets can be withdrawn from funding
        } else {
            error_log("Transfer successful. Waiting 3 seconds for balance to update...");
            sleep(3);
            
            // Re-check balance in spot account
            $usdcBalanceAfterTransfer = $binance->getAccountBalance('USDC');
            $freeUsdcAfterTrade = floatval($usdcBalanceAfterTransfer['free'] ?? $freeUsdcAfterTrade);
            error_log("New USDC balance after transfer - Free: $freeUsdcAfterTrade");
        }
    }
    
    error_log("Withdrawing $freeUsdcAfterTrade USDC to Polygon address: $withdrawalWallet");
    
    // Use slightly less than free balance to account for withdrawal fees
    $withdrawAmount = round($freeUsdcAfterTrade * 0.999, 6); // Use 99.9% to leave room for fees
    
    // Try withdrawal - if transfer failed, attempt from funding wallet (usually won't work)
    $walletType = isset($withdrawFromFunding) && $withdrawFromFunding ? 'FUNDING' : null;
    $withdrawResult = $binance->withdraw('USDC', $withdrawalWallet, $withdrawAmount, 'MATIC', '', $walletType);
    
    if (isset($withdrawResult['error'])) {
        error_log("ERROR withdrawing USDC: " . $withdrawResult['error']);
        error_log("Withdrawal response: " . json_encode($withdrawResult));
        exit(1);
    }
    
    $withdrawId = $withdrawResult['id'] ?? 'UNKNOWN';
    error_log("Withdrawal initiated - ID: $withdrawId");
    error_log("Withdrawal details: " . json_encode($withdrawResult));
    
    // Log the transaction
    try {
        $stmt = $pdo->prepare("
            INSERT INTO binance_auto_trades 
            (usdt_balance, usdc_received, withdraw_amount, withdraw_address, trade_order_id, withdraw_id, status, created_at)
            VALUES (?, ?, ?, ?, ?, ?, 'completed', NOW())
        ");
        $stmt->execute([
            $freeUsdt, // USDT balance before trade
            $freeUsdcAfterTrade, // USDC received after conversion
            $withdrawAmount, // Amount withdrawn
            $withdrawalWallet, // Withdrawal address
            $orderId, // Convert order ID
            $withdrawId // Withdrawal ID
        ]);
        error_log("Transaction logged to database");
    } catch (Exception $e) {
        error_log("WARNING: Could not log transaction to database: " . $e->getMessage());
    }
    
    error_log("=== Auto Convert USDT to USDC Completed Successfully ===");
    
    // Clean output buffer before exit
    if (php_sapi_name() === 'cli' && ob_get_level() > 0) {
        ob_end_clean();
    }
    
    exit(0);
    
} catch (Exception $e) {
        error_log("FATAL ERROR in auto convert: " . $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);
}


