<?php
declare(strict_types=1);

/**
 * /admin/coins/adjust.php
 *
 * Окрема адмін-сторінка ручного коригування балансу VM Coins.
 *
 * Відповідає за:
 * - ручне поповнення або списання монет у конкретного користувача
 * - пошук користувача по ID / username / email
 * - live preview поточного балансу через JSON endpoint
 * - заборону списання нижче 0
 *
 * ВАЖЛИВО:
 * - зведення винесене в /admin/coins/
 * - налаштування винесені в /admin/coins/settings.php
 */

require_once __DIR__ . '/../../includes/start.php';
require_once __DIR__ . '/../_helpers.php';
require_once __DIR__ . '/../_sidebar.php';

$__vmCoinsLib = __DIR__ . '/../../functional/VMCoins/_lib.php';
if (is_file($__vmCoinsLib)) {
    require_once $__vmCoinsLib;
}
unset($__vmCoinsLib);

if (!headers_sent()) {
    header('X-Robots-Tag: noindex, nofollow, noarchive, nosnippet', true);
    header('Cache-Control: no-store, max-age=0', true);
    header('Pragma: no-cache', true);
}

require_login();

$pdo = isset($pdo) && $pdo instanceof PDO ? $pdo : db();
$me  = isset($me) && is_array($me) ? $me : current_user();

if (function_exists('require_role')) {
    require_role(['admin']);
} else {
        $role = (string)($me['role'] ?? '');
        if ($role !== 'admin') {
            http_response_code(403);
            exit('Forbidden');
        }
}

if (!function_exists('e')) {
    function e($v): string
    {
        return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8');
    }
}

if (!function_exists('csrf_token')) {
    function csrf_token(): string
    {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(16));
        }
        return (string)$_SESSION['csrf_token'];
    }
}

if (!function_exists('csrf_check')) {
    function csrf_check(?string $token): bool
    {
        $sess = (string)($_SESSION['csrf_token'] ?? '');
        $sent = (string)($token ?? '');
        return $sess !== '' && hash_equals($sess, $sent);
    }
}

if (!function_exists('is_post')) {
    function is_post(): bool
    {
        return strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET')) === 'POST';
    }
}

if (!function_exists('admin_coins_t')) {
    function admin_coins_t(string $uk, string $ru, string $en): string
    {
        $lang = function_exists('lang') ? (string)lang() : (string)($_SESSION['lang'] ?? 'uk');
        if (!in_array($lang, ['uk', 'ru', 'en'], true)) {
            $lang = 'uk';
        }

        return match ($lang) {
            'ru' => $ru,
            'en' => $en,
            default => $uk,
        };
    }
}

if (!function_exists('admin_coins_flash_set')) {
    function admin_coins_flash_set(string $type, string $message): void
    {
        $_SESSION['admin_vmcoins_flash'] = [
            'type' => $type,
            'message' => $message,
        ];
    }
}

if (!function_exists('admin_coins_flash_pull')) {
    function admin_coins_flash_pull(): ?array
    {
        $flash = $_SESSION['admin_vmcoins_flash'] ?? null;
        unset($_SESSION['admin_vmcoins_flash']);

        return is_array($flash) ? $flash : null;
    }
}

if (!function_exists('admin_coins_redirect_self')) {
    function admin_coins_redirect_self(string $anchor = ''): never
    {
        $to = '/admin/coins/adjust.php';
        if ($anchor !== '') {
            $to .= '#' . ltrim($anchor, '#');
        }
        header('Location: ' . $to);
        exit;
    }
}

if (!function_exists('admin_coins_emit_json')) {
    function admin_coins_emit_json(array $payload, int $status = 200): never
    {
        if (!headers_sent()) {
            http_response_code($status);
            header('Content-Type: application/json; charset=UTF-8', true);
            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', true);
            header('Pragma: no-cache', true);
        }

        echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }
}

if (!function_exists('admin_coins_db_has_table')) {
    function admin_coins_db_has_table(PDO $pdo, string $table): bool
    {
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $table)) {
            return false;
        }

        if (function_exists('db_has_table')) {
            try {
                return (bool)db_has_table($pdo, $table);
            } catch (Throwable $e) {
            }
        }

        try {
            $st = $pdo->prepare("
                SELECT 1
                FROM information_schema.tables
                WHERE table_schema = DATABASE()
                  AND table_name = ?
                LIMIT 1
            ");
            $st->execute([$table]);
            return (bool)$st->fetchColumn();
        } catch (Throwable $e) {
            return false;
        }
    }
}

if (!function_exists('admin_coins_db_has_column')) {
    function admin_coins_db_has_column(PDO $pdo, string $table, string $column): bool
    {
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $table) || !preg_match('/^[a-zA-Z0-9_]+$/', $column)) {
            return false;
        }

        if (function_exists('db_has_column')) {
            try {
                return (bool)db_has_column($pdo, $table, $column);
            } catch (Throwable $e) {
            }
        }

        try {
            $st = $pdo->prepare("
                SELECT 1
                FROM information_schema.columns
                WHERE table_schema = DATABASE()
                  AND table_name = ?
                  AND column_name = ?
                LIMIT 1
            ");
            $st->execute([$table, $column]);
            return (bool)$st->fetchColumn();
        } catch (Throwable $e) {
            return false;
        }
    }
}

if (!function_exists('admin_coins_num')) {
    function admin_coins_num($n): string
    {
        return number_format((float)$n, 0, '.', ' ');
    }
}

if (!function_exists('admin_coins_section_help')) {
    function admin_coins_section_help(string $section): string
    {
        return match ($section) {
            'manual_adjust' => admin_coins_t(
                'Ручне поповнення або списання монет у конкретного користувача через ID, нікнейм або email.',
                'Ручное пополнение или списание монет у конкретного пользователя через ID, никнейм или email.',
                'Manually add or subtract coins for a specific user by ID, username, or email.'
            ),
            default => '',
        };
    }
}

if (!function_exists('admin_coins_find_user')) {
    function admin_coins_find_user(PDO $pdo, string $query): ?array
    {
        $query = trim($query);
        if ($query === '') {
            return null;
        }

        $query = ltrim($query, '@');

        try {
            if (ctype_digit($query)) {
                $st = $pdo->prepare("
                    SELECT id, username, email, vm_coins_balance
                    FROM users
                    WHERE id = ?
                    LIMIT 1
                ");
                $st->execute([(int)$query]);
                $row = $st->fetch(PDO::FETCH_ASSOC);
                return $row ?: null;
            }

            $needle = function_exists('mb_strtolower') ? mb_strtolower($query, 'UTF-8') : strtolower($query);

            $st = $pdo->prepare("
                SELECT id, username, email, vm_coins_balance
                FROM users
                WHERE LOWER(username) = ?
                   OR LOWER(email) = ?
                ORDER BY
                    CASE WHEN LOWER(username) = ? THEN 0 ELSE 1 END,
                    CASE WHEN LOWER(email) = ? THEN 0 ELSE 1 END,
                    id ASC
                LIMIT 1
            ");
            $st->execute([$needle, $needle, $needle, $needle]);
            $row = $st->fetch(PDO::FETCH_ASSOC);

            return $row ?: null;
        } catch (Throwable $e) {
            return null;
        }
    }
}

if (!function_exists('admin_coins_user_lookup_payload')) {
    function admin_coins_user_lookup_payload(PDO $pdo, string $query): array
    {
        $query = trim($query);
        if ($query === '') {
            return [
                'ok' => true,
                'found' => false,
                'message' => admin_coins_t(
                    'Почни вводити ID, username або email.',
                    'Начни вводить ID, username или email.',
                    'Start typing ID, username, or email.'
                ),
            ];
        }

        $user = admin_coins_find_user($pdo, $query);
        if (!$user) {
            return [
                'ok' => true,
                'found' => false,
                'message' => admin_coins_t(
                    'Користувача не знайдено.',
                    'Пользователь не найден.',
                    'User not found.'
                ),
            ];
        }

        $id = (int)($user['id'] ?? 0);
        $username = trim((string)($user['username'] ?? ''));
        $email = trim((string)($user['email'] ?? ''));
        $balance = (int)($user['vm_coins_balance'] ?? 0);

        $label = $username !== '' ? '@' . $username : ('#' . $id);
        $metaParts = ['ID: ' . $id];
        if ($email !== '') {
            $metaParts[] = $email;
        }

        return [
            'ok' => true,
            'found' => true,
            'user' => [
                'id' => $id,
                'username' => $username,
                'email' => $email,
                'label' => $label,
                'meta' => implode(' · ', $metaParts),
                'balance' => $balance,
                'balance_formatted' => admin_coins_num($balance),
            ],
        ];
    }
}

if (!function_exists('admin_coins_apply_manual_adjustment')) {
    function admin_coins_apply_manual_adjustment(
        PDO $pdo,
        int $targetUserId,
        int $deltaAmount,
        int $adminUserId,
        ?string $note = null
    ): array {
        if ($targetUserId <= 0) {
            return ['ok' => false, 'reason' => 'bad_user'];
        }

        if ($deltaAmount === 0) {
            return ['ok' => false, 'reason' => 'zero_delta'];
        }

        if (!admin_coins_db_has_table($pdo, 'vm_coin_transactions')) {
            return ['ok' => false, 'reason' => 'tx_table_missing'];
        }

        $needCols = [
            'vm_coins_balance',
            'vm_coins_earned_total',
            'vm_coins_spent_total',
            'vm_coins_updated_at',
        ];
        foreach ($needCols as $col) {
            if (!admin_coins_db_has_column($pdo, 'users', $col)) {
                return ['ok' => false, 'reason' => 'schema_missing', 'column' => $col];
            }
        }

        $ownTx = !$pdo->inTransaction();

        try {
            if ($ownTx) {
                $pdo->beginTransaction();
            }

            $st = $pdo->prepare("
                SELECT id, vm_coins_balance, vm_coins_earned_total, vm_coins_spent_total
                FROM users
                WHERE id = ?
                LIMIT 1
                FOR UPDATE
            ");
            $st->execute([$targetUserId]);
            $u = $st->fetch(PDO::FETCH_ASSOC);

            if (!$u) {
                if ($ownTx && $pdo->inTransaction()) {
                    $pdo->rollBack();
                }
                return ['ok' => false, 'reason' => 'user_not_found'];
            }

            $currentBalance = (int)$u['vm_coins_balance'];
            $earnedTotal    = (int)$u['vm_coins_earned_total'];
            $spentTotal     = (int)$u['vm_coins_spent_total'];
            $newBalance     = $currentBalance + $deltaAmount;

            if ($newBalance < 0) {
                if ($ownTx && $pdo->inTransaction()) {
                    $pdo->rollBack();
                }

                $requiredAmount = abs($deltaAmount);
                $missingAmount  = max(0, $requiredAmount - $currentBalance);

                return [
                    'ok' => false,
                    'reason' => 'insufficient_funds',
                    'balance' => $currentBalance,
                    'available_balance' => $currentBalance,
                    'required_amount' => $requiredAmount,
                    'missing_amount' => $missingAmount,
                    'delta_amount' => $deltaAmount,
                ];
            }

            $newEarnedTotal = $earnedTotal + ($deltaAmount > 0 ? $deltaAmount : 0);
            $newSpentTotal  = $spentTotal + ($deltaAmount < 0 ? abs($deltaAmount) : 0);

            $metaJson = json_encode([
                'admin_user_id' => $adminUserId,
                'source' => 'admin/coins/adjust.php',
            ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

            $note = trim((string)$note);
            if ($note === '') {
                $note = admin_coins_t(
                    'Ручне коригування адміністратором',
                    'Ручная корректировка администратором',
                    'Manual adjustment by admin'
                );
            }

            $ins = $pdo->prepare("
                INSERT INTO vm_coin_transactions
                (user_id, delta_amount, balance_after, event_key, entity_type, entity_id, related_user_id, op_key, note, meta_json, created_at)
                VALUES (?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, NOW())
            ");
            $ins->execute([
                $targetUserId,
                $deltaAmount,
                $newBalance,
                'admin_adjust',
                'user',
                $targetUserId,
                $adminUserId > 0 ? $adminUserId : null,
                $note,
                $metaJson,
            ]);

            $txId = (int)$pdo->lastInsertId();

            $up = $pdo->prepare("
                UPDATE users
                SET vm_coins_balance = ?,
                    vm_coins_earned_total = ?,
                    vm_coins_spent_total = ?,
                    vm_coins_updated_at = NOW()
                WHERE id = ?
                LIMIT 1
            ");
            $up->execute([
                $newBalance,
                $newEarnedTotal,
                $newSpentTotal,
                $targetUserId,
            ]);

            if ($ownTx && $pdo->inTransaction()) {
                $pdo->commit();
            }

            return [
                'ok' => true,
                'tx_id' => $txId,
                'balance' => $newBalance,
                'available_balance' => $newBalance,
            ];
        } catch (Throwable $e) {
            if ($ownTx && $pdo->inTransaction()) {
                $pdo->rollBack();
            }
            return [
                'ok' => false,
                'reason' => 'exception',
                'error' => $e->getMessage(),
            ];
        }
    }
}

/* ===== ajax user lookup ===== */
if (!is_post() && ((string)($_GET['ajax'] ?? '') === 'user_lookup')) {
    $q = trim((string)($_GET['user_q'] ?? ''));
    admin_coins_emit_json(admin_coins_user_lookup_payload($pdo, $q));
}

/* ===== actions ===== */
if (is_post()) {
    $action = (string)($_POST['action'] ?? '');

    if (!csrf_check((string)($_POST['csrf'] ?? ''))) {
        admin_coins_flash_set(
            'danger',
            function_exists('t')
                ? (string)t('bad_csrf')
                : admin_coins_t('Невірний CSRF токен.', 'Неверный CSRF токен.', 'Invalid CSRF token.')
        );
        admin_coins_redirect_self();
    }

    if ($action === 'manual_adjust') {
        $userQuery = trim((string)($_POST['user_query'] ?? ''));
        $operation = trim((string)($_POST['operation'] ?? 'add'));
        $amountRaw = trim((string)($_POST['amount'] ?? '0'));
        $note      = trim((string)($_POST['note'] ?? ''));

        $amount = is_numeric($amountRaw) ? abs((int)$amountRaw) : 0;

        if (!isset($_POST['amount']) && isset($_POST['delta_amount'])) {
            $legacyDelta = is_numeric((string)$_POST['delta_amount']) ? (int)$_POST['delta_amount'] : 0;
            $amount = abs($legacyDelta);
            $operation = $legacyDelta < 0 ? 'subtract' : 'add';
        }

        if (!in_array($operation, ['add', 'subtract'], true)) {
            $operation = 'add';
        }

        $delta = $operation === 'subtract' ? -$amount : $amount;
        $adminId = (int)($me['id'] ?? 0);

        if ($userQuery === '') {
            admin_coins_flash_set(
                'danger',
                admin_coins_t('Вкажи ID, нікнейм або email користувача.', 'Укажи ID, никнейм или email пользователя.', 'Enter user ID, username, or email.')
            );
            admin_coins_redirect_self('manual-adjust');
        }

        if ($amount <= 0 || $delta === 0) {
            admin_coins_flash_set(
                'danger',
                admin_coins_t('Сума коригування має бути більшою за 0.', 'Сумма корректировки должна быть больше 0.', 'Adjustment amount must be greater than 0.')
            );
            admin_coins_redirect_self('manual-adjust');
        }

        $target = admin_coins_find_user($pdo, $userQuery);
        if (!$target) {
            admin_coins_flash_set(
                'danger',
                admin_coins_t('Користувача не знайдено.', 'Пользователь не найден.', 'User not found.')
            );
            admin_coins_redirect_self('manual-adjust');
        }

        $res = admin_coins_apply_manual_adjustment($pdo, (int)$target['id'], $delta, $adminId, $note);
        if (!($res['ok'] ?? false)) {
            $reason = (string)($res['reason'] ?? '');

            if ($reason === 'insufficient_funds') {
                $available = (int)($res['available_balance'] ?? $res['balance'] ?? 0);
                admin_coins_flash_set(
                    'danger',
                    admin_coins_t(
                        'Недостатньо VM Coins для списання. Поточний баланс користувача: ',
                        'Недостаточно VM Coins для списания. Текущий баланс пользователя: ',
                        'Not enough VM Coins to subtract. Current user balance: '
                    ) . admin_coins_num($available)
                );
            } else {
                admin_coins_flash_set(
                    'danger',
                    admin_coins_t('Не вдалося скоригувати баланс.', 'Не удалось скорректировать баланс.', 'Failed to adjust balance.')
                );
            }
        } else {
            $label = trim((string)($target['username'] ?? ''));
            if ($label === '') {
                $label = '#' . (int)$target['id'];
            } else {
                $label = '@' . $label;
            }

            $deltaLabel = ($delta > 0 ? '+' : '') . $delta;
            $newBalance = (int)($res['balance'] ?? 0);

            admin_coins_flash_set(
                'success',
                admin_coins_t('Баланс оновлено для ', 'Баланс обновлён для ', 'Balance updated for ')
                . $label
                . ' (' . $deltaLabel . '). '
                . admin_coins_t('Новий баланс: ', 'Новый баланс: ', 'New balance: ')
                . admin_coins_num($newBalance)
            );
        }

        admin_coins_redirect_self('manual-adjust');
    }
}

/* ===== view data ===== */
$flash = admin_coins_flash_pull();
$manualUserPrefill = trim((string)($_GET['user_q'] ?? ''));
$manualUserData = $manualUserPrefill !== '' ? admin_coins_find_user($pdo, $manualUserPrefill) : null;

$manualUserLabel = admin_coins_t('Користувач не вибраний', 'Пользователь не выбран', 'No user selected');
$manualUserMeta = admin_coins_t('Введи ID, username або email, щоб побачити поточний баланс.', 'Введи ID, username или email, чтобы увидеть текущий баланс.', 'Enter ID, username, or email to see the current balance.');
$manualUserBalance = '—';

if ($manualUserData) {
    $mId = (int)($manualUserData['id'] ?? 0);
    $mUsername = trim((string)($manualUserData['username'] ?? ''));
    $mEmail = trim((string)($manualUserData['email'] ?? ''));
    $manualUserLabel = $mUsername !== '' ? '@' . $mUsername : ('#' . $mId);

    $parts = ['ID: ' . $mId];
    if ($mEmail !== '') {
        $parts[] = $mEmail;
    }
    $manualUserMeta = implode(' · ', $parts);
    $manualUserBalance = admin_coins_num((int)($manualUserData['vm_coins_balance'] ?? 0));
}

$title = admin_coins_t('VM Coins — ручне коригування', 'VM Coins — ручная корректировка', 'VM Coins — Manual adjustment');

require_once __DIR__ . '/../../includes/header.php';
?>

<div class="container py-4">
    <div class="row g-4">
        <div class="col-lg-8">
            <div class="card card-app mb-4" id="manual-adjust">
                <div class="card-body">
                    <div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
                        <div>
                            <h1 class="h3 mb-1"><?= e(admin_coins_t('VM Coins — ручне коригування', 'VM Coins — ручная корректировка', 'VM Coins — Manual adjustment')) ?></h1>
                            <div class="text-muted">
                                <?= e(admin_coins_t(
                                    'Окрема сторінка для ручного поповнення або списання монет у користувачів.',
                                    'Отдельная страница для ручного пополнения или списания монет у пользователей.',
                                    'A dedicated page for manually adding or subtracting user coins.'
                                )) ?>
                            </div>
                        </div>
                    </div>

                    <?php if ($flash): ?>
                        <div class="alert alert-<?= e((string)($flash['type'] ?? 'info')) ?> mb-3">
                            <?= e((string)($flash['message'] ?? '')) ?>
                        </div>
                    <?php endif; ?>

                    <div class="text-muted small mb-3"><?= e(admin_coins_section_help('manual_adjust')) ?></div>

                    <form method="post" action="/admin/coins/adjust.php#manual-adjust" class="row g-3" id="manual-adjust-form">
                        <input type="hidden" name="csrf" value="<?= e(csrf_token()) ?>">
                        <input type="hidden" name="action" value="manual_adjust">

                        <div class="col-lg-5">
                            <label class="form-label"><?= e(admin_coins_t('Користувач', 'Пользователь', 'User')) ?></label>
                            <input
                                class="form-control"
                                type="text"
                                name="user_query"
                                id="manual-user-query"
                                value="<?= e($manualUserPrefill) ?>"
                                placeholder="<?= e(admin_coins_t('ID, @username або email', 'ID, @username или email', 'ID, @username or email')) ?>"
                                autocomplete="off"
                                required
                            >
                            <div class="form-text">
                                <?= e(admin_coins_t(
                                    'Можна вказати ID, нікнейм або email.',
                                    'Можно указать ID, никнейм или email.',
                                    'You can enter ID, username, or email.'
                                )) ?>
                            </div>
                        </div>

                        <div class="col-lg-3">
                            <label class="form-label"><?= e(admin_coins_t('Дія', 'Действие', 'Action')) ?></label>
                            <select class="form-select" name="operation" required>
                                <option value="add"><?= e(admin_coins_t('Додати монети', 'Добавить монеты', 'Add coins')) ?></option>
                                <option value="subtract"><?= e(admin_coins_t('Списати монети', 'Списать монеты', 'Subtract coins')) ?></option>
                            </select>
                            <div class="form-text">
                                <?= e(admin_coins_t(
                                    'Окремо обирай нарахування або списання.',
                                    'Отдельно выбирай начисление или списание.',
                                    'Choose credit or debit separately.'
                                )) ?>
                            </div>
                        </div>

                        <div class="col-lg-4">
                            <label class="form-label"><?= e(admin_coins_t('Кількість монет', 'Количество монет', 'Coins amount')) ?></label>
                            <input
                                class="form-control"
                                type="number"
                                name="amount"
                                min="1"
                                max="1000000"
                                step="1"
                                required
                            >
                            <div class="form-text">
                                <?= e(admin_coins_t(
                                    'Вводь лише додатне число.',
                                    'Вводи только положительное число.',
                                    'Enter a positive number only.'
                                )) ?>
                            </div>
                        </div>

                        <div class="col-12">
                            <div class="border rounded-3 p-3 bg-light" id="manual-user-preview">
                                <div class="d-flex flex-wrap align-items-center justify-content-between gap-3">
                                    <div>
                                        <div class="small text-muted mb-1"><?= e(admin_coins_t('Знайдений користувач', 'Найденный пользователь', 'Matched user')) ?></div>
                                        <div class="fw-semibold" data-manual-user-label><?= e($manualUserLabel) ?></div>
                                        <div class="small text-muted" data-manual-user-meta><?= e($manualUserMeta) ?></div>
                                    </div>
                                    <div class="text-lg-end">
                                        <div class="small text-muted mb-1"><?= e(admin_coins_t('Поточний баланс', 'Текущий баланс', 'Current balance')) ?></div>
                                        <div class="h4 mb-0" data-manual-user-balance><?= e($manualUserBalance) ?></div>
                                    </div>
                                </div>
                                <div class="small text-muted mt-2" data-manual-user-status>
                                    <?= e(admin_coins_t(
                                        'Баланс оновлюється автоматично під час вводу користувача.',
                                        'Баланс обновляется автоматически при вводе пользователя.',
                                        'The balance updates automatically while you type.'
                                    )) ?>
                                </div>
                            </div>
                        </div>

                        <div class="col-12">
                            <div class="alert alert-warning mb-0">
                                <?= e(admin_coins_t(
                                    'Якщо при списанні у користувача не вистачає VM Coins, баланс не піде в мінус — операція буде відхилена.',
                                    'Если при списании у пользователя не хватает VM Coins, баланс не уйдёт в минус — операция будет отклонена.',
                                    'If the user does not have enough VM Coins for subtraction, the balance will not go negative — the operation will be rejected.'
                                )) ?>
                            </div>
                        </div>

                        <div class="col-12">
                            <label class="form-label"><?= e(admin_coins_t('Примітка', 'Примечание', 'Note')) ?></label>
                            <input
                                class="form-control"
                                type="text"
                                name="note"
                                maxlength="255"
                                placeholder="<?= e(admin_coins_t('Необов’язково', 'Необязательно', 'Optional')) ?>"
                            >
                        </div>

                        <div class="col-12">
                            <button type="submit" class="btn btn-outline-primary">
                                <?= e(admin_coins_t('Застосувати коригування', 'Применить корректировку', 'Apply adjustment')) ?>
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>

        <div class="col-lg-4">
            <?php admin_sidebar('vmcoins_adjust'); ?>
        </div>
    </div>
</div>

<script>
(() => {
    const input = document.getElementById('manual-user-query');
    const preview = document.getElementById('manual-user-preview');
    if (!input || !preview) return;

    const labelEl = preview.querySelector('[data-manual-user-label]');
    const metaEl = preview.querySelector('[data-manual-user-meta]');
    const balanceEl = preview.querySelector('[data-manual-user-balance]');
    const statusEl = preview.querySelector('[data-manual-user-status]');

    const txt = {
        idleLabel: <?= json_encode(admin_coins_t('Користувач не вибраний', 'Пользователь не выбран', 'No user selected'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
        idleMeta: <?= json_encode(admin_coins_t('Введи ID, username або email, щоб побачити поточний баланс.', 'Введи ID, username или email, чтобы увидеть текущий баланс.', 'Enter ID, username, or email to see the current balance.'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
        idleStatus: <?= json_encode(admin_coins_t('Баланс оновлюється автоматично під час вводу користувача.', 'Баланс обновляется автоматически при вводе пользователя.', 'The balance updates automatically while you type.'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
        loading: <?= json_encode(admin_coins_t('Пошук користувача…', 'Поиск пользователя…', 'Searching user…'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
        notFound: <?= json_encode(admin_coins_t('Користувача не знайдено.', 'Пользователь не найден.', 'User not found.'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
        currentBalance: <?= json_encode(admin_coins_t('Поточний баланс завантажено.', 'Текущий баланс загружен.', 'Current balance loaded.'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
        loadError: <?= json_encode(admin_coins_t('Не вдалося завантажити баланс.', 'Не удалось загрузить баланс.', 'Failed to load balance.'), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>,
    };

    let timer = null;
    let controller = null;

    const setIdle = () => {
        labelEl.textContent = txt.idleLabel;
        metaEl.textContent = txt.idleMeta;
        balanceEl.textContent = '—';
        statusEl.textContent = txt.idleStatus;
    };

    const setLoading = () => {
        statusEl.textContent = txt.loading;
    };

    const setNotFound = () => {
        labelEl.textContent = txt.notFound;
        metaEl.textContent = '';
        balanceEl.textContent = '—';
        statusEl.textContent = txt.notFound;
    };

    const setFound = (user) => {
        labelEl.textContent = user.label || txt.idleLabel;
        metaEl.textContent = user.meta || '';
        balanceEl.textContent = user.balance_formatted || String(user.balance || 0);
        statusEl.textContent = txt.currentBalance;
    };

    const lookup = async (value) => {
        const q = String(value || '').trim();

        if (controller) {
            controller.abort();
            controller = null;
        }

        if (q === '') {
            setIdle();
            return;
        }

        setLoading();
        controller = new AbortController();

        try {
            const res = await fetch('/admin/coins/adjust.php?ajax=user_lookup&user_q=' + encodeURIComponent(q), {
                method: 'GET',
                credentials: 'same-origin',
                headers: {
                    'Accept': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest'
                },
                cache: 'no-store',
                signal: controller.signal
            });

            if (!res.ok) {
                throw new Error('HTTP ' + res.status);
            }

            const data = await res.json();

            if (!data || !data.ok) {
                throw new Error('Bad payload');
            }

            if (data.found && data.user) {
                setFound(data.user);
            } else {
                setNotFound();
            }
        } catch (err) {
            if (err && err.name === 'AbortError') {
                return;
            }
            statusEl.textContent = txt.loadError;
        }
    };

    const scheduleLookup = () => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            lookup(input.value);
        }, 250);
    };

    input.addEventListener('input', scheduleLookup);
    input.addEventListener('blur', () => {
        clearTimeout(timer);
        lookup(input.value);
    });

    if (String(input.value || '').trim() !== '') {
        lookup(input.value);
    } else {
        setIdle();
    }
})();
</script>

<?php require_once __DIR__ . '/../../includes/footer.php'; ?>