<?php
declare(strict_types=1);

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

mocker_admin_require_permission('promo-codes');

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

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

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

if ($method === 'GET') {
    try {
        $st = $pdo->query(
            'SELECT id, code, coins, max_uses, uses_count, is_active, created_at, expires_at
             FROM promo_codes ORDER BY id DESC'
        );
        $rows = $st ? $st->fetchAll(PDO::FETCH_ASSOC) : [];
    } catch (Throwable $e) {
        http_response_code(503);
        echo json_encode(['ok' => false, 'error' => 'db'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    $out = [];
    foreach ($rows as $r) {
        $out[] = [
            'id' => (int) $r['id'],
            'code' => (string) $r['code'],
            'coins' => (int) $r['coins'],
            'maxUses' => $r['max_uses'] === null ? null : (int) $r['max_uses'],
            'usesCount' => (int) $r['uses_count'],
            'isActive' => (int) $r['is_active'] === 1,
            'createdAt' => (int) $r['created_at'],
            'expiresAt' => $r['expires_at'] === null ? null : (int) $r['expires_at'],
        ];
    }
    echo json_encode(['ok' => true, 'codes' => $out], JSON_UNESCAPED_UNICODE);
    exit;
}

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

mocker_require_csrf_post();

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

if ($action === 'create') {
    $codeRaw = (string) ($input['code'] ?? '');
    $code = mocker_promo_normalize_code($codeRaw);
    $coins = (int) ($input['coins'] ?? 0);
    $maxUses = $input['maxUses'] ?? null;
    $expiresAt = $input['expiresAt'] ?? null;

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

    $maxUsesSql = null;
    if ($maxUses !== null && $maxUses !== '') {
        $mu = (int) $maxUses;
        if ($mu < 1) {
            http_response_code(400);
            echo json_encode(['ok' => false, 'error' => 'max_uses'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        $maxUsesSql = $mu;
    }

    $expSql = null;
    if ($expiresAt !== null && $expiresAt !== '') {
        $expSql = (int) $expiresAt;
        if ($expSql <= 0) {
            http_response_code(400);
            echo json_encode(['ok' => false, 'error' => 'expires'], JSON_UNESCAPED_UNICODE);
            exit;
        }
    }

    $now = time();
    try {
        $ins = $pdo->prepare(
            'INSERT INTO promo_codes (code, coins, max_uses, uses_count, is_active, created_at, expires_at)
             VALUES (:c, :coins, :maxu, 0, 1, :t, :exp)'
        );
        $ins->execute([
            ':c' => $code,
            ':coins' => $coins,
            ':maxu' => $maxUsesSql,
            ':t' => $now,
            ':exp' => $expSql,
        ]);
    } catch (PDOException $e) {
        if ($e->getCode() === '23000' || strpos($e->getMessage(), 'UNIQUE') !== false) {
            http_response_code(409);
            echo json_encode(['ok' => false, 'error' => 'duplicate'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        throw $e;
    }

    $id = (int) $pdo->lastInsertId();
    echo json_encode(
        [
            'ok' => true,
            'code' => [
                'id' => $id,
                'code' => $code,
                'coins' => $coins,
                'maxUses' => $maxUsesSql,
                'usesCount' => 0,
                'isActive' => true,
                'createdAt' => $now,
                'expiresAt' => $expSql,
            ],
        ],
        JSON_UNESCAPED_UNICODE
    );
    exit;
}

if ($action === 'update') {
    $id = (int) ($input['id'] ?? 0);
    if ($id <= 0) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'id'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $st = $pdo->prepare('SELECT id, uses_count FROM promo_codes WHERE id = :id LIMIT 1');
    $st->execute([':id' => $id]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $sets = [];
    $params = [':id' => $id];

    if (array_key_exists('coins', $input)) {
        $coins = (int) $input['coins'];
        if ($coins < 1 || $coins > 10000000) {
            http_response_code(400);
            echo json_encode(['ok' => false, 'error' => 'coins'], JSON_UNESCAPED_UNICODE);
            exit;
        }
        $sets[] = 'coins = :coins';
        $params[':coins'] = $coins;
    }

    if (array_key_exists('maxUses', $input)) {
        $maxUses = $input['maxUses'];
        if ($maxUses === null || $maxUses === '') {
            $sets[] = 'max_uses = NULL';
        } else {
            $mu = (int) $maxUses;
            if ($mu < (int) $row['uses_count']) {
                http_response_code(400);
                echo json_encode(['ok' => false, 'error' => 'max_uses_below_uses'], JSON_UNESCAPED_UNICODE);
                exit;
            }
            if ($mu < 1) {
                http_response_code(400);
                echo json_encode(['ok' => false, 'error' => 'max_uses'], JSON_UNESCAPED_UNICODE);
                exit;
            }
            $sets[] = 'max_uses = :maxu';
            $params[':maxu'] = $mu;
        }
    }

    if (array_key_exists('isActive', $input)) {
        $sets[] = 'is_active = :ia';
        $params[':ia'] = !empty($input['isActive']) ? 1 : 0;
    }

    if (array_key_exists('expiresAt', $input)) {
        $exp = $input['expiresAt'];
        if ($exp === null || $exp === '') {
            $sets[] = 'expires_at = NULL';
        } else {
            $expI = (int) $exp;
            if ($expI <= 0) {
                http_response_code(400);
                echo json_encode(['ok' => false, 'error' => 'expires'], JSON_UNESCAPED_UNICODE);
                exit;
            }
            $sets[] = 'expires_at = :exp';
            $params[':exp'] = $expI;
        }
    }

    if ($sets === []) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'empty'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $sql = 'UPDATE promo_codes SET ' . implode(', ', $sets) . ' WHERE id = :id';
    $up = $pdo->prepare($sql);
    $up->execute($params);

    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'purge_all') {
    $pdo->exec('DELETE FROM promo_codes');
    echo json_encode(['ok' => true, 'deleted' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

if ($action === 'delete') {
    $id = (int) ($input['id'] ?? 0);
    if ($id <= 0) {
        http_response_code(400);
        echo json_encode(['ok' => false, 'error' => 'id'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $st = $pdo->prepare('SELECT uses_count FROM promo_codes WHERE id = :id LIMIT 1');
    $st->execute([':id' => $id]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'error' => 'not_found'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    if ((int) $row['uses_count'] > 0) {
        $pdo->prepare('DELETE FROM promo_redemptions WHERE promo_code_id = :id')->execute([':id' => $id]);
    }

    $del = $pdo->prepare('DELETE FROM promo_codes WHERE id = :id');
    $del->execute([':id' => $id]);
    echo json_encode(['ok' => true], JSON_UNESCAPED_UNICODE);
    exit;
}

http_response_code(400);
echo json_encode(['ok' => false, 'error' => 'action'], JSON_UNESCAPED_UNICODE);
