<?php
declare(strict_types=1);

require_once __DIR__ . '/user_auth.php';
require_once __DIR__ . '/views.php';

adminer_app_session_start();

// Bootstrap users table (+ optional seed)
try {
    adminer_app_bootstrap();
} catch (Throwable $e) {
    admin_layout('DB-Verwaltung', '<div class="notice notice-err">' . h($e->getMessage()) . '</div>', 'Fehler beim Start');
    exit;
}

// App-Logout
if ((string)($_GET['auth'] ?? '') === 'logout') {
    adminer_app_logout();
    header('Location: /adminer', true, 302);
    exit;
}

$appPage  = (string)($_GET['page'] ?? 'login');
$appError = null;
$appRegError = null;
$appRegOk    = null;

// Login POST
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'app_login') {
    $res = adminer_app_try_login((string)($_POST['username'] ?? ''), (string)($_POST['password'] ?? ''));
    if (!empty($res['ok'])) {
        header('Location: /adminer', true, 302);
        exit;
    }
    $appError = (string)($res['error'] ?? 'Login fehlgeschlagen.');
    $appPage  = 'login';
}

// Register POST
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'app_register') {
    $res = adminer_app_try_register(
        (string)($_POST['username'] ?? ''),
        (string)($_POST['password'] ?? ''),
        (string)($_POST['password2'] ?? '')
    );
    if (!empty($res['ok'])) {
        $appRegOk  = 'Konto erstellt. Bitte lasse dich von einem Server-Administrator verifizieren, bevor du dich anmelden kannst.';
        $appPage   = 'login';
    } else {
        $appRegError = (string)($res['error'] ?? 'Registrierung fehlgeschlagen.');
        $appPage     = 'register';
    }
}

// ── LOGIN / REGISTER SEITE ────────────────────────────────────────────────
if (!adminer_app_is_logged_in()) {
    $canReg = adminer_app_allow_register();
    $isReg  = ($appPage === 'register');

    $body  = '<div class="login-wrap">';

    // Tabs
    $body .= '<div class="tabs">';
    $body .= '<a class="tab ' . (!$isReg ? 'active' : '') . '" href="/adminer?page=login">Login</a>';
    if ($canReg) $body .= '<a class="tab ' . ($isReg ? 'active' : '') . '" href="/adminer?page=register">Registrieren</a>';
    $body .= '</div>';

    $body .= '<div class="card">';

    if ($appRegOk)   $body .= '<div class="notice notice-ok">'  . h($appRegOk)    . '</div>';
    if ($appError)   $body .= '<div class="notice notice-err">' . h($appError)    . '</div>';
    if ($appRegError)$body .= '<div class="notice notice-err">' . h($appRegError) . '</div>';

    if ($isReg && $canReg) {
        // ── Registrierungsformular ──────────────────────────────────────
        $body .= '<form method="post">'
            . '<input type="hidden" name="action" value="app_register">'
            . '<div class="field"><label>Benutzername</label><input name="username" autocomplete="username" placeholder="z.B. fabian"></div>'
            . '<div class="field"><label>Passwort</label><input name="password" type="password" autocomplete="new-password" placeholder="mind. 8 Zeichen"></div>'
            . '<div class="field"><label>Passwort wiederholen</label><input name="password2" type="password" autocomplete="new-password" placeholder="Wiederholung"></div>'
            . '<button class="btn" type="submit" style="width:100%">Konto erstellen</button>'
            . '</form>';
        $body .= '<p class="muted" style="margin-top:.9rem;text-align:center">Bereits ein Konto? <a href="/adminer?page=login">Login</a></p>';
    } else {
        // ── Login-Formular ──────────────────────────────────────────────
        $body .= '<form method="post">'
            . '<input type="hidden" name="action" value="app_login">'
            . '<div class="field"><label>Benutzername</label><input name="username" autocomplete="username" placeholder="Dein Benutzername"></div>'
            . '<div class="field"><label>Passwort</label><input name="password" type="password" autocomplete="current-password" placeholder="Dein Passwort"></div>'
            . '<button class="btn" type="submit" style="width:100%">Anmelden</button>'
            . '</form>';
        if ($canReg) $body .= '<p class="muted" style="margin-top:.9rem;text-align:center">Noch kein Konto? <a href="/adminer?page=register">Registrieren</a></p>';
    }

    $body .= '</div>';
    $body .= '</div>';

    admin_layout('DB-Verwaltung', $body, $isReg ? 'Neues Konto erstellen' : 'Bitte einloggen');
    exit;
}

// ── DB-VERBINDUNGS-LOGIN ──────────────────────────────────────────────────
require_once __DIR__ . '/auth.php';
admin_session_start();

if ((string)($_GET['a'] ?? '') === 'logout') {
    admin_logout();
    header('Location: /adminer', true, 302);
    exit;
}

if (!isset($_SESSION['db_admin_select'])) $_SESSION['db_admin_select'] = [];

$selectError = null;
$selectMsg   = null;

// Probe: Datenbanken laden
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'probe') {
    $host = trim((string)($_POST['host'] ?? ''));
    $port = (int)($_POST['port'] ?? 3306);
    $user = trim((string)($_POST['user'] ?? ''));
    $pass = (string)($_POST['pass'] ?? '');

    if ($host === '' || $port <= 0 || $user === '') {
        $selectError = 'Bitte Host, Port und Benutzer angeben.';
    } else {
        try {
            $pdo = new PDO(sprintf('mysql:host=%s;port=%d;charset=utf8mb4', $host, $port), $user, $pass, [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            ]);
            $dbs = $pdo->query('SHOW DATABASES')->fetchAll(PDO::FETCH_COLUMN, 0);
            $_SESSION['db_admin_select'] = compact('host', 'port', 'user', 'pass', 'dbs');
            $selectMsg = 'Datenbanken geladen – bitte unten eine auswählen.';
        } catch (Throwable $e) {
            $selectError = 'Fehler: ' . $e->getMessage();
        }
    }
}

// DB-Login
$dbError = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'login') {
    $res = admin_try_login(
        trim((string)($_POST['host'] ?? '')),
        (int)($_POST['port'] ?? 3306),
        trim((string)($_POST['user'] ?? '')),
        (string)($_POST['pass'] ?? ''),
        trim((string)($_POST['db'] ?? ''))
    );
    if ($res['ok']) {
        header('Location: /adminer', true, 302);
        exit;
    }
    $dbError = (string)($res['error'] ?? 'Login fehlgeschlagen.');
}

$defaults    = admin_default_creds();
$selectState = is_array($_SESSION['db_admin_select']) ? $_SESSION['db_admin_select'] : [];
$prefHost    = isset($selectState['host']) ? (string)$selectState['host'] : (string)$defaults['host'];
$prefPort    = isset($selectState['port']) ? (int)$selectState['port']   : (int)$defaults['port'];
$prefUser    = isset($selectState['user']) ? (string)$selectState['user'] : (string)$defaults['user'];
$prefPass    = isset($selectState['pass']) ? (string)$selectState['pass'] : '';
$dbList      = isset($selectState['dbs'])  && is_array($selectState['dbs']) ? $selectState['dbs'] : [];

if (!admin_is_logged_in()) {
    $body  = '<div class="card" style="max-width:520px;margin:0 auto">';

    if ($selectMsg)  $body .= '<div class="notice notice-ok">'  . h($selectMsg)  . '</div>';
    if ($selectError)$body .= '<div class="notice notice-err">' . h($selectError) . '</div>';
    if ($dbError)    $body .= '<div class="notice notice-err">' . h($dbError)     . '</div>';

    // Step 1
    $body .= '<h2>1 · Server verbinden</h2>';
    $body .= '<form method="post">'
        . '<input type="hidden" name="action" value="probe">'
        . '<div class="field"><label>Host</label><input name="host" value="' . h($prefHost) . '" placeholder="localhost"></div>'
        . '<div class="field"><label>Port</label><div class="field-port"><input id="port-input" name="port" type="number" value="' . h((string)$prefPort) . '" min="1" max="65535"><div class="field-port__spinners"><button type="button" onclick="var i=document.getElementById(\'port-input\');i.value=Math.min(65535,+(i.value||3306)+1)">▲</button><button type="button" onclick="var i=document.getElementById(\'port-input\');i.value=Math.max(1,+(i.value||3306)-1)">▼</button></div></div></div>'
        . '<div class="field"><label>Benutzer</label><input name="user" value="' . h($prefUser) . '"></div>'
        . '<div class="field"><label>Passwort</label><input name="pass" type="password" value="' . h($prefPass) . '"></div>'
        . '<button class="btn btn-ghost btn-sm" type="submit">Datenbanken laden</button>'
        . '</form>';

    $body .= '<hr>';

    // Step 2
    $body .= '<h2>2 · Datenbank auswählen & einloggen</h2>';
    $body .= '<form method="post">'
        . '<input type="hidden" name="action" value="login">'
        . '<input type="hidden" name="host" value="' . h($prefHost) . '">'
        . '<input type="hidden" name="port" value="' . h((string)$prefPort) . '">'
        . '<input type="hidden" name="user" value="' . h($prefUser) . '">'
        . '<input type="hidden" name="pass" value="' . h($prefPass) . '">'
        . '<div class="field"><label>Datenbank</label>';

    if (!empty($dbList)) {
        $body .= '<select name="db">';
        $sel = (string)$defaults['db'];
        foreach ($dbList as $dbName) {
            $dbName = (string)$dbName;
            $body .= '<option value="' . h($dbName) . '"' . ($dbName === $sel ? ' selected' : '') . '>' . h($dbName) . '</option>';
        }
        $body .= '</select>';
    } else {
        $body .= '<input name="db" value="' . h((string)$defaults['db']) . '" placeholder="Datenbank-Name">';
    }

    $body .= '</div>'
        . '<button class="btn" type="submit" style="width:100%">Einloggen</button>'
        . '</form>';

    $body .= '</div>';

    admin_layout('DB-Verwaltung', $body, 'Datenbankverbindung');
    exit;
}

// ── DB-VERWALTUNG (eingeloggt) ────────────────────────────────────────────
try {
    $pdo    = admin_pdo();
    $table  = (string)($_GET['t'] ?? '');
    $page   = max(1, (int)($_GET['p'] ?? 1));
    $limit  = 50;
    $offset = ($page - 1) * $limit;

    $msg             = null;
    $queryResultHtml = '';

    // SQL Query ausführen
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'query') {
        $sql = trim((string)($_POST['sql'] ?? ''));
        if ($sql !== '') {
            if (preg_match('/;\s*\S/', $sql)) {
                $msg = ['ok' => false, 'text' => 'Nur ein Statement ausführen (kein zweites Semikolon).'];
            } else {
                try {
                    $stmt = $pdo->query($sql);
                    if ($stmt instanceof PDOStatement) {
                        $rows = $stmt->fetchAll();
                        $queryResultHtml = '<h3 style="margin-top:1.2rem">Ergebnis</h3>' . admin_render_table($rows);
                        $msg = ['ok' => true, 'text' => 'Query ausgeführt (' . count($rows) . ' Zeilen).'];
                    } else {
                        $msg = ['ok' => true, 'text' => 'Statement ausgeführt.'];
                    }
                } catch (Throwable $e) {
                    $msg = ['ok' => false, 'text' => $e->getMessage()];
                }
            }
        }
    }

    // Datensatz löschen
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'delete_row') {
        $delTable = (string)($_POST['table'] ?? '');
        $pkCol    = (string)($_POST['pk_col'] ?? '');
        $pkVal    = (string)($_POST['pk_val'] ?? '');

        if (!preg_match('/^[A-Za-z0-9_]+$/', $delTable) || !preg_match('/^[A-Za-z0-9_]+$/', $pkCol)) {
            $msg = ['ok' => false, 'text' => 'Ungültige Parameter für Löschen.'];
        } else {
            try {
                // PK-Spalte gegen echte PK-Spalte validieren
                $realPk = admin_get_primary_key_column($pdo, $delTable);
                if ($realPk === null || $realPk !== $pkCol) {
                    $msg = ['ok' => false, 'text' => 'Löschen ist nur über eine echte Primary-Key-Spalte möglich.'];
                } else {
                    $stmt = $pdo->prepare('DELETE FROM `' . $delTable . '` WHERE `' . $pkCol . '` = :v LIMIT 1');
                    $stmt->execute([':v' => $pkVal]);
                    $msg = ['ok' => true, 'text' => 'Datensatz gelöscht.'];

                    // Wenn wir gerade diese Tabelle anzeigen: auf Seite 1 zurück, damit man nicht auf leerer Seite landet
                    if ($table === $delTable) {
                        $page = 1;
                        $offset = 0;
                    }
                }
            } catch (Throwable $e) {
                $msg = ['ok' => false, 'text' => $e->getMessage()];
            }
        }
    }

    // Datensatz hinzufügen
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'insert_row') {
        $insTable = (string)($_POST['table'] ?? '');
        if (!preg_match('/^[A-Za-z0-9_]+$/', $insTable)) {
            $msg = ['ok' => false, 'text' => 'Ungültiger Tabellenname für Insert.'];
        } else {
            try {
                $colsMeta = admin_get_table_columns($pdo, $insTable);
                if (empty($colsMeta)) {
                    $msg = ['ok' => false, 'text' => 'Keine Spalten gefunden.'];
                } else {
                    $fields = [];
                    foreach ($colsMeta as $c) {
                        $name = (string)$c['Field'];
                        // Nur Spalten zulassen, die wirklich existieren
                        if (!array_key_exists('col_' . $name, $_POST)) continue;

                        $raw = (string)($_POST['col_' . $name] ?? '');
                        $isNull = ((string)($_POST['null_' . $name] ?? '') === '1');

                        $fields[] = [
                            'name' => $name,
                            'value' => $isNull ? null : ($raw === '' ? null : $raw),
                            'forceNull' => $isNull,
                        ];
                    }

                    // Leere Submits verhindern
                    if (empty($fields)) {
                        $msg = ['ok' => false, 'text' => 'Keine Felder zum Einfügen übergeben.'];
                    } else {
                        $colNames = [];
                        $placeholders = [];
                        $params = [];

                        foreach ($fields as $f) {
                            $colNames[] = '`' . $f['name'] . '`';
                            $ph = ':c_' . $f['name'];
                            $placeholders[] = $ph;
                            $params[$ph] = $f['value'];
                        }

                        $sql = 'INSERT INTO `' . $insTable . '` (' . implode(',', $colNames) . ') VALUES (' . implode(',', $placeholders) . ')';
                        $stmt = $pdo->prepare($sql);
                        $stmt->execute($params);
                        $msg = ['ok' => true, 'text' => 'Datensatz hinzugefügt.'];

                        // Nach Insert wieder zur Tabelle springen
                        $table = $insTable;
                        $page = 1;
                        $offset = 0;
                    }
                }
            } catch (Throwable $e) {
                $msg = ['ok' => false, 'text' => $e->getMessage()];
            }
        }
    }

    $tables = $pdo->query('SHOW TABLES')->fetchAll(PDO::FETCH_NUM);

    // ── TOP BAR ──────────────────────────────────────────────────────────
    $dbName = (string)($_SESSION['db_admin']['db'] ?? '');
    $uname  = (string)($_SESSION['adminer_app']['username'] ?? '');

    $body = '<div class="top-bar">'
        . '<div class="top-bar-left">'
        . '<span style="font-weight:700;font-size:1rem">' . h($dbName) . '</span>'
        . ($uname ? '<span class="pill">' . h($uname) . '</span>' : '')
        . '</div>'
        . '<div class="top-bar-actions">'
        . '<a class="btn btn-ghost btn-sm" href="/adminer?a=logout">DB-Logout</a>'
        . '<a class="btn btn-ghost btn-sm" href="/adminer?auth=logout">Account-Logout</a>'
        . '</div>'
        . '</div>';

    // ── GRID: TABELLENLISTE + CONTENT ─────────────────────────────────────
    $body .= '<div class="admin-grid">';

    // Linke Spalte: Tabellenliste
    $body .= '<div class="card">';
    $body .= '<h2>Tabellen</h2>';
    if (empty($tables)) {
        $body .= '<p class="muted">Keine Tabellen gefunden.</p>';
    } else {
        $body .= '<ul class="nav-list">';
        foreach ($tables as $row) {
            $tn  = (string)$row[0];
            $cls = ($tn === $table) ? 'active' : '';
            $body .= '<li><a class="' . $cls . '" href="/adminer?t=' . rawurlencode($tn) . '">' . h($tn) . '</a></li>';
        }
        $body .= '</ul>';
    }
    $body .= '</div>';

    // Rechte Spalte: Browse + Query
    $body .= '<div>';

    // Notices
    if ($msg) {
        $cls  = $msg['ok'] ? 'notice-ok' : 'notice-err';
        $body .= '<div class="notice ' . $cls . '">' . h($msg['text']) . '</div>';
    }

    // Browse
    if ($table !== '') {
        if (!preg_match('/^[A-Za-z0-9_]+$/', $table)) {
            $body .= '<div class="notice notice-err">Ungültiger Tabellenname.</div>';
        } else {
            $pkCol = admin_get_primary_key_column($pdo, $table);
            $stmt = $pdo->query('SELECT * FROM `' . $table . '` LIMIT ' . (int)$limit . ' OFFSET ' . (int)$offset);
            $rows = $stmt->fetchAll();

            $body .= '<div class="card" style="margin-bottom:16px">';
            $body .= '<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap">'
                . '<h2 style="margin:0">' . h($table) . '</h2>'
                . '<a class="btn btn-ghost btn-sm" href="/adminer?t=' . rawurlencode($table) . '&add=1">+ Datensatz</a>'
                . '</div>';

            $body .= admin_render_table($rows, $table, $pkCol);

            $body .= '<div class="pagination">';
            if ($page > 1) $body .= '<a class="btn btn-ghost btn-sm" href="/adminer?t=' . rawurlencode($table) . '&p=' . ($page - 1) . '">← Zurück</a>';
            if (count($rows) === $limit) $body .= '<a class="btn btn-ghost btn-sm" href="/adminer?t=' . rawurlencode($table) . '&p=' . ($page + 1) . '">Weiter →</a>';
            if ($page > 1 || count($rows) === $limit) $body .= '<span class="muted">Seite ' . $page . '</span>';
            $body .= '</div>';

            $body .= '</div>';

            // Add form
            if ((string)($_GET['add'] ?? '') === '1') {
                $colsMeta = admin_get_table_columns($pdo, $table);
                $body .= '<div class="card" style="margin-bottom:16px">';
                $body .= '<h2>Datensatz hinzufügen</h2>';
                $body .= '<form method="post">'
                    . '<input type="hidden" name="action" value="insert_row">'
                    . '<input type="hidden" name="table" value="' . h($table) . '">';

                foreach ($colsMeta as $c) {
                    $col = (string)$c['Field'];
                    $extra = (string)($c['Extra'] ?? '');
                    $nullOk = ((string)($c['Null'] ?? 'NO') === 'YES');

                    // auto_increment standardmäßig nicht anfassen
                    if (stripos($extra, 'auto_increment') !== false) {
                        $body .= '<div class="field">'
                            . '<label>' . h($col) . ' <span class="pill">auto</span></label>'
                            . '<input disabled value="(auto)" />'
                            . '</div>';
                        continue;
                    }

                    $body .= '<div class="field">'
                        . '<label>' . h($col) . ($nullOk ? ' <span class="pill">NULL ok</span>' : '') . '</label>'
                        . '<input name="col_' . h($col) . '" placeholder="Wert…">';

                    if ($nullOk) {
                        $body .= '<div style="margin-top:8px;display:flex;align-items:center;gap:8px">'
                            . '<input style="width:auto" type="checkbox" name="null_' . h($col) . '" value="1" id="null_' . h($col) . '">'
                            . '<label for="null_' . h($col) . '" style="margin:0;text-transform:none;letter-spacing:0;font-size:.85rem;color:var(--text-muted)">NULL setzen</label>'
                            . '</div>';
                    }

                    $body .= '</div>';
                }

                $body .= '<div style="display:flex;gap:10px;flex-wrap:wrap">'
                    . '<button class="btn" type="submit">Speichern</button>'
                    . '<a class="btn btn-ghost" href="/adminer?t=' . rawurlencode($table) . '">Abbrechen</a>'
                    . '</div>'
                    . '</form>';
                $body .= '</div>';
            }
        }
    }

    // SQL Query Box
    $body .= '<div class="card">';
    $body .= '<h2>SQL Query</h2>';
    $body .= '<form method="post">'
        . '<input type="hidden" name="action" value="query">'
        . '<div class="field"><textarea name="sql" rows="6" placeholder="SELECT * FROM tabelle LIMIT 10"></textarea></div>'
        . '<button class="btn btn-sm" type="submit">Ausführen</button>'
        . '</form>';
    $body .= $queryResultHtml;
    $body .= '</div>';

    $body .= '</div>'; // right col
    $body .= '</div>'; // admin-grid

    admin_layout('DB-Verwaltung', $body, h($dbName), 'wrap--full');

} catch (Throwable $e) {
    admin_logout();
    admin_layout('DB-Verwaltung',
        '<div class="notice notice-err">' . h($e->getMessage()) . '</div>'
        . '<p style="margin-top:1rem;text-align:center"><a class="btn btn-ghost btn-sm" href="/adminer">Zurück zum Login</a></p>',
        'Fehler',
        'wrap--wide'
    );
}

function admin_render_table(array $rows, string $table = '', ?string $pkCol = null): string
{
    if (empty($rows)) return '<p class="muted">(keine Zeilen)</p>';

    $cols = array_keys((array)$rows[0]);
    $hasActions = ($table !== '' && $pkCol !== null && in_array($pkCol, $cols, true));

    $html = '<div class="table-scroll"><table class="db-table"><thead><tr>';
    foreach ($cols as $c) $html .= '<th>' . h((string)$c) . '</th>';
    if ($hasActions) $html .= '<th style="width:1%;white-space:nowrap">Aktionen</th>';

    $html .= '</tr></thead><tbody>';
    foreach ($rows as $r) {
        $html .= '<tr>';
        foreach ($cols as $c) {
            $v = $r[$c] ?? null;
            $cell = $v === null
                ? '<span class="null-val">NULL</span>'
                : (strlen((string)$v) > 300 ? h(substr((string)$v, 0, 300)) . '…' : h((string)$v));
            $html .= '<td>' . $cell . '</td>';
        }

        if ($hasActions) {
            $pkVal = $r[$pkCol] ?? null;
            $safePkVal = $pkVal === null ? '' : (string)$pkVal;

            $html .= '<td>'
                . '<form method="post" style="display:inline" onsubmit="return confirm(\'Datensatz wirklich löschen?\');">'
                . '<input type="hidden" name="action" value="delete_row">'
                . '<input type="hidden" name="table" value="' . h($table) . '">'
                . '<input type="hidden" name="pk_col" value="' . h((string)$pkCol) . '">'
                . '<input type="hidden" name="pk_val" value="' . h($safePkVal) . '">'
                . '<button class="btn btn-ghost btn-sm" type="submit">Löschen</button>'
                . '</form>'
                . '</td>';
        }

        $html .= '</tr>';
    }
    $html .= '</tbody></table></div>';
    return $html;
}

function admin_get_primary_key_column(PDO $pdo, string $table): ?string
{
    if (!preg_match('/^[A-Za-z0-9_]+$/', $table)) return null;

    $stmt = $pdo->prepare(
        "SELECT COLUMN_NAME\n"
        . "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE\n"
        . "WHERE TABLE_SCHEMA = DATABASE()\n"
        . "  AND TABLE_NAME = :t\n"
        . "  AND CONSTRAINT_NAME = 'PRIMARY'\n"
        . "ORDER BY ORDINAL_POSITION\n"
        . "LIMIT 1"
    );
    $stmt->execute([':t' => $table]);
    $pk = $stmt->fetchColumn();
    return $pk !== false ? (string)$pk : null;
}

function admin_get_table_columns(PDO $pdo, string $table): array
{
    if (!preg_match('/^[A-Za-z0-9_]+$/', $table)) return [];
    $stmt = $pdo->query('SHOW COLUMNS FROM `' . $table . '`');
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    return is_array($rows) ? $rows : [];
}
