<?php
/**
 * Dolipesa - M-Pesa Payment Module Callback Handler
 * Author: NESTICT INFOTECH
 * Version: 1.0.1
 * License: GNU General Public License v3.0
 */

require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';

// Load translations
$langs->load('dolipesa@dolipesa');

// Check if this is a callback from M-Pesa (no GET params, JSON input expected)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_GET)) {
    // Handle M-Pesa callback
    $callbackData = json_decode(file_get_contents('php://input'), true);

    if (!isset($callbackData['Body']['stkCallback'])) {
        http_response_code(400);
        exit('Invalid callback data');
    }

    $stkCallback = $callbackData['Body']['stkCallback'];
    $resultCode = $stkCallback['ResultCode'];
    $resultDesc = $stkCallback['ResultDesc'];
    $checkoutRequestID = $stkCallback['CheckoutRequestID'];

    // Log the callback response (assumes llx_dolipesa_transactions table exists)
    $sql = "INSERT INTO " . MAIN_DB_PREFIX . "dolipesa_transactions (checkout_request_id, result_code, result_desc, datec) ";
    $sql .= "VALUES ('" . $db->escape($checkoutRequestID) . "', '" . $db->escape($resultCode) . "', ";
    $sql .= "'" . $db->escape($resultDesc) . "', NOW())";
    $db->query($sql);

    // Process successful payment (ResultCode 0 = success)
    if ($resultCode == 0) {
        $callbackMetadata = $stkCallback['CallbackMetadata']['Item'];
        $transactionId = null;
        $amount = null;
        $phoneNumber = null;

        foreach ($callbackMetadata as $item) {
            switch ($item['Name']) {
                case 'MpesaReceiptNumber':
                    $transactionId = $item['Value'];
                    break;
                case 'Amount':
                    $amount = $item['Value'];
                    break;
                case 'PhoneNumber':
                    $phoneNumber = $item['Value'];
                    break;
            }
        }

        // Find invoice linked to this CheckoutRequestID (you will need to store this mapping)
        $sql = "SELECT fk_invoice FROM " . MAIN_DB_PREFIX . "dolipesa_transactions ";
        $sql .= "WHERE checkout_request_id = '" . $db->escape($checkoutRequestID) . "'";
        $resql = $db->query($sql);
        if ($resql && $obj = $db->fetch_object($resql)) {
            $invoice = new Facture($db);
            $invoice->fetch($obj->fk_invoice);

            if ($invoice->id && $invoice->statut == 1) { // Validated invoice
                // Mark invoice as paid
                $invoice->setPaid($user, '', $transactionId);
                // Log transaction with invoice link
                $sql = "UPDATE " . MAIN_DB_PREFIX . "dolipesa_transactions ";
                $sql .= "SET fk_invoice = " . $invoice->id . ", transaction_id = '" . $db->escape($transactionId) . "' ";
                $sql .= "WHERE checkout_request_id = '" . $db->escape($checkoutRequestID) . "'";
                $db->query($sql);
            }
        }
    }

    http_response_code(200);
    exit('Callback processed');
}

// Payment initiation (assumes this is accessed via GET with invoice_id and token)
$invoiceId = GETPOST('invoice_id', 'int');
$token = GETPOST('token', 'alpha');

if (!$invoiceId || !$token) {
    accessforbidden($langs->trans('MissingParameters'));
}

// Validate token (simple example; improve as needed)
$expectedToken = md5($invoiceId . $conf->global->MAIN_SECURITY_SALT); // Use a more secure method in production
if ($token !== $expectedToken) {
    accessforbidden($langs->trans('InvalidToken'));
}

// Load invoice
$invoice = new Facture($db);
if ($invoice->fetch($invoiceId) <= 0 || $invoice->statut != 1) {
    accessforbidden($langs->trans('InvoiceNotFoundOrNotValidated'));
}

// Process payment submission
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $phoneNumber = GETPOST('phone_number', 'alpha');
    $amount = floatval($invoice->total_ttc); // Use invoice total

    // Validate phone number (Kenyan format: 2547XXXXXXXX)
    if (!preg_match('/^254[0-9]{9}$/', $phoneNumber)) {
        setEventMessages($langs->trans('InvalidPhoneNumber'), null, 'errors');
    } else {
        // Load M-Pesa credentials
        $consumerKey = $conf->global->MPESAPAY_CONSUMER_KEY;
        $consumerSecret = dol_decrypt($conf->global->MPESAPAY_CONSUMER_SECRET);
        $shortcode = $conf->global->MPESAPAY_SHORTCODE;
        $passkey = dol_decrypt($conf->global->MPESAPAY_PASSKEY);
        $callbackUrl = $conf->global->MPESAPAY_CALLBACK_URL ?: DOL_MAIN_URL_ROOT . '/custom/dolipesa/callback.php';

        // Generate OAuth token
        $credentials = base64_encode($consumerKey . ':' . $consumerSecret);
        $tokenResponse = dol_http_get('https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials', [
            'Authorization: Basic ' . $credentials
        ]);
        $tokenData = json_decode($tokenResponse, true);
        $accessToken = $tokenData['access_token'] ?? null;

        if (!$accessToken) {
            setEventMessages($langs->trans('FailedToGetMpesaToken'), null, 'errors');
        } else {
            // Prepare STK Push payload
            $timestamp = date('YmdHis');
            $password = base64_encode($shortcode . $passkey . $timestamp);
            $payload = [
                'BusinessShortCode' => $shortcode,
                'Password' => $password,
                'Timestamp' => $timestamp,
                'TransactionType' => 'CustomerPayBillOnline',
                'Amount' => $amount,
                'PartyA' => $phoneNumber,
                'PartyB' => $shortcode,
                'PhoneNumber' => $phoneNumber,
                'CallBackURL' => $callbackUrl,
                'AccountReference' => $invoice->ref,
                'TransactionDesc' => 'Payment for Invoice #' . $invoice->ref
            ];

            // Send STK Push request
            $response = dol_http_post('https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest', json_encode($payload), [
                'Authorization: Bearer ' . $accessToken,
                'Content-Type: application/json'
            ]);
            $responseData = json_decode($response, true);

            if ($responseData && $responseData['ResponseCode'] == '0') {
                // Store CheckoutRequestID for callback mapping
                $checkoutRequestID = $responseData['CheckoutRequestID'];
                $sql = "INSERT INTO " . MAIN_DB_PREFIX . "dolipesa_transactions (checkout_request_id, fk_invoice, datec) ";
                $sql .= "VALUES ('" . $db->escape($checkoutRequestID) . "', " . $invoice->id . ", NOW())";
                $db->query($sql);

                setEventMessages($langs->trans('PaymentInitiated'), null, 'mesgs');
            } else {
                setEventMessages($langs->trans('PaymentInitiationFailed') . ': ' . ($responseData['errorMessage'] ?? 'Unknown error'), null, 'errors');
            }
        }
    }
}

// Display payment form
print load_fiche_titre($langs->trans('PayInvoice', $invoice->ref));
print '<form method="POST" action="' . $_SERVER['PHP_SELF'] . '?invoice_id=' . $invoiceId . '&token=' . $token . '">';
print '<table class="noborder">';
print '<tr><td><label for="phone_number">' . $langs->trans('PhoneNumber') . ' (254...):</label></td>';
print '<td><input type="text" name="phone_number" id="phone_number" pattern="^254[0-9]{9}$" value="254" required></td></tr>';
print '<tr><td><label for="amount">' . $langs->trans('Amount') . ':</label></td>';
print '<td><input type="number" name="amount" id="amount" value="' . price($invoice->total_ttc) . '" readonly></td></tr>';
print '</table>';
print '<div class="center"><input type="submit" class="button" value="' . $langs->trans('PayNow') . '"></div>';
print '</form>';

llxFooter();
$db->close();
?>