<?php
/**
 * KamiPay Webhook Handler
 * Procesa notificaciones automáticas de cambios de estado de pagos PIX
 */

// Configurar logging de errores
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/../kamipay_webhook.log');

require_once '../configs.php';

// Función para logging
function logWebhook($message, $level = 'INFO') {
    $timestamp = date('Y-m-d H:i:s');
    $logEntry = "[$timestamp] [$level] KamiPay Webhook: $message" . PHP_EOL;
    file_put_contents(__DIR__ . '/../kamipay_webhook.log', $logEntry, FILE_APPEND | LOCK_EX);
}

// Función para responder y terminar
function respondAndExit($code = 200, $message = 'OK') {
    http_response_code($code);
    echo $message;
    exit();
}

// Verificar que sea POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    logWebhook('Invalid request method: ' . $_SERVER['REQUEST_METHOD'], 'ERROR');
    respondAndExit(405, 'Method Not Allowed');
}

// Obtener datos del webhook
$rawInput = file_get_contents('php://input');
$webhookData = json_decode($rawInput, true);

// Log del webhook recibido
logWebhook('Webhook received: ' . $rawInput);

// Verificar que los datos sean válidos
if (!$webhookData || !isset($webhookData['operation_id'])) {
    logWebhook('Invalid webhook data received', 'ERROR');
    respondAndExit(400, 'Invalid Data');
}

try {
    // Extraer información del webhook
    $operation_id = $webhookData['operation_id'];
    $status = $webhookData['status'] ?? 'unknown';
    $txid = $webhookData['txid'] ?? null;
    $bank_txid = $webhookData['bank_txid'] ?? null;
    $amount_brl = $webhookData['amount_brl'] ?? null;
    $amount_usdt = $webhookData['amount_usdt'] ?? null;
    
    logWebhook("Processing webhook for operation: $operation_id, status: $status");
    
    // Guardar log del webhook
    $stmt = $pdo->prepare("
        INSERT INTO kamipay_webhook_logs (operation_id, webhook_data, status, created_at) 
        VALUES (?, ?, ?, NOW())
    ");
    $stmt->execute([$operation_id, $rawInput, $status]);
    
    // Buscar la transacción en nuestra base de datos
    $stmt = $pdo->prepare("SELECT * FROM kamipay_transactions WHERE operation_id = ? LIMIT 1");
    $stmt->execute([$operation_id]);
    $transaction = $stmt->fetch(PDO::FETCH_ASSOC);
    
    if (!$transaction) {
        logWebhook("Transaction not found for operation_id: $operation_id", 'WARNING');
        respondAndExit(404, 'Transaction Not Found');
    }
    
    // Verificar si ya fue procesada
    if ($transaction['status'] === 'completed') {
        logWebhook("Transaction already completed: $operation_id");
        respondAndExit(200, 'Already Processed');
    }
    
    // Mapear estados de KamiPay a nuestros estados
    $newStatus = mapKamiPayStatus($status);
    
    if (!$newStatus) {
        logWebhook("Unknown KamiPay status: $status", 'WARNING');
        respondAndExit(200, 'Unknown Status');
    }
    
    // Actualizar estado de la transacción
    $updateSql = "UPDATE kamipay_transactions SET status = ?, updated_at = NOW()";
    $updateParams = [$newStatus];
    
    if ($txid) {
        $updateSql .= ", txid = ?";
        $updateParams[] = $txid;
    }
    
    if ($bank_txid) {
        $updateSql .= ", bank_txid = ?";
        $updateParams[] = $bank_txid;
    }
    
    if ($newStatus === 'completed') {
        $updateSql .= ", processed_at = NOW()";
    }
    
    $updateSql .= " WHERE id = ?";
    $updateParams[] = $transaction['id'];
    
    $stmt = $pdo->prepare($updateSql);
    $stmt->execute($updateParams);
    
    logWebhook("Transaction status updated: $operation_id -> $newStatus");
    
    // Si el pago fue completado, procesar la donación
    if ($newStatus === 'completed') {
        $success = processPayment($transaction, $pdo);
        
        if ($success) {
            logWebhook("Payment processed successfully: $operation_id");
            
            // Marcar webhook como procesado
            $stmt = $pdo->prepare("UPDATE kamipay_webhook_logs SET processed = TRUE WHERE operation_id = ?");
            $stmt->execute([$operation_id]);
            
        } else {
            logWebhook("Failed to process payment: $operation_id", 'ERROR');
            
            // Revertir estado para reintento manual
            $stmt = $pdo->prepare("UPDATE kamipay_transactions SET status = 'processing' WHERE id = ?");
            $stmt->execute([$transaction['id']]);
        }
    }
    
    respondAndExit(200, 'Processed');
    
} catch (PDOException $e) {
    logWebhook("Database error: " . $e->getMessage(), 'ERROR');
    respondAndExit(500, 'Database Error');
} catch (Exception $e) {
    logWebhook("Unexpected error: " . $e->getMessage(), 'ERROR');
    respondAndExit(500, 'Internal Error');
}

/**
 * Mapear estados de KamiPay a nuestros estados internos
 */
function mapKamiPayStatus($kamiPayStatus) {
    $statusMap = [
        'pending' => 'pending',
        'processing' => 'processing', 
        'done' => 'completed',
        'completed' => 'completed',
        'failed' => 'failed',
        'expired' => 'expired',
        'cancelled' => 'failed',
        'returned' => 'failed'
    ];
    
    return $statusMap[$kamiPayStatus] ?? null;
}

/**
 * Procesar pago completado - agregar JC al personaje
 */
function processPayment($transaction, $pdo) {
    try {
        // Verificar que el personaje aún existe
        $stmt = $pdo->prepare("SELECT obj_id, char_name FROM characters WHERE char_name = ? LIMIT 1");
        $stmt->execute([$transaction['character_name']]);
        $character = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$character) {
            logWebhook("Character not found: " . $transaction['character_name'], 'ERROR');
            return false;
        }
        
        // Calcular JC total con bonus
        $base_jc = $transaction['amount_jc'];
        $bonus_jc = calculateBonus($base_jc);
        $total_jc = $base_jc + $bonus_jc;
        
        // Verificar si ya existe el item JC en el inventario
        $stmt = $pdo->prepare("
            SELECT count FROM items 
            WHERE owner_id = ? AND object_id = 9623 AND loc = 'INVENTORY' 
            LIMIT 1
        ");
        $stmt->execute([$character['obj_id']]);
        $existingJC = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if ($existingJC) {
            // Actualizar cantidad existente
            $stmt = $pdo->prepare("
                UPDATE items 
                SET count = count + ? 
                WHERE owner_id = ? AND object_id = 9623 AND loc = 'INVENTORY'
            ");
            $stmt->execute([$total_jc, $character['obj_id']]);
        } else {
            // Crear nuevo item JC
            $stmt = $pdo->prepare("
                INSERT INTO items (owner_id, object_id, count, loc, loc_data) 
                VALUES (?, 9623, ?, 'INVENTORY', 0)
            ");
            $stmt->execute([$character['obj_id'], $total_jc]);
        }
        
        logWebhook("JC credited: Character={$transaction['character_name']}, Base={$base_jc}, Bonus={$bonus_jc}, Total={$total_jc}");
        
        // Opcional: Enviar notificación in-game si el jugador está conectado
        // sendIngameNotification($character['char_name'], $total_jc);
        
        return true;
        
    } catch (PDOException $e) {
        logWebhook("Error processing payment: " . $e->getMessage(), 'ERROR');
        return false;
    }
}

/**
 * Calcular bonus JC basado en la cantidad
 */
function calculateBonus($amount) {
    $bonus = 0;
    
    if ($amount >= 0 && $amount <= 99) {
        $bonus = floor($amount * 0.10);
    } elseif ($amount >= 100 && $amount <= 499) {
        $bonus = floor($amount * 0.15);
    } elseif ($amount >= 500 && $amount <= 999) {
        $bonus = floor($amount * 0.20);
    } elseif ($amount >= 1000 && $amount <= 2999) {
        $bonus = floor($amount * 0.25);
    } elseif ($amount >= 3000 && $amount <= 7499) {
        $bonus = floor($amount * 0.30);
    } elseif ($amount >= 7500) {
        $bonus = floor($amount * 0.35);
    }
    
    return $bonus;
}

/**
 * Opcional: Enviar notificación in-game
 * Esta función debería implementarse según el sistema de notificaciones del servidor
 */
function sendIngameNotification($characterName, $jcAmount) {
    // Ejemplo de implementación - ajustar según el sistema del servidor
    try {
        global $pdo;
        
        $message = "¡Donación recibida! Se han creditado {$jcAmount} JC a tu cuenta. ¡Gracias por apoyar L2Jade!";
        
        // Insertar mensaje en sistema de correo interno (si existe)
        $stmt = $pdo->prepare("
            INSERT INTO mail (sender_name, receiver_name, subject, message, send_date, unread) 
            VALUES ('L2Jade System', ?, 'Donación PIX Confirmada', ?, NOW(), 1)
        ");
        $stmt->execute([$characterName, $message]);
        
        logWebhook("In-game notification sent to: $characterName");
        
    } catch (Exception $e) {
        logWebhook("Failed to send in-game notification: " . $e->getMessage(), 'WARNING');
    }
}
?>
