<?php
/**
 * POST /api/wallet/topup.php
 * WAVE E + FIX A — Full Kernel Replace + DB-level Idempotency
 *
 * IDEMPOTENCY: wallet_transactions.payment_ref has UNIQUE(user_id, payment_ref, ref_type)
 * Duplicate charge = MySQL Duplicate entry error → caught → 409 response
 * No LIKE queries. No race conditions.
 */
require_once __DIR__ . '/../../config.php';
require_once __DIR__ . '/../../engine/Kernel.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    Kernel::fail('method_not_allowed', '', 405);
}

$ctx = Kernel::handle(['auth' => true, 'rate' => 'api']);
$u   = $ctx['user'];
$uid = (int)$u['id'];

$b      = json_decode(file_get_contents('php://input'), true) ?? [];
$amount = max(100, min(1000000, (int)($b['amount_sdg'] ?? 0)));
$ref    = mb_substr(trim($b['payment_ref'] ?? ''), 0, 100);

// Normalize ref: lowercase + trim whitespace + remove non-standard chars
// Prevents bypass via "REF123 " or "ref123" or "REF 123"
$ref = mb_strtolower(preg_replace('/\s+/', ' ', trim($ref)));
$ref = preg_replace('/[^\p{L}\p{N}\-\/\.\s]/u', '', $ref);

if (!$ref || mb_strlen($ref) < 3) {
    Kernel::fail('payment_ref_required', 'مرجع الدفع مطلوب (3 أحرف على الأقل)', 400);
}
if ($amount < 100) {
    Kernel::fail('invalid_amount', 'الحد الأدنى للشحن 100 SDG', 400);
}

try {
    db()->beginTransaction();

    $w = db()->prepare("SELECT id, balance_sdg AS balance FROM wallet WHERE user_id=? FOR UPDATE");
    $w->execute([$uid]);
    $wallet = $w->fetch();

    if (!$wallet) {
        db()->prepare("INSERT INTO wallet (user_id,balance_sdg) VALUES (?,0)")->execute([$uid]);
        $wallet = ['id' => (int)db()->lastInsertId(), 'balance' => 0];
    }

    $newBal = (float)$wallet['balance'] + $amount;

    db()->prepare("UPDATE wallet SET balance_sdg=? WHERE id=?")->execute([$newBal, $wallet['id']]);

    // DB-level idempotency: UNIQUE(user_id, payment_ref, ref_type)
    // Duplicate entry = same ref used twice → MySQL throws → we catch below
    db()->prepare(
        "INSERT INTO wallet_transactions
         (wallet_id, user_id, type, amount_sdg, balance_after, ref_type, payment_ref, description)
         VALUES (?, ?, 'credit', ?, ?, 'topup', ?, ?)"
    )->execute([
        $wallet['id'], $uid, $amount, $newBal,
        $ref,  // stored in payment_ref for UNIQUE enforcement
        "شحن محفظة: {$ref}",
    ]);

    db()->commit();

    Logger::info('wallet_topup', [
        'user_id'     => $uid,
        'amount_sdg'  => $amount,
        'new_balance' => $newBal,
        'payment_ref' => $ref,
    ]);

    Kernel::respond(['ok' => true, 'new_balance' => $newBal, 'amount' => $amount]);

} catch (Throwable $e) {
    if (db()->inTransaction()) db()->rollBack();

    // DB constraint violation = duplicate payment_ref
    if (str_contains($e->getMessage(), 'Duplicate entry') ||
        str_contains($e->getMessage(), '1062')) {
        Logger::warn('topup_duplicate_ref', ['user_id' => $uid, 'ref' => $ref]);
        Kernel::fail(
            'duplicate_payment_ref',
            'تم شحن هذا الإيصال مسبقاً. لا يمكن استخدام نفس الإيصال مرتين.',
            409
        );
    }

    Logger::error('wallet_topup_failed', ['user_id' => $uid, 'error' => $e->getMessage()]);
    Kernel::fail('topup_failed', 'فشل الشحن — حاول مرة أخرى', 500);
}
