<?php
// mpesa-callback.php - M-PESA STK Push Callback Handler with Goal Allocation
ini_set('display_errors', 1);
error_log("M-PESA Callback accessed at: " . date('Y-m-d H:i:s'));

// Database configuration
const DB_HOST = 'localhost';
const DB_USER = 'gnmprime_root';
const DB_PASS = 'Moses@4602';
const DB_NAME = 'gnmprime_saveapp';
const DEBUG = true;

// Connect to MySQL
function getDbConnection() {
    $conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
    if ($conn->connect_error) {
        error_log("Database connection failed: " . $conn->connect_error);
        http_response_code(500);
        echo json_encode(['ResponseCode' => '1', 'ResponseDesc' => 'System error']);
        exit;
    }
    return $conn;
}

function logError($message) {
    error_log("[M-PESA Callback ERROR] " . $message);
}

function logInfo($message) {
    error_log("[M-PESA Callback INFO] " . $message);
}

// Read raw callback data
$callbackData = file_get_contents('php://input');
logInfo("Received raw callback: " . $callbackData);

if (empty($callbackData)) {
    logError("No callback data received");
    http_response_code(400);
    echo json_encode(['ResponseCode' => '1', 'ResponseDesc' => 'No data received']);
    exit;
}

$callbackJson = json_decode($callbackData, true);
if (json_last_error() !== JSON_ERROR_NONE) {
    logError("Invalid JSON received: " . json_last_error_msg());
    http_response_code(400);
    echo json_encode(['ResponseCode' => '1', 'ResponseDesc' => 'Invalid JSON']);
    exit;
}

if (!isset($callbackJson['Body']['stkCallback']['CheckoutRequestID'])) {
    logError("Missing CheckoutRequestID in callback");
    http_response_code(400);
    echo json_encode(['ResponseCode' => '1', 'ResponseDesc' => 'Invalid callback format']);
    exit;
}

$stkCallback = $callbackJson['Body']['stkCallback'];
$checkoutRequestId = $stkCallback['CheckoutRequestID'];
$resultCode = $stkCallback['ResultCode'];
$resultDesc = $stkCallback['ResultDesc'] ?? 'No description';

logInfo("Processing CheckoutRequestID: $checkoutRequestId | ResultCode: $resultCode");

$conn = getDbConnection();

// Find transaction
$stmt = $conn->prepare("
    SELECT 
        id, 
        user_id, 
        savings_amount, 
        allocated_goal_id, 
        merchant_paybill, 
        merchant_account, 
        merchant_amount,
        status
    FROM transactions 
    WHERE checkout_request_id = ? 
    LIMIT 1
");
if (!$stmt) {
    logError("Prepare failed: " . $conn->error);
    http_response_code(500);
    echo json_encode(['ResponseCode' => '1', 'ResponseDesc' => 'System error']);
    $conn->close();
    exit;
}

$stmt->bind_param("s", $checkoutRequestId);
$stmt->execute();
$result = $stmt->get_result();
$transaction = $result->fetch_assoc();
$stmt->close();

if (!$transaction) {
    logError("Transaction not found for CheckoutRequestID: $checkoutRequestId");
    http_response_code(404);
    echo json_encode(['ResponseCode' => '1', 'ResponseDesc' => 'Transaction not found']);
    $conn->close();
    exit;
}

$transactionId = $transaction['id'];
$userId = $transaction['user_id'];
$savingsAmount = (float)$transaction['savings_amount'];
$goalId = $transaction['allocated_goal_id'] ? (int)$transaction['allocated_goal_id'] : null;
$currentStatus = $transaction['status'];

// Prevent duplicate processing
if ($currentStatus === 'completed') {
    logInfo("Transaction $transactionId already completed – ignoring duplicate callback");
    $conn->close();
    echo json_encode(['ResponseCode' => '0', 'ResponseDesc' => 'Success']);
    exit;
}

// Extract M-PESA receipt
$mpesaReceipt = '';
if (isset($stkCallback['CallbackMetadata']['Item'])) {
    foreach ($stkCallback['CallbackMetadata']['Item'] as $item) {
        if ($item['Name'] === 'MpesaReceiptNumber') {
            $mpesaReceipt = $item['Value'];
            break;
        }
    }
}

if ($resultCode == 0) {
    // Payment SUCCESS
    logInfo("Payment successful for transaction $transactionId");

    // Update transaction to completed
    $stmt = $conn->prepare("
        UPDATE transactions 
        SET status = 'completed', 
            mpesa_receipt = ?, 
            validated_at = NOW() 
        WHERE id = ?
    ");
    $stmt->bind_param("si", $mpesaReceipt, $transactionId);
    $stmt->execute();
    $stmt->close();

    // Forward to merchant (your existing logic)
    $merchantResponse = forwardToMerchant(
        $transactionId,
        $transaction['merchant_paybill'],
        $transaction['merchant_account'],
        $transaction['merchant_amount']
    );

    if ($merchantResponse['status'] === 'success') {
        $stmt = $conn->prepare("UPDATE transactions SET merchant_status = 'completed', merchant_reference = ? WHERE id = ?");
        $stmt->bind_param("si", $merchantResponse['reference'], $transactionId);
    } else {
        $stmt = $conn->prepare("UPDATE transactions SET merchant_status = 'failed', merchant_error = ? WHERE id = ?");
        $stmt->bind_param("si", $merchantResponse['message'], $transactionId);
    }
    $stmt->execute();
    $stmt->close();

    // === GOAL ALLOCATION LOGIC ===
    if ($savingsAmount > 0 && $goalId !== null) {
        logInfo("Allocating KSh $savingsAmount savings to goal ID $goalId for user $userId");

        // Validate goal still exists and is active
        $stmt = $conn->prepare("
            SELECT id, target_amount, current_amount 
            FROM savings_goals 
            WHERE id = ? AND user_id = ? AND status = 'active'
        ");
        $stmt->bind_param("ii", $goalId, $userId);
        $stmt->execute();
        $goalResult = $stmt->get_result();
        $goal = $goalResult->fetch_assoc();
        $stmt->close();

        if ($goal) {
            $newCurrent = $goal['current_amount'] + $savingsAmount;

            // Record contribution
            $stmt = $conn->prepare("
                INSERT INTO goal_contributions 
                (user_id, goal_id, amount, source_transaction_id, created_at)
                VALUES (?, ?, ?, ?, NOW())
            ");
            $stmt->bind_param("iidi", $userId, $goalId, $savingsAmount, $transactionId);
            $stmt->execute();
            $stmt->close();

            // Update goal progress
            $updateQuery = "
                UPDATE savings_goals 
                SET current_amount = ?
            ";
            if ($newCurrent >= $goal['target_amount']) {
                $updateQuery .= ", status = 'completed', completed_at = NOW()";
            }
            $updateQuery .= " WHERE id = ?";

            $stmt = $conn->prepare($updateQuery);
            $stmt->bind_param("di", $newCurrent, $goalId);
            $stmt->execute();
            $stmt->close();

            logInfo("Goal $goalId updated. New progress: $newCurrent / {$goal['target_amount']}" . 
                    ($newCurrent >= $goal['target_amount'] ? " → COMPLETED!" : ""));
        } else {
            logError("Goal ID $goalId not found or no longer active – savings not allocated");
        }
    }

    // Clean up temporary goal allocation
    $stmt = $conn->prepare("UPDATE transactions SET allocated_goal_id = NULL WHERE id = ?");
    $stmt->bind_param("i", $transactionId);
    $stmt->execute();
    $stmt->close();

    logInfo("Transaction $transactionId fully processed with savings allocation");

} else {
    // Payment FAILED
    logError("Payment failed for transaction $transactionId: $resultDesc");

    $stmt = $conn->prepare("
        UPDATE transactions 
        SET status = 'failed', 
            error_message = ? 
        WHERE id = ?
    ");
    $stmt->bind_param("si", $resultDesc, $transactionId);
    $stmt->execute();
    $stmt->close();
}

$conn->close();

// Always acknowledge receipt to M-PESA
echo json_encode(['ResponseCode' => '0', 'ResponseDesc' => 'Success']);