<?php
declare(strict_types=1);

require_once __DIR__ . '/bootstrap.php';
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/promo_lib.php';

header('Content-Type: application/json; charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['ok' => false, 'error' => 'method'], JSON_UNESCAPED_UNICODE);
    exit;
}

mocker_require_csrf_post();

$uid = isset($_SESSION['mocker_user_id']) ? (int) $_SESSION['mocker_user_id'] : 0;
if ($uid <= 0) {
    http_response_code(401);
    echo json_encode(['ok' => false, 'error' => 'auth'], JSON_UNESCAPED_UNICODE);
    exit;
}

$input = json_decode((string) file_get_contents('php://input'), true) ?: [];
$code = mocker_promo_normalize_code((string) ($input['code'] ?? ''));

if (strlen($code) < 4) {
    http_response_code(400);
    echo json_encode(['ok' => false, 'error' => 'code'], JSON_UNESCAPED_UNICODE);
    exit;
}

try {
    $pdo = mocker_db();
} catch (Throwable $e) {
    http_response_code(503);
    echo json_encode(['ok' => false, 'error' => 'db'], JSON_UNESCAPED_UNICODE);
    exit;
}

$pdo->beginTransaction();
try {
    $st = $pdo->prepare(
        'SELECT id, coins, max_uses, uses_count, is_active, expires_at
         FROM promo_codes WHERE code = :c LIMIT 1'
    );
    $st->execute([':c' => $code]);
    $promo = $st->fetch(PDO::FETCH_ASSOC);

    if (!$promo) {
        $pdo->rollBack();
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $pid = (int) $promo['id'];
    $coins = (int) $promo['coins'];
    $maxUses = $promo['max_uses'] !== null ? (int) $promo['max_uses'] : null;
    $uses = (int) $promo['uses_count'];
    $active = (int) $promo['is_active'] === 1;
    $exp = $promo['expires_at'] !== null ? (int) $promo['expires_at'] : null;

    if (!$active) {
        $pdo->rollBack();
        echo json_encode(['ok' => false, 'error' => 'inactive'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ($exp !== null && time() > $exp) {
        $pdo->rollBack();
        echo json_encode(['ok' => false, 'error' => 'expired'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ($maxUses !== null && $uses >= $maxUses) {
        $pdo->rollBack();
        echo json_encode(['ok' => false, 'error' => 'exhausted'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $chk = $pdo->prepare('SELECT 1 FROM promo_redemptions WHERE user_id = :u AND promo_code_id = :p LIMIT 1');
    $chk->execute([':u' => $uid, ':p' => $pid]);
    if ($chk->fetch()) {
        $pdo->rollBack();
        echo json_encode(['ok' => false, 'error' => 'already_used'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $now = time();
    $insR = $pdo->prepare(
        'INSERT INTO promo_redemptions (promo_code_id, user_id, coins_awarded, redeemed_at)
         VALUES (:p, :u, :c, :t)'
    );
    $insR->execute([':p' => $pid, ':u' => $uid, ':c' => $coins, ':t' => $now]);

    $upP = $pdo->prepare('UPDATE promo_codes SET uses_count = uses_count + 1 WHERE id = :id');
    $upP->execute([':id' => $pid]);

    $upU = $pdo->prepare('UPDATE users SET coins = coins + :a WHERE id = :id');
    $upU->execute([':a' => $coins, ':id' => $uid]);

    $bal = $pdo->prepare('SELECT coins FROM users WHERE id = :id LIMIT 1');
    $bal->execute([':id' => $uid]);
    $brow = $bal->fetch(PDO::FETCH_ASSOC);
    $newCoins = $brow ? (int) $brow['coins'] : 0;

    $pdo->commit();

    echo json_encode(
        [
            'ok' => true,
            'coinsAdded' => $coins,
            'coins' => $newCoins,
        ],
        JSON_UNESCAPED_UNICODE
    );
} catch (Throwable $e) {
    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }
    http_response_code(500);
    echo json_encode(['ok' => false, 'error' => 'server'], JSON_UNESCAPED_UNICODE);
}
