<?php
/**
 * mpesa/callback.php — Unified PesaFlux / LipaLink Webhook Handler
 *
 * PesaFlux POSTs a flat JSON object after every payment result:
 * {
 *   "event":            "payment.success",
 *   "transaction_id":   "PFX20240101ABCDEF",
 *   "mpesa_receipt":    "QHY67XXXXX",
 *   "msisdn":           "254712345678",
 *   "amount":           100.00,
 *   "reference":        "ORDER-001",
 *   "business_id":      3,
 *   "status":           "Success",
 *   "transaction_date": "2024-01-01 12:00:00"
 * }
 *
 * Handles ALL payment types:
 *   1. wallet_recharge   → wallet_recharges table  → credit main_wallet
 *   2. product_purchase  → product_purchases table → download token + commissions
 *   3. activation        → transactions table      → activate user account
 */

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

// ── Immediate HTTP 200 — keep PesaFlux happy (no retries) ────────────────────
header('Content-Type: application/json');
http_response_code(200);
echo json_encode(['ResultCode' => 0, 'ResultDesc' => 'Confirmation received successfully']);

if (session_status() !== PHP_SESSION_NONE) session_write_close();
if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();

$log_file = __DIR__ . '/callback_log.txt';
$input    = file_get_contents('php://input');

file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ========== NEW PESAFLUX WEBHOOK ==========\n", FILE_APPEND);
file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] RAW: $input\n", FILE_APPEND);

$data = json_decode($input, true);
if (!$data) {
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ERROR: Invalid JSON\n", FILE_APPEND);
    exit();
}

// ── Parse PesaFlux flat webhook ───────────────────────────────────────────────
$event          = $data['event']          ?? '';
$transaction_id = trim($data['transaction_id'] ?? '');   // PFX... — this IS the reference
$mpesa_receipt  = $data['mpesa_receipt']  ?? null;
$status         = strtolower($data['status'] ?? '');
$paid_amount    = floatval($data['amount'] ?? 0);

// Also support legacy STK / SmartPanel formats so old pending rows still resolve
$transaction_successful = false;
$reference              = null;

if (!empty($transaction_id)) {
    // ── PesaFlux flat format ──────────────────────────────────────────────────
    $reference = $transaction_id;

    // PesaFlux success: event=payment.success AND status=Success
    // PesaFlux failure/cancel: event=payment.failed OR status != Success
    // M-PESA cancel code 1032 = user cancelled, 1037 = timeout, 17 = wrong PIN
    $pfResultCode = intval($data['result_code'] ?? $data['ResultCode'] ?? -1);
    $isCancelled  = (
        $event === 'payment.failed'   ||
        $event === 'payment.cancelled' ||
        (in_array($pfResultCode, [1032, 1037, 17, 1001])) ||
        ($status !== '' && $status !== 'success' && $event !== 'payment.success')
    );
    $transaction_successful = ($event === 'payment.success' && $status === 'success');

} elseif (isset($data['Body']['stkCallback'])) {
    // ── Legacy STK Push format ────────────────────────────────────────────────
    $callback  = $data['Body']['stkCallback'];
    $reference = $callback['CheckoutRequestID'] ?? null;
    if (($callback['ResultCode'] ?? null) == 0) {
        $transaction_successful = true;
        foreach (($callback['CallbackMetadata']['Item'] ?? []) as $item) {
            if ($item['Name'] === 'Amount')             $paid_amount    = floatval($item['Value']);
            if ($item['Name'] === 'MpesaReceiptNumber') $mpesa_receipt  = $item['Value'];
        }
    }

} elseif (isset($data['ResponseCode']) || isset($data['ResultCode'])) {
    // ── Legacy SmartPanel / ResultCode format ─────────────────────────────────
    $rc        = $data['ResponseCode'] ?? $data['ResultCode'] ?? null;
    $reference = $data['CheckoutRequestID'] ?? $data['Reference'] ?? null;
    if ($rc == 0) {
        $transaction_successful = true;
        $paid_amount   = floatval($data['TransactionAmount'] ?? $data['Amount'] ?? 0);
        $mpesa_receipt = $data['TransactionReceipt'] ?? $data['MpesaReceiptNumber'] ?? null;
    }

} else {
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ERROR: Unrecognized webhook format\n", FILE_APPEND);
    exit();
}

if (!$reference) {
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ERROR: No reference/transaction_id\n", FILE_APPEND);
    exit();
}

$reference = trim($reference);
file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] Ref: $reference | Event: $event | Status: $status | OK: " . ($transaction_successful ? 'YES' : 'NO') . "\n", FILE_APPEND);

// ── FAILED / CANCELLED PAYMENT ────────────────────────────────────────────────
if (!$transaction_successful) {
    // Determine exact failure reason for DB meta
    $failReason = 'failed';
    if (isset($isCancelled) && $isCancelled) {
        if ($pfResultCode === 1032) $failReason = 'cancelled_by_user';
        elseif ($pfResultCode === 1037) $failReason = 'timeout';
        elseif ($pfResultCode === 17)   $failReason = 'wrong_pin';
        else                            $failReason = 'cancelled';
    }

    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] PAYMENT NOT SUCCESSFUL — reason=$failReason event=$event status=$status code=$pfResultCode\n", FILE_APPEND);

    try {
        $pdo  = getPDO();
        $meta = json_encode([
            'failed_at'   => date('Y-m-d H:i:s'),
            'event'       => $event,
            'status'      => $status,
            'result_code' => $pfResultCode,
            'reason'      => $failReason,
        ]);

        // Always write 'failed' — safe for ENUMs that don't have 'cancelled' yet.
        // The $failReason is stored in meta_json so you can still see WHY it failed.
        // After running the ALTER TABLE migration, you can change this to $dbStatus.
        $dbStatus = 'failed';

        $pdo->prepare("UPDATE transactions SET status='failed', meta_json=?
            WHERE reference=? AND status='pending'")
            ->execute([$meta, $reference]);

        $pdo->prepare("UPDATE product_purchases SET status='failed'
            WHERE checkout_request_id=? AND status='pending'")
            ->execute([$reference]);

        $pdo->prepare("UPDATE wallet_recharges SET status='failed'
            WHERE checkout_request_id=? AND status='pending'")
            ->execute([$reference]);

        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ Marked as 'failed' (reason=$failReason) for ref=$reference\n", FILE_APPEND);

    } catch (Exception $e) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] Could not update failed records: " . $e->getMessage() . "\n", FILE_APPEND);
    }
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ========== END WEBHOOK ==========\n\n", FILE_APPEND);
    exit();
}

$pdo = getPDO();

// ── STEP 1: Check wallet_recharges table ──────────────────────────────────────
$rStmt = $pdo->prepare("SELECT * FROM wallet_recharges WHERE checkout_request_id=? AND status='pending' LIMIT 1");
$rStmt->execute([$reference]);
$recharge = $rStmt->fetch();

if ($recharge) {
    handle_wallet_recharge($pdo, $recharge, $paid_amount, $mpesa_receipt, $log_file);
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ========== END WEBHOOK ==========\n\n", FILE_APPEND);
    exit();
}

// ── STEP 2: Find pending transaction ─────────────────────────────────────────
$tx          = null;
$max_retries = 3;

for ($attempt = 1; $attempt <= $max_retries; $attempt++) {
    $s = $pdo->prepare("SELECT * FROM transactions WHERE reference=? AND status='pending' LIMIT 1");
    $s->execute([$reference]);
    $tx = $s->fetch();
    if ($tx) break;
    if ($attempt < $max_retries) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] RETRY $attempt/$max_retries for ref=$reference\n", FILE_APPEND);
        sleep(2);
    }
}

if (!$tx) {
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] NOT FOUND: No pending transaction for $reference\n", FILE_APPEND);
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ========== END WEBHOOK ==========\n\n", FILE_APPEND);
    exit();
}

// ── STEP 3: Route by transaction type ────────────────────────────────────────
$txType    = $tx['type'] ?? '';
$metaData  = json_decode($tx['meta_json'] ?? '{}', true);
$metaType  = $metaData['type'] ?? '';

$isProductPurchase = (
    $txType  === 'product_purchase' ||
    $metaType === 'product_purchase' ||
    strpos($reference, 'PROD_') === 0
);

file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] Routing — DB Type: '$txType' | Meta Type: '$metaType' | Ref: '$reference' | IsProduct: " . ($isProductPurchase ? 'YES' : 'NO') . "\n", FILE_APPEND);

if ($isProductPurchase) {
    handle_product_purchase($pdo, $tx, $paid_amount, $mpesa_receipt, $reference, null, $log_file);
} else {
    handle_activation($pdo, $tx, $paid_amount, $mpesa_receipt, $reference, null, $log_file);
}

file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ========== END WEBHOOK ==========\n\n", FILE_APPEND);
exit();


// ════════════════════════════════════════════════════════════════════════════
// HANDLER 0: WALLET RECHARGE
// ════════════════════════════════════════════════════════════════════════════
function handle_wallet_recharge($pdo, $recharge, $paid_amount, $mpesa_receipt, $log_file) {
    $userId = intval($recharge['user_id']);
    $rId    = intval($recharge['id']);
    $amount = $paid_amount > 0 ? $paid_amount : floatval($recharge['amount']);

    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] RECHARGE: user=$userId amount=$amount\n", FILE_APPEND);

    try {
        $pdo->beginTransaction();

        $upd = $pdo->prepare("UPDATE wallet_recharges SET status='completed', amount=?, mpesa_receipt=?, completed_at=NOW() WHERE id=? AND status='pending'");
        $upd->execute([$amount, $mpesa_receipt, $rId]);

        if ($upd->rowCount() < 1) {
            $pdo->rollBack();
            file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] RECHARGE: Already processed id=$rId\n", FILE_APPEND);
            return;
        }

        // Ensure wallet row exists
        $wChk = $pdo->prepare("SELECT id FROM wallets WHERE user_id=? LIMIT 1");
        $wChk->execute([$userId]);
        if (!$wChk->fetch()) {
            $pdo->prepare("INSERT INTO wallets
                (user_id, balance, total_earned, main_wallet, referral_wallet, bonus_wallet,
                 video_wallet, trivia_wallet, survey_wallet, ads_wallet, spin_wallet,
                 blog_wallet, meme_wallet, chat_wallet, transcription_wallet, created_at, updated_at)
                VALUES (?, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NOW(), NOW())")
                ->execute([$userId]);
        }

        $cr = $pdo->prepare("UPDATE wallets
            SET main_wallet  = COALESCE(main_wallet,  0) + ?,
                balance      = COALESCE(balance,      0) + ?,
                total_earned = COALESCE(total_earned, 0) + ?,
                updated_at   = NOW()
            WHERE user_id = ?");
        $cr->execute([$amount, $amount, $amount, $userId]);

        if ($cr->rowCount() < 1) {
            throw new Exception("Wallet UPDATE hit 0 rows for user=$userId");
        }

        $pdo->commit();
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ RECHARGE committed: +$amount to main_wallet user=$userId receipt=$mpesa_receipt\n", FILE_APPEND);

    } catch (Exception $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ❌ RECHARGE error: " . $e->getMessage() . "\n", FILE_APPEND);
    }
}


// ════════════════════════════════════════════════════════════════════════════
// HANDLER A: DIGITAL PRODUCT PURCHASE
// ════════════════════════════════════════════════════════════════════════════
function handle_product_purchase($pdo, $tx, $transaction_amount, $mpesa_receipt, $reference, $transaction_reference, $log_file) {
    $buyerId    = intval($tx['user_id']);
    $meta       = json_decode($tx['meta_json'] ?? '{}', true);
    $purchaseId = intval($meta['purchase_id'] ?? 0);
    $productId  = intval($meta['product_id']  ?? 0);

    $purchaseRow = null;
    if ($purchaseId) {
        $s = $pdo->prepare("SELECT * FROM product_purchases WHERE id=? AND status='pending' LIMIT 1");
        $s->execute([$purchaseId]);
        $purchaseRow = $s->fetch();
    }
    if (!$purchaseRow) {
        $s = $pdo->prepare("SELECT * FROM product_purchases WHERE checkout_request_id=? AND status='pending' LIMIT 1");
        $s->execute([$reference]);
        $purchaseRow = $s->fetch();
    }
    if (!$purchaseRow) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] PRODUCT: Purchase record not found\n", FILE_APPEND);
        return;
    }

    $purchaseId = intval($purchaseRow['id']);
    $productId  = intval($purchaseRow['product_id']);
    $buyerId    = intval($purchaseRow['user_id']);

    $s = $pdo->prepare("SELECT * FROM digital_products WHERE id=? LIMIT 1");
    $s->execute([$productId]);
    $product = $s->fetch();
    if (!$product) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] PRODUCT: Product #$productId not found\n", FILE_APPEND);
        return;
    }

    $dlToken = null;
    try {
        $pdo->beginTransaction();
        $dlToken = bin2hex(random_bytes(32));

        $pdo->prepare("UPDATE product_purchases SET
                status='completed', mpesa_receipt=?, download_token=?,
                checkout_request_id=?, amount_paid=?, purchased_at=NOW()
            WHERE id=? AND status='pending'")
            ->execute([$mpesa_receipt, $dlToken, $reference, $transaction_amount, $purchaseId]);

        $pdo->prepare("UPDATE transactions SET status='completed', amount=?, meta_json=?, reference=?
            WHERE reference=? AND status='pending'")
            ->execute([
                $transaction_amount,
                json_encode(['mpesa_receipt' => $mpesa_receipt, 'processed_at' => date('Y-m-d H:i:s'), 'type' => 'product_purchase']),
                $reference,
                $reference,
            ]);

        $pdo->prepare("UPDATE digital_products SET sales_count=sales_count+1 WHERE id=?")->execute([$productId]);

        $pdo->commit();
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ PRODUCT purchase #$purchaseId complete. Token: $dlToken\n", FILE_APPEND);
    } catch (Exception $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ❌ PRODUCT DB error: " . $e->getMessage() . "\n", FILE_APPEND);
        return;
    }

    // Multi-level product commission distribution
    $commissionedUsers = [];
    try {
        $commPct  = floatval($product['commission_percent']);
        $commPool = ($transaction_amount * $commPct) / 100;

        if ($commPool > 0.01) {
            $s = $pdo->prepare("SELECT username, referred_by, country FROM users WHERE id=? LIMIT 1");
            $s->execute([$buyerId]);
            $buyerRow      = $s->fetch();
            $buyerUsername = $buyerRow['username'] ?? 'Someone';
            $buyerCountry  = $buyerRow['country']  ?? '';

            $s = $pdo->prepare("SELECT s.l1_pct, s.l2_pct, s.l3_pct
                FROM product_commission_splits s
                JOIN countries c ON c.id = s.country_id
                WHERE LOWER(TRIM(c.name)) = LOWER(TRIM(?)) LIMIT 1");
            $s->execute([$buyerCountry]);
            $splitRow = $s->fetch();

            $splits = [
                1 => floatval($splitRow['l1_pct'] ?? 60),
                2 => floatval($splitRow['l2_pct'] ?? 30),
                3 => floatval($splitRow['l3_pct'] ?? 10),
            ];

            file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] PRODUCT COMM: pool=" . number_format($commPool, 2) . " ($commPct%) splits=L1:{$splits[1]}%/L2:{$splits[2]}%/L3:{$splits[3]}%\n", FILE_APPEND);

            $currentReferrerId = !empty($buyerRow['referred_by']) ? intval($buyerRow['referred_by']) : 0;
            $commLevel = 1; $chainDepth = 0; $totalDistributed = 0;

            while ($currentReferrerId && $chainDepth < 10) {
                $chainDepth++;
                if ($commLevel > 3) break;

                $s = $pdo->prepare("SELECT u.id, u.username, u.referred_by, u.country, c.id AS country_id, c.currency_symbol
                    FROM users u LEFT JOIN countries c ON LOWER(TRIM(u.country)) = LOWER(TRIM(c.name))
                    WHERE u.id = ?");
                $s->execute([$currentReferrerId]);
                $referrer = $s->fetch();

                if (!$referrer) break;
                if (empty($referrer['country_id'])) {
                    $currentReferrerId = !empty($referrer['referred_by']) ? intval($referrer['referred_by']) : 0;
                    continue;
                }

                $levelSplitPct = $splits[$commLevel] ?? 0;
                if ($levelSplitPct <= 0) break;

                $levelAmount = ($commPool * $levelSplitPct) / 100;
                if ($levelAmount < 0.01) {
                    $commLevel++;
                    $currentReferrerId = !empty($referrer['referred_by']) ? intval($referrer['referred_by']) : 0;
                    continue;
                }

                $dup = $pdo->prepare("SELECT id FROM product_commissions WHERE purchase_id=? AND recipient_id=? AND level_number=? LIMIT 1");
                $dup->execute([$purchaseId, $currentReferrerId, $commLevel]);
                if ($dup->fetch()) {
                    $commLevel++;
                    $currentReferrerId = !empty($referrer['referred_by']) ? intval($referrer['referred_by']) : 0;
                    continue;
                }

                ensureWalletExistsPDO($pdo, $currentReferrerId);

                $pdo->prepare("UPDATE wallets SET
                    main_wallet=COALESCE(main_wallet,0)+?,
                    balance=COALESCE(balance,0)+?,
                    total_earned=COALESCE(total_earned,0)+?,
                    updated_at=NOW()
                    WHERE user_id=?")->execute([$levelAmount, $levelAmount, $levelAmount, $currentReferrerId]);

                $desc = "L{$commLevel} product commission ({$levelSplitPct}% of pool) — \"{$product['title']}\" (buyer: {$buyerUsername})";
                $ref2 = "PCOMM_L{$commLevel}_{$purchaseId}_" . time() . "_" . mt_rand(100, 999);

                $pdo->prepare("INSERT INTO transactions (user_id, wallet_type, type, amount, description, reference, status, created_at)
                    VALUES (?, 'main_wallet', 'product_commission', ?, ?, ?, 'completed', NOW())")
                    ->execute([$currentReferrerId, $levelAmount, $desc, $ref2]);

                $pdo->prepare("INSERT INTO product_commissions (purchase_id, product_id, buyer_id, recipient_id, level_number, commission_amount, status)
                    VALUES (?, ?, ?, ?, ?, ?, 'credited')")
                    ->execute([$purchaseId, $productId, $buyerId, $currentReferrerId, $commLevel, $levelAmount]);

                $totalDistributed += $levelAmount;
                $commissionedUsers[] = ['id' => $currentReferrerId, 'username' => $referrer['username'], 'amount' => $levelAmount, 'level' => $commLevel];

                file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ L{$commLevel}: " . ($referrer['currency_symbol'] ?? 'KSh') . number_format($levelAmount, 2) . " → {$referrer['username']} (#{$currentReferrerId})\n", FILE_APPEND);

                $commLevel++;
                $currentReferrerId = !empty($referrer['referred_by']) ? intval($referrer['referred_by']) : 0;
            }

            if ($totalDistributed > 0) {
                $pdo->prepare("UPDATE product_purchases SET commission_paid=1 WHERE id=?")->execute([$purchaseId]);
            }

            file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ PRODUCT commissions done: total=$totalDistributed levels=" . count($commissionedUsers) . "\n", FILE_APPEND);
        }
    } catch (Exception $e) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ⚠ PRODUCT commission error (non-critical): " . $e->getMessage() . "\n", FILE_APPEND);
    }

    // Notifications
    try {
        require_once __DIR__ . '/../includes/email.php';
        sendProductPurchaseEmail($buyerId, $product['title'], $dlToken, $transaction_amount);
        foreach ($commissionedUsers as $cu) {
            sendProductCommissionEmail($cu['id'], $buyerUsername ?? 'Someone', $product['title'], $cu['amount'], $cu['level']);
        }
    } catch (Exception $e) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ⚠ Product notification error (non-critical): " . $e->getMessage() . "\n", FILE_APPEND);
    }

    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ PRODUCT handler complete\n", FILE_APPEND);
}


// ════════════════════════════════════════════════════════════════════════════
// HANDLER B: ACCOUNT ACTIVATION
// ════════════════════════════════════════════════════════════════════════════
function handle_activation($pdo, $tx, $transaction_amount, $mpesa_receipt, $reference, $transaction_reference, $log_file) {
    $payer_id           = intval($tx['user_id']);
    $activating_user_id = $payer_id;

    if (!empty($tx['meta_json'])) {
        $meta = json_decode($tx['meta_json'], true);
        if (!empty($meta['activating_user_id'])) {
            $activating_user_id = intval($meta['activating_user_id']);
        }
    }
    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ACTIVATION: Payer #$payer_id → Activating #$activating_user_id\n", FILE_APPEND);

    try {
        $pdo->beginTransaction();

        $newMeta = json_encode([
            'mpesa_receipt'      => $mpesa_receipt,
            'transaction_amount' => $transaction_amount,
            'processed_at'       => date('Y-m-d H:i:s'),
            'payer_id'           => $payer_id,
            'activating_user_id' => $activating_user_id,
        ]);

        $s = $pdo->prepare("UPDATE transactions SET status='completed', amount=?, meta_json=?, reference=?
            WHERE reference=? AND status='pending'");
        $s->execute([$transaction_amount, $newMeta, $reference, $reference]);

        if ($s->rowCount() == 0) {
            throw new Exception("Transaction already processed (race condition handled)");
        }

        $pdo->prepare("UPDATE users SET status='active', activation_date=NOW() WHERE id=? AND status='inactive'")
            ->execute([$activating_user_id]);

        $pdo->commit();
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ ACTIVATION committed. User #$activating_user_id active. Receipt: $mpesa_receipt\n", FILE_APPEND);

    } catch (Exception $e) {
        if ($pdo->inTransaction()) $pdo->rollBack();
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ❌ ACTIVATION DB error: " . $e->getMessage() . "\n", FILE_APPEND);
        return;
    }

    // Distribute referral bonuses
    try {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] 💰 Distributing activation bonuses for user #$activating_user_id\n", FILE_APPEND);
        distribute_payment_referral_bonus($pdo, $activating_user_id, $transaction_amount, 'client_activation');
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ Activation bonuses distributed\n", FILE_APPEND);
    } catch (Exception $e) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ⚠ Activation bonus error (non-critical): " . $e->getMessage() . "\n", FILE_APPEND);
    }

    // Notifications
    try {
        require_once __DIR__ . '/../includes/email.php';
        sendActivationSuccessEmail($activating_user_id);
    } catch (Exception $e) {
        file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ⚠ Activation notification error (non-critical): " . $e->getMessage() . "\n", FILE_APPEND);
    }

    file_put_contents($log_file, "[" . date('Y-m-d H:i:s') . "] ✅ ACTIVATION handler complete\n", FILE_APPEND);
}