<?php
// mpesa/stk_push.php — Unified STK Push Handler (PesaFlux / LipaLink)
// Handles: account activation + digital product purchases

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../includes/functions.php';

// ============================================================================
// CORE: Initiate STK Push via PesaFlux / LipaLink
// ============================================================================
function initiate_stk($phone, $amount, $reference) {
    $apiKey     = getSetting('pesaflux_api_key',     '');
    $businessId = intval(getSetting('pesaflux_business_id', 0));

    if (empty($apiKey) || $businessId < 1) {
        return ['success' => false, 'message' => 'Payment gateway not configured. Contact admin.'];
    }

    $phone  = formatPhoneNumber($phone);
    $amount = (int)$amount;

    $endpoint = 'http://lipalink.co.ke/api/stk_push.php';
    $payload  = json_encode([
        'amount'      => $amount,
        'msisdn'      => $phone,
        'reference'   => $reference,
        'business_id' => $businessId,
    ]);

    $ch = curl_init($endpoint);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/json',
            'X-Api-Key: ' . $apiKey,
        ],
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_TIMEOUT        => 30,
        CURLOPT_SSL_VERIFYPEER => false, // LipaLink uses HTTP; flip when they add HTTPS
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlErr  = curl_error($ch);
    curl_close($ch);

    // Log every request/response for debugging
    $logFile = __DIR__ . '/stk_raw_response.txt';
    file_put_contents($logFile, date('Y-m-d H:i:s') . " REQUEST:  $payload\n",    FILE_APPEND);
    file_put_contents($logFile, date('Y-m-d H:i:s') . " RESPONSE: $response\n\n", FILE_APPEND);

    if ($curlErr) {
        return ['success' => false, 'message' => 'Connection error: ' . $curlErr];
    }

    $decoded = json_decode($response, true);

    // PesaFlux success: { "success": true, "transaction_id": "PFX...", "message": "STK push sent" }
    if (!empty($decoded['success']) && !empty($decoded['transaction_id'])) {
        return [
            'success'                => true,
            'CheckoutRequestID'      => $decoded['transaction_id'],
            'transaction_request_id' => $decoded['transaction_id'],
            'message'                => $decoded['message'] ?? 'STK push sent. Please enter your M-PESA PIN.',
        ];
    }

    return [
        'success' => false,
        'message' => $decoded['error'] ?? $decoded['message'] ?? 'Unknown error from payment gateway',
    ];
}

// ============================================================================
// FORMAT PHONE — always returns 254XXXXXXXXX
// ============================================================================
function formatPhoneNumber($phone) {
    $phone = preg_replace('/[^0-9]/', '', $phone);
    if (substr($phone, 0, 1) === '0')       $phone = '254' . substr($phone, 1);
    elseif (substr($phone, 0, 3) !== '254') $phone = '254' . $phone;
    return $phone;
}

// ============================================================================
// ACTIVATION PAYMENT
// ============================================================================
function processActivationPayment($userId, $phoneNumber, $amount) {
    $conn   = getConnection();
    $amount = (int)$amount;

    $reference = 'ACT_' . $userId . '_' . time() . '_' . rand(1000, 9999);

    $stmt = $conn->prepare("
        INSERT INTO transactions (user_id, wallet_type, amount, type, description, reference, status)
        VALUES (?, 'activation', ?, 'activation_fee', 'Account activation payment', ?, 'pending')
    ");
    $stmt->bind_param("ids", $userId, $amount, $reference);
    $stmt->execute();

    $result = initiate_stk($phoneNumber, $amount, $reference);

    if ($result['success']) {
        $crid = $result['CheckoutRequestID'];  // PFX... transaction_id
        $up   = $conn->prepare("UPDATE transactions SET reference=? WHERE user_id=? AND reference=?");
        $up->bind_param("sis", $crid, $userId, $reference);
        $up->execute();
        return ['success' => true, 'message' => $result['message'], 'checkout_request_id' => $crid];
    }

    $fail = $conn->prepare("UPDATE transactions SET status='failed' WHERE user_id=? AND reference=?");
    $fail->bind_param("is", $userId, $reference);
    $fail->execute();

    return ['success' => false, 'message' => $result['message']];
}

// ============================================================================
// PRODUCT PURCHASE PAYMENT
// ============================================================================
function processProductPayment($userId, $phoneNumber, $productId) {
    $conn = getConnection();

    // 1. Fetch & validate product
    $stmt = $conn->prepare("SELECT * FROM digital_products WHERE id=? AND status='active' LIMIT 1");
    $stmt->bind_param("i", $productId);
    $stmt->execute();
    $product = $stmt->get_result()->fetch_assoc();
    if (!$product) {
        return ['success' => false, 'message' => 'Product not found or unavailable.'];
    }

    // 2. Already purchased?
    $ck = $conn->prepare("SELECT id FROM product_purchases WHERE user_id=? AND product_id=? AND status='completed' LIMIT 1");
    $ck->bind_param("ii", $userId, $productId);
    $ck->execute();
    if ($ck->get_result()->num_rows > 0) {
        return ['success' => false, 'message' => 'You already own this product.'];
    }

    // 3. Resolve phone — use passed phone, fall back to account phone
    if (!empty($phoneNumber)) {
        $phoneNumber = formatPhoneNumber($phoneNumber);
    } else {
        $pStmt = $conn->prepare("SELECT phone FROM users WHERE id=? LIMIT 1");
        $pStmt->bind_param("i", $userId);
        $pStmt->execute();
        $pRow = $pStmt->get_result()->fetch_assoc();
        if (empty($pRow['phone'])) {
            return ['success' => false, 'message' => 'No phone number on your account. Enter one in the payment form.'];
        }
        $phoneNumber = formatPhoneNumber($pRow['phone']);
    }

    // 4. Price is already in KES — no conversion needed
    $amount = (int)round(floatval($product['price']));
    if ($amount < 1) {
        return ['success' => false, 'message' => 'Invalid product price. Contact support.'];
    }

    // 5. Wipe any non-completed row for this user+product
    $dp = $conn->prepare("DELETE FROM product_purchases WHERE user_id=? AND product_id=? AND status != 'completed'");
    $dp->bind_param("ii", $userId, $productId);
    $dp->execute();

    // 6. Create fresh pending purchase row
    $ins = $conn->prepare("
        INSERT INTO product_purchases (user_id, product_id, amount_paid, status, checkout_request_id, download_token)
        VALUES (?, ?, ?, 'pending', NULL, NULL)
        ON DUPLICATE KEY UPDATE
            amount_paid         = VALUES(amount_paid),
            status              = 'pending',
            checkout_request_id = NULL,
            download_token      = NULL
    ");
    $ins->bind_param("iii", $userId, $productId, $amount);
    $ins->execute();

    $purchaseId = $conn->insert_id;
    if (!$purchaseId) {
        $fi = $conn->prepare("SELECT id FROM product_purchases WHERE user_id=? AND product_id=? LIMIT 1");
        $fi->bind_param("ii", $userId, $productId);
        $fi->execute();
        $fiRow      = $fi->get_result()->fetch_assoc();
        $purchaseId = $fiRow['id'] ?? 0;
    }

    if (!$purchaseId) {
        return ['success' => false, 'message' => 'Failed to create purchase record. Please try again.'];
    }

    // 7. Build reference and create pending transaction
    $reference = 'PROD_' . $purchaseId . '_' . $userId . '_' . time();
    $meta      = json_encode([
        'purchase_id' => $purchaseId,
        'product_id'  => $productId,
        'type'        => 'product_purchase',
    ]);
    $desc = 'Digital product: ' . $product['title'];

    $tStmt = $conn->prepare("
        INSERT INTO transactions (user_id, type, amount, description, reference, status, meta_json)
        VALUES (?, 'product_purchase', ?, ?, ?, 'pending', ?)
    ");
    $tStmt->bind_param("iisss", $userId, $amount, $desc, $reference, $meta);
    $tStmt->execute();

    // Store initial reference in purchase row
    $upd = $conn->prepare("UPDATE product_purchases SET checkout_request_id=? WHERE id=?");
    $upd->bind_param("si", $reference, $purchaseId);
    $upd->execute();

    // 8. Fire STK push
    $result = initiate_stk($phoneNumber, $amount, $reference);

    if ($result['success']) {
        $crid = $result['CheckoutRequestID'];  // PFX... transaction_id

        $ru = $conn->prepare("UPDATE transactions SET reference=? WHERE reference=?");
        $ru->bind_param("ss", $crid, $reference);
        $ru->execute();

        $rp = $conn->prepare("UPDATE product_purchases SET checkout_request_id=? WHERE id=?");
        $rp->bind_param("si", $crid, $purchaseId);
        $rp->execute();

        return [
            'success'             => true,
            'message'             => $result['message'],
            'purchase_id'         => $purchaseId,
            'checkout_request_id' => $crid,
        ];
    }

    // 9. STK failed
    $conn->prepare("UPDATE product_purchases SET status='failed' WHERE id=?")->execute([$purchaseId]) ;
    $conn->prepare("UPDATE transactions SET status='failed' WHERE reference=?")->execute([$reference]);

    return ['success' => false, 'message' => $result['message']];
}

// ============================================================================
// CHECK TRANSACTION STATUS
// Queries PesaFlux API directly, then syncs DB.
// This catches cancellations even when PesaFlux doesn't fire a webhook.
// ============================================================================
function checkTransactionStatus($checkoutRequestID) {
    $conn   = getConnection();
    $apiKey = getSetting('pesaflux_api_key', '');

    // ── 1. Always ask PesaFlux first if we have a PFX... transaction_id ──────
    if (!empty($apiKey) && strpos($checkoutRequestID, 'PFX') === 0) {
        $url = 'http://lipalink.co.ke/api/transaction_status.php?transaction_id=' . urlencode($checkoutRequestID);

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => ['X-Api-Key: ' . $apiKey],
            CURLOPT_TIMEOUT        => 10,
            CURLOPT_SSL_VERIFYPEER => false,
        ]);
        $response = curl_exec($ch);
        $curlErr  = curl_error($ch);
        curl_close($ch);

        if (!$curlErr && $response) {
            $d = json_decode($response, true);

            // Log the raw response for debugging
            $logFile = dirname(__FILE__) . '/stk_raw_response.txt';
            file_put_contents($logFile, "[" . date('Y-m-d H:i:s') . "] STATUS CHECK ref=$checkoutRequestID resp=$response
", FILE_APPEND);

            if (!empty($d['success'])) {
                $pfStatus = strtolower($d['status'] ?? '');

                // Map PesaFlux status → our DB status
                if ($pfStatus === 'success') {
                    $dbStatus = 'completed';
                } elseif (in_array($pfStatus, ['failed', 'cancelled', 'canceled'])) {
                    // Distinguish cancel vs failure using result_desc
                    $desc = strtolower($d['result_desc'] ?? '');
                    $isCancelDesc = (
                        strpos($desc, 'cancel') !== false ||
                        strpos($desc, 'reject') !== false ||
                        strpos($desc, '1032')   !== false ||
                        strpos($desc, '1037')   !== false
                    );
                    $dbStatus = $isCancelDesc ? 'failed' : 'failed'; // both map to failed (enum safe)
                    $cancelReason = $isCancelDesc ? 'cancelled_by_user' : 'failed';
                } else {
                    $dbStatus = 'pending'; // still processing
                }

                // ── Sync DB if status changed ─────────────────────────────────
                if ($dbStatus !== 'pending') {
                    $meta = json_encode([
                        'synced_from_api' => true,
                        'pf_status'       => $pfStatus,
                        'result_desc'     => $d['result_desc'] ?? '',
                        'mpesa_receipt'   => $d['mpesa_receipt'] ?? null,
                        'reason'          => $cancelReason ?? $dbStatus,
                        'synced_at'       => date('Y-m-d H:i:s'),
                    ]);

                    $upd = $conn->prepare("UPDATE transactions SET status=?, meta_json=? WHERE reference=? AND status='pending'");
                    $upd->bind_param("sss", $dbStatus, $meta, $checkoutRequestID);
                    $upd->execute();

                    // Also sync product_purchases / wallet_recharges
                    $upd2 = $conn->prepare("UPDATE product_purchases SET status=? WHERE checkout_request_id=? AND status='pending'");
                    $upd2->bind_param("ss", $dbStatus, $checkoutRequestID);
                    $upd2->execute();

                    $upd3 = $conn->prepare("UPDATE wallet_recharges SET status=? WHERE checkout_request_id=? AND status='pending'");
                    $upd3->bind_param("ss", $dbStatus, $checkoutRequestID);
                    $upd3->execute();

                    return [
                        'found'       => true,
                        'status'      => $dbStatus,
                        'reason'      => $cancelReason ?? $dbStatus,
                        'pf_status'   => $pfStatus,
                        'result_desc' => $d['result_desc'] ?? '',
                        'amount'      => floatval($d['amount'] ?? 0),
                    ];
                }
            }
        }
    }

    // ── 2. Fall back to DB (webhook may have already updated it) ─────────────
    $stmt = $conn->prepare("SELECT * FROM transactions WHERE reference=? ORDER BY created_at DESC LIMIT 1");
    $stmt->bind_param("s", $checkoutRequestID);
    $stmt->execute();
    $tx = $stmt->get_result()->fetch_assoc();

    if ($tx) {
        $meta   = json_decode($tx['meta_json'] ?? '{}', true);
        $reason = $meta['reason'] ?? $tx['status'];
        return [
            'found'       => true,
            'status'      => $tx['status'],
            'reason'      => $reason,
            'amount'      => $tx['amount'],
            'created_at'  => $tx['created_at'],
        ];
    }

    return ['found' => false, 'status' => 'unknown', 'reason' => ''];
}