<?php
/**
 * process_withdrawal.php
 * 
 * Admin endpoint to process pending withdrawal requests
 * Allows admins to approve or reject withdrawal requests
 * Records transaction details and crypto transaction hash
 * Part of the Ton Sui Mining investment lifecycle
 */

header('Content-Type: application/json');
// Critical: Add cache control headers
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// CRITICAL: Allow origin with credentials (no wildcard when credentials=true)
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (!empty($origin)) {
    header('Access-Control-Allow-Origin: ' . $origin);
} else {
    $scheme = $_SERVER['REQUEST_SCHEME'] ?? 'https';
    $host = $_SERVER['HTTP_HOST'] ?? '';
    if (!empty($host)) {
        header('Access-Control-Allow-Origin: ' . $scheme . '://' . $host);
    }
}
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, Cache-Control');
header('Access-Control-Allow-Credentials: true');
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// Define TONSUI_LOADED constant to prevent direct access to session_init.php
define('TONSUI_LOADED', true);

// Include centralized session initialization
require_once __DIR__ . '/session_init.php';

// Require admin authentication
requireAdmin();

require_once 'config.php';
require_once 'db.php';
require_once 'email_helper.php';

// Validate request method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Method not allowed']);
    exit;
}

// Get and validate POST data
$json_data = file_get_contents('php://input');
$data = json_decode($json_data, true);

if (!$data || !isset($data['transaction_id']) || !isset($data['action'])) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Missing required fields']);
    exit;
}

$transaction_id = intval($data['transaction_id']);
$action = $data['action']; // 'approve', 'reject'
$tx_hash = isset($data['tx_hash']) ? trim($data['tx_hash']) : null;
$admin_notes = isset($data['admin_notes']) ? trim($data['admin_notes']) : '';

// Validate action
if (!in_array($action, ['approve', 'reject'])) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Invalid action']);
    exit;
}

// Transaction hash is optional - can be added later if needed
// Admins can approve without hash and update later

try {
    // Begin transaction
    $pdo->beginTransaction();
    
    // Introspect schemas for tolerant updates
    $tx_has_updated = false;
    $pin_has_status = false; $pin_has_used = false; $pin_has_used_at = false; $pin_has_notes = false; $pin_has_tx = false; $pin_has_updated = false;
    $user_has_total_withdrawn = false;
    try {
        $c1 = $pdo->query("SHOW COLUMNS FROM transactions");
        while ($c = $c1->fetch(PDO::FETCH_ASSOC)) {
            if (strtolower($c['Field'] ?? '') === 'updated_at') $tx_has_updated = true;
        }
    } catch (Exception $ie) { /* ignore */ }
    try {
        $c2 = $pdo->query("SHOW COLUMNS FROM withdrawal_pins");
        while ($c = $c2->fetch(PDO::FETCH_ASSOC)) {
            $f = strtolower($c['Field'] ?? '');
            if ($f === 'status') $pin_has_status = true;
            if ($f === 'used') $pin_has_used = true;
            if ($f === 'used_at') $pin_has_used_at = true;
            if ($f === 'notes') $pin_has_notes = true;
            if ($f === 'transaction_id') $pin_has_tx = true;
            if ($f === 'updated_at') $pin_has_updated = true;
        }
    } catch (Exception $ie) { /* ignore */ }
    try {
        $c3 = $pdo->query("SHOW COLUMNS FROM users");
        while ($c = $c3->fetch(PDO::FETCH_ASSOC)) {
            if (strtolower($c['Field'] ?? '') === 'total_withdrawn') $user_has_total_withdrawn = true;
        }
    } catch (Exception $ie) { /* ignore */ }
    
    // Get the withdrawal transaction
    $transStmt = $pdo->prepare("
        SELECT t.*, u.email, u.username
        FROM transactions t
        JOIN users u ON t.user_id = u.id
        WHERE t.id = ? AND t.type = 'withdrawal' AND t.status = 'pending'
    ");
    
    $transStmt->execute([$transaction_id]);
    $transaction = $transStmt->fetch(PDO::FETCH_ASSOC);
    
    if (!$transaction) {
        throw new Exception('Transaction not found or not a pending withdrawal');
    }
    
    // Parse transaction details
    $details = json_decode($transaction['details'], true) ?? [];
    
    // Add admin action information
    $details['admin_action'] = $action;
    $details['admin_id'] = isset($_SESSION['admin_id']) ? $_SESSION['admin_id'] : 1;
    $details['admin_notes'] = $admin_notes;
    $details['processed_at'] = date('Y-m-d H:i:s');
    
    if ($tx_hash) {
        $details['tx_hash'] = $tx_hash;
    }
    
    $updated_details = json_encode($details);
    
    if ($action === 'approve') {
        // Update transaction status
        $txSql = "UPDATE transactions SET status='completed', details=?" . ($tx_has_updated ? ", updated_at=NOW()" : "") . " WHERE id = ?";
        $updateTransStmt = $pdo->prepare($txSql);
        $updateTransStmt->execute([$updated_details, $transaction_id]);
        
        // Get any PIN associated with this transaction (schema-aware)
        $selectCols = 'id, pin' . ($pin_has_status ? ', status' : '');
        $pinWhere = ($pin_has_tx ? 'transaction_id = ?' : '1=0') . ' OR id = ?';
        $getPinStmt = $pdo->prepare("SELECT $selectCols FROM withdrawal_pins WHERE $pinWhere");

        $pin_id = $details['withdrawal_pin_id'] ?? null;
        $getPinStmt->execute([$transaction_id, $pin_id]);
        $pin = $getPinStmt->fetch(PDO::FETCH_ASSOC);
        
        // If we found a PIN, mark it as used
        if ($pin) {
            if ($pin_has_status) {
                $sql = "UPDATE withdrawal_pins SET status='used'" .
                       ($pin_has_tx ? ", transaction_id=?" : "") .
                       ($pin_has_notes ? ", notes = CONCAT(IFNULL(notes, ''), ' | Used in approved withdrawal #', ?)" : "") .
                       ($pin_has_updated ? ", updated_at=NOW()" : "") .
                       " WHERE id=?";
                $updatePinStmt = $pdo->prepare($sql);
                $params = [];
                if ($pin_has_tx) $params[] = $transaction_id;
                if ($pin_has_notes) $params[] = $transaction_id;
                $params[] = $pin['id'];
                $updatePinStmt->execute($params);
            } elseif ($pin_has_used) {
                $sql = "UPDATE withdrawal_pins SET used=1" .
                       ($pin_has_tx ? ", transaction_id=?" : "") .
                       ($pin_has_used_at ? ", used_at=NOW()" : "") .
                       ($pin_has_notes ? ", notes = CONCAT(IFNULL(notes, ''), ' | Used in approved withdrawal #', ?)" : "") .
                       " WHERE id=?";
                $updatePinStmt = $pdo->prepare($sql);
                $params = [];
                if ($pin_has_tx) $params[] = $transaction_id;
                if ($pin_has_notes) $params[] = $transaction_id;
                $params[] = $pin['id'];
                $updatePinStmt->execute($params);
            }
            
            // Add PIN info to transaction details
            $details['withdrawal_pin_id'] = $pin['id'];
            $details['withdrawal_pin'] = $pin['pin'];
            $details['withdrawal_pin_status'] = 'used';
            $updated_details = json_encode($details);
        }
        
        // Update user's withdrawal stats
        if ($user_has_total_withdrawn) {
            $updateUserStmt = $pdo->prepare("UPDATE users SET total_withdrawn = COALESCE(total_withdrawn, 0) + ?, updated_at = NOW() WHERE id = ?");
            $updateUserStmt->execute([$transaction['amount'], $transaction['user_id']]);
        } else {
            $updateUserStmt = $pdo->prepare("UPDATE users SET updated_at = NOW() WHERE id = ?");
            $updateUserStmt->execute([$transaction['user_id']]);
        }
        
        $status_message = 'approved';
    } else {
        // Reject the withdrawal and refund the user
        
        // Update transaction status
        $txSql = "UPDATE transactions SET status='rejected', details=?" . ($tx_has_updated ? ", updated_at=NOW()" : "") . " WHERE id = ?";
        $updateTransStmt = $pdo->prepare($txSql);
        $updateTransStmt->execute([$updated_details, $transaction_id]);
        
        // Refund the amount to user's balance
        $updateBalanceStmt = $pdo->prepare("
            UPDATE users 
            SET 
                balance = balance + ?,
                updated_at = NOW() 
            WHERE id = ?
        ");
        
        $updateBalanceStmt->execute([$transaction['amount'], $transaction['user_id']]);
        
        // Get any PIN associated with this transaction (schema-aware)
        $selectCols = 'id, pin' . ($pin_has_status ? ', status' : '');
        $pinWhere = ($pin_has_tx ? 'transaction_id = ?' : '1=0') . ' OR id = ?';
        $getPinStmt = $pdo->prepare("SELECT $selectCols FROM withdrawal_pins WHERE $pinWhere");

        $pin_id = $details['withdrawal_pin_id'] ?? null;
        $getPinStmt->execute([$transaction_id, $pin_id]);
        $pin = $getPinStmt->fetch(PDO::FETCH_ASSOC);
        
        // If we found a PIN and it's not already used or cancelled
        if ($pin && (!$pin_has_status || ($pin['status'] !== 'cancelled' && $pin['status'] !== 'used'))) {
            // Restore the PIN to active/available
            if ($pin_has_status) {
                $sql = "UPDATE withdrawal_pins SET status='active'" .
                       ($pin_has_tx ? ", transaction_id=NULL" : "") .
                       ($pin_has_notes ? ", notes = CONCAT(IFNULL(notes, ''), ' | Reactivated from rejected withdrawal #', ?)" : "") .
                       ($pin_has_updated ? ", updated_at=NOW()" : "") .
                       " WHERE id = ?";
                $updatePinStmt = $pdo->prepare($sql);
                $params = [];
                if ($pin_has_notes) $params[] = $transaction_id;
                $params[] = $pin['id'];
                $updatePinStmt->execute($params);
            } elseif ($pin_has_used) {
                $sql = "UPDATE withdrawal_pins SET used=0" .
                       ($pin_has_tx ? ", transaction_id=NULL" : "") .
                       ($pin_has_notes ? ", notes = CONCAT(IFNULL(notes, ''), ' | Reactivated from rejected withdrawal #', ?)" : "") .
                       " WHERE id = ?";
                $updatePinStmt = $pdo->prepare($sql);
                $params = [];
                if ($pin_has_notes) $params[] = $transaction_id;
                $params[] = $pin['id'];
                $updatePinStmt->execute($params);
            }
            
            // Add PIN info to transaction details
            $details['withdrawal_pin_id'] = $pin['id'];
            $details['withdrawal_pin'] = $pin['pin'];
            $details['withdrawal_pin_status'] = 'active';
            $updated_details = json_encode($details);
        }
        
        $status_message = 'rejected and refunded';
    }
    
    // Create admin log (non-fatal if table missing)
    $log_details = json_encode([
        'transaction_id' => $transaction_id,
        'user_id' => $transaction['user_id'],
        'amount' => $transaction['amount'],
        'action' => $action,
        'admin_notes' => $admin_notes,
        'tx_hash' => $tx_hash
    ]);
    try {
        $logStmt = $pdo->prepare("INSERT INTO admin_logs (admin_id, action, target_type, target_id, details, created_at) VALUES (?, ?, ?, ?, ?, NOW())");
        $logStmt->execute([
            isset($_SESSION['admin_id']) ? $_SESSION['admin_id'] : 1,
            $action . '_withdrawal',
            'transaction',
            $transaction_id,
            $log_details
        ]);
    } catch (Exception $ie) { /* ignore logging errors */ }
    
    // Commit the transaction
    $pdo->commit();
    
    // Post-commit: send user email notification on approval
    try {
        if ($action === 'approve') {
            // Load latest user data (for name/account fields)
            $usr = null;
            try {
                $uStmt = $pdo->prepare('SELECT email, username, name FROM users WHERE id = ? LIMIT 1');
                $uStmt->execute([ (int)$transaction['user_id'] ]);
                $usr = $uStmt->fetch(PDO::FETCH_ASSOC);
            } catch (Exception $ie) { /* ignore */ }

            $userEmail = $usr['email'] ?? ($transaction['email'] ?? null);
            if ($userEmail) {
                $userName = ($usr['name'] ?? '') ?: ($usr['username'] ?? $transaction['username'] ?? 'User');

                // Extract details JSON
                $detailsArr = is_array($details) ? $details : [];
                $method = !empty($detailsArr['payment_method_name']) ? (string)$detailsArr['payment_method_name'] : 'Transfer';
                $withdrawalAddress = !empty($detailsArr['withdrawal_address']) ? (string)$detailsArr['withdrawal_address'] : '';

                // Currency priority: bank_details.currency > users.account_currency > payment_method.currency
                $finalCurrency = '';
                if (!empty($detailsArr['bank_details']) && !empty($detailsArr['bank_details']['currency'])) {
                    $finalCurrency = strtoupper((string)$detailsArr['bank_details']['currency']);
                }
                if ($finalCurrency === '') {
                    try {
                        $hasAcctCurr = $pdo->query("SHOW COLUMNS FROM users LIKE 'account_currency'")->rowCount() > 0;
                        if ($hasAcctCurr) {
                            $cs = $pdo->prepare('SELECT account_currency FROM users WHERE id = ? LIMIT 1');
                            $cs->execute([ (int)$transaction['user_id'] ]);
                            $rowc = $cs->fetch(PDO::FETCH_ASSOC);
                            if ($rowc && !empty($rowc['account_currency'])) { $finalCurrency = strtoupper((string)$rowc['account_currency']); }
                        }
                    } catch (Exception $ie) { /* ignore */ }
                }
                if ($finalCurrency === '') {
                    $finalCurrency = (string)($detailsArr['payment_method_currency'] ?? 'EUR');
                }

                $amountStr = number_format((float)$transaction['amount'], 2) . ($finalCurrency ? (' ' . $finalCurrency) : '');

                // Account number and available balance
                $accountNumber = '';
                $availableBalance = '';
                try {
                    $col = $pdo->query("SHOW COLUMNS FROM users LIKE 'account_number'");
                    if ($col && $col->rowCount() > 0) {
                        $q = $pdo->prepare('SELECT account_number, balance FROM users WHERE id = ? LIMIT 1');
                    } else {
                        $q = $pdo->prepare('SELECT balance FROM users WHERE id = ? LIMIT 1');
                    }
                    $q->execute([ (int)$transaction['user_id'] ]);
                    $ur = $q->fetch(PDO::FETCH_ASSOC);
                    if ($ur) {
                        if (!empty($ur['account_number'])) { $accountNumber = (string)$ur['account_number']; }
                        $bal = isset($ur['balance']) ? (float)$ur['balance'] : 0.0;
                        $availableBalance = number_format($bal, 2) . ($finalCurrency ? (' ' . $finalCurrency) : '');
                    }
                } catch (Exception $ie) { /* ignore */ }

                // Send approval email
                $emailResult = @sendEmail($pdo, $userEmail, 'withdrawalApproved', [
                    'user_name' => $userName,
                    'amount' => $amountStr,
                    'method' => $method,
                    'withdrawal_address' => $withdrawalAddress,
                    'account_number' => $accountNumber,
                    'available_balance' => $availableBalance,
                    'date' => date('Y-m-d H:i:s'),
                    'currency' => $finalCurrency,
                ]);
                // Log outcome for diagnostics
                try {
                    $logDir = __DIR__ . '/logs';
                    if (!is_dir($logDir)) { @mkdir($logDir, 0775, true); }
                    $logMsg = sprintf(
                        "[%s] process_withdrawal approve: email to %s => %s%s\n",
                        date('Y-m-d H:i:s'),
                        $userEmail,
                        (is_array($emailResult) && !empty($emailResult['success']) ? 'SUCCESS' : 'FAIL'),
                        (is_array($emailResult) && empty($emailResult['success']) ? (' | error=' . ($emailResult['error'] ?? 'unknown')) : '')
                    );
                    @file_put_contents($logDir . '/email_send.log', $logMsg, FILE_APPEND);
                } catch (Exception $ie) { /* ignore */ }
            }
        }
    } catch (Exception $mailErr) { /* ignore email errors */ }
    
    // Return success response
    echo json_encode([
        'success' => true,
        'message' => "Withdrawal request {$status_message} successfully.",
        'transaction' => [
            'id' => $transaction_id,
            'user_id' => $transaction['user_id'],
            'amount' => $transaction['amount'],
            'status' => $action === 'approve' ? 'completed' : 'rejected'
        ]
    ]);
    
} catch (PDOException $e) {
    // Rollback transaction if in progress
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }
    
    error_log('Database error processing withdrawal: ' . $e->getMessage());
    
    http_response_code(500);
    echo json_encode([
        'success' => false, 
        'message' => 'Database error processing withdrawal request.'
    ]);
    
} catch (Exception $e) {
    // Rollback transaction if in progress
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }
    
    http_response_code(400);
    echo json_encode([
        'success' => false, 
        'message' => $e->getMessage()
    ]);
}
