<?php
/**
 * MiniAdmin v2 - Lightweight MySQL manager with full CRUD
 * Single-file PHP · Edit · Delete · Insert · Browse · SQL · Structure
 */

session_start();
error_reporting(0);

define('APP_NAME', 'MiniAdmin');
define('VERSION',  '2.0');

// ── helpers ──────────────────────────────────────────────────────────────────

function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }

function pdo() {
    if (!isset($_SESSION['db_conn_params'])) return null;
    $p   = $_SESSION['db_conn_params'];
    $dsn = "mysql:host={$p['host']};port={$p['port']};charset=utf8mb4";
    if (!empty($p['db'])) $dsn .= ";dbname={$p['db']}";
    try {
        return new PDO($dsn, $p['user'], $p['pass'], [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4",
        ]);
    } catch (PDOException $e) { return null; }
}

function connected()  { return isset($_SESSION['db_conn_params']) && pdo() !== null; }
function currentDb()  { return $_SESSION['db_conn_params']['db'] ?? ''; }

function getPK($table) {
    $db = pdo(); if (!$db) return [];
    $cols = $db->query("DESCRIBE `" . addslashes($table) . "`")->fetchAll();
    $pks  = [];
    foreach ($cols as $c) { if ($c['Key'] === 'PRI') $pks[] = $c['Field']; }
    return $pks;
}

function buildPKWhere($table, $pkJson) {
    $pks    = getPK($table);
    $pkVals = json_decode($pkJson, true);
    if (!$pks || !$pkVals) return null;
    $parts  = []; $params = [];
    foreach ($pks as $col) {
        if (!array_key_exists($col, $pkVals)) return null;
        $parts[]  = "`" . addslashes($col) . "` = ?";
        $params[] = $pkVals[$col];
    }
    return [implode(' AND ', $parts), $params];
}

// ── ACTIONS ───────────────────────────────────────────────────────────────────

$action  = $_GET['action'] ?? 'login';
$message = '';
$msgType = 'error';

// LOGIN
if ($action === 'connect' && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $_SESSION['db_conn_params'] = [
        'host' => trim($_POST['host'] ?? 'localhost'),
        'port' => trim($_POST['port'] ?? '3306'),
        'user' => trim($_POST['user'] ?? ''),
        'pass' => $_POST['pass'] ?? '',
        'db'   => trim($_POST['db']  ?? ''),
    ];
    if (pdo()) { header('Location: ?action=home'); exit; }
    unset($_SESSION['db_conn_params']);
    $message = 'Connection failed. Check your credentials.';
}

// LOGOUT
if ($action === 'logout') { session_destroy(); header('Location: ?action=login'); exit; }

// SELECT DB
if ($action === 'use_db' && connected()) {
    $_SESSION['db_conn_params']['db'] = $_GET['db'] ?? '';
    header('Location: ?action=home'); exit;
}

// DELETE ROW
if ($action === 'delete_row' && connected() && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $tbl    = $_POST['table']  ?? '';
    $pkJson = $_POST['pk']     ?? '';
    $offset = (int)($_POST['offset'] ?? 0);
    $where  = buildPKWhere($tbl, $pkJson);
    if ($tbl && $where) {
        try {
            $stmt = pdo()->prepare("DELETE FROM `" . addslashes($tbl) . "` WHERE {$where[0]} LIMIT 1");
            $stmt->execute($where[1]);
            $message = 'Row deleted successfully.'; $msgType = 'success';
        } catch (PDOException $e) { $message = 'Delete failed: ' . $e->getMessage(); }
    }
    header("Location: ?action=browse&table=" . urlencode($tbl) . "&offset={$offset}&msg=" . urlencode($message) . "&mt=" . urlencode($msgType)); exit;
}

// SAVE EDIT
if ($action === 'save_edit' && connected() && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $tbl    = $_POST['table']  ?? '';
    $pkJson = $_POST['pk']     ?? '';
    $offset = (int)($_POST['offset'] ?? 0);
    $where  = buildPKWhere($tbl, $pkJson);
    $fields = $_POST['fields'] ?? [];
    if ($tbl && $where && $fields) {
        try {
            $sets = []; $params = [];
            foreach ($fields as $col => $val) {
                $sets[]   = "`" . addslashes($col) . "` = ?";
                $params[] = ($val === '__NULL__') ? null : $val;
            }
            $params = array_merge($params, $where[1]);
            pdo()->prepare("UPDATE `" . addslashes($tbl) . "` SET " . implode(', ', $sets) . " WHERE {$where[0]} LIMIT 1")->execute($params);
            $message = 'Row updated successfully.'; $msgType = 'success';
        } catch (PDOException $e) { $message = 'Update failed: ' . $e->getMessage(); }
    }
    header("Location: ?action=browse&table=" . urlencode($tbl) . "&offset={$offset}&msg=" . urlencode($message) . "&mt=" . urlencode($msgType)); exit;
}

// INSERT ROW
if ($action === 'insert_row' && connected() && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $tbl    = $_POST['table']  ?? '';
    $fields = $_POST['fields'] ?? [];
    if ($tbl && $fields) {
        try {
            $cols = []; $params = [];
            foreach ($fields as $col => $val) {
                if ($val === '__SKIP__') continue;
                $cols[]   = "`" . addslashes($col) . "`";
                $params[] = ($val === '__NULL__') ? null : $val;
            }
            if ($cols) {
                $ph = implode(', ', array_fill(0, count($cols), '?'));
                pdo()->prepare("INSERT INTO `" . addslashes($tbl) . "` (" . implode(', ', $cols) . ") VALUES ({$ph})")->execute($params);
                $message = 'Row inserted successfully.'; $msgType = 'success';
            }
        } catch (PDOException $e) { $message = 'Insert failed: ' . $e->getMessage(); }
    }
    header("Location: ?action=browse&table=" . urlencode($tbl) . "&msg=" . urlencode($message) . "&mt=" . urlencode($msgType)); exit;
}

// RUN SQL
$sqlResult = null; $sqlError = null; $sqlQuery = '';
if ($action === 'sql' && connected() && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $sqlQuery = trim($_POST['query'] ?? '');
    if ($sqlQuery) {
        try {
            $stmt = pdo()->query($sqlQuery);
            if ($stmt->columnCount() > 0) {
                $sqlResult = ['cols' => [], 'rows' => $stmt->fetchAll()];
                if ($sqlResult['rows']) $sqlResult['cols'] = array_keys($sqlResult['rows'][0]);
            } else { $sqlResult = ['affected' => $stmt->rowCount()]; }
        } catch (PDOException $e) { $sqlError = $e->getMessage(); }
    }
}

// ── BUILD PAGE DATA ────────────────────────────────────────────────────────────

$databases = []; $tables = []; $tableData = null; $tableStructure = null; $editRow = null;
$selectedTable = $_GET['table'] ?? '';

if (!$message && isset($_GET['msg'])) { $message = $_GET['msg']; $msgType = $_GET['mt'] ?? 'success'; }

if (connected()) {
    try {
        $db = pdo();
        $databases = $db->query("SHOW DATABASES")->fetchAll(PDO::FETCH_COLUMN);
        if (currentDb()) { $tables = $db->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN); }
        if ($selectedTable && currentDb()) {
            $tableStructure = $db->query("DESCRIBE `" . addslashes($selectedTable) . "`")->fetchAll();
            if ($action === 'browse') {
                $limit  = 50; $offset = (int)($_GET['offset'] ?? 0);
                $total  = $db->query("SELECT COUNT(*) FROM `" . addslashes($selectedTable) . "`")->fetchColumn();
                $rows   = $db->query("SELECT * FROM `" . addslashes($selectedTable) . "` LIMIT {$limit} OFFSET {$offset}")->fetchAll();
                $cols   = $rows ? array_keys($rows[0]) : array_column($tableStructure, 'Field');
                $pks    = getPK($selectedTable);
                $tableData = compact('rows','cols','total','limit','offset','pks');
            }
            if ($action === 'edit_row') {
                $where = buildPKWhere($selectedTable, $_GET['pk'] ?? '');
                if ($where) {
                    $stmt = $db->prepare("SELECT * FROM `" . addslashes($selectedTable) . "` WHERE {$where[0]} LIMIT 1");
                    $stmt->execute($where[1]); $editRow = $stmt->fetch();
                }
            }
        }
    } catch (PDOException $e) {}
}

?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><?= APP_NAME ?></title>
<style>
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Syne:wght@400;700;800&display=swap');
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{--bg:#0d0f14;--surface:#13161e;--border:#1e2330;--accent:#00e5a0;--accent2:#0078ff;
  --text:#d4dbe8;--muted:#5a6380;--danger:#ff4757;--warning:#ffa502;--radius:6px;
  --mono:'JetBrains Mono',monospace;--sans:'Syne',sans-serif}
html,body{height:100%}
body{background:var(--bg);color:var(--text);font-family:var(--sans);font-size:14px}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}

/* LOGIN */
.login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;
  background:radial-gradient(ellipse 80% 60% at 50% -10%,rgba(0,229,160,.12),transparent)}
.login-card{width:420px;background:var(--surface);border:1px solid var(--border);
  border-radius:12px;padding:40px;position:relative;overflow:hidden}
.login-card::before{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(135deg,rgba(0,229,160,.05) 0%,transparent 60%)}
.login-logo{font-size:28px;font-weight:800;letter-spacing:-1px;margin-bottom:6px}
.login-logo span{color:var(--accent)}
.login-sub{color:var(--muted);font-size:12px;margin-bottom:32px;font-family:var(--mono)}

.field{margin-bottom:16px}
.field label{display:block;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.field input,.field textarea{width:100%;padding:10px 14px;background:var(--bg);border:1px solid var(--border);
  border-radius:var(--radius);color:var(--text);font-family:var(--mono);font-size:13px;outline:none;transition:border-color .2s}
.field input:focus,.field textarea:focus{border-color:var(--accent)}
.field textarea{resize:vertical;min-height:80px;line-height:1.5}
.row2{display:grid;grid-template-columns:1fr 80px;gap:12px}

.btn{display:inline-flex;align-items:center;gap:7px;padding:10px 20px;border-radius:var(--radius);
  border:none;font-family:var(--sans);font-weight:700;font-size:13px;cursor:pointer;
  transition:opacity .15s,transform .1s;text-decoration:none;white-space:nowrap}
.btn:active{transform:scale(.97)}
.btn-primary{background:var(--accent);color:#000}.btn-primary:hover{opacity:.88}
.btn-ghost{background:transparent;color:var(--muted);border:1px solid var(--border)}.btn-ghost:hover{border-color:var(--accent);color:var(--accent)}
.btn-danger{background:var(--danger);color:#fff}.btn-danger:hover{opacity:.85}
.btn-warn{background:var(--warning);color:#000}.btn-warn:hover{opacity:.85}
.btn-sm{padding:5px 12px;font-size:12px}
.btn-full{width:100%;justify-content:center;margin-top:8px}

.msg{padding:10px 14px;border-radius:var(--radius);font-size:13px;margin-bottom:18px;transition:opacity .5s}
.msg.error  {background:rgba(255,71,87,.12);border:1px solid rgba(255,71,87,.3);color:#ff6b78}
.msg.success{background:rgba(0,229,160,.10);border:1px solid rgba(0,229,160,.3);color:var(--accent)}

/* SHELL */
.shell{display:grid;grid-template-columns:220px 1fr;grid-template-rows:48px 1fr;min-height:100vh}
.topbar{grid-column:1/-1;background:var(--surface);border-bottom:1px solid var(--border);
  display:flex;align-items:center;padding:0 20px;gap:16px}
.topbar-logo{font-weight:800;font-size:16px;letter-spacing:-.5px}
.topbar-logo span{color:var(--accent)}
.topbar-db{font-family:var(--mono);font-size:11px;padding:3px 10px;
  background:rgba(0,229,160,.08);border:1px solid rgba(0,229,160,.2);border-radius:20px;color:var(--accent)}
.topbar-spacer{flex:1}
.topbar-user{font-family:var(--mono);font-size:12px;color:var(--muted)}
.sidebar{background:var(--surface);border-right:1px solid var(--border);overflow-y:auto;padding:12px 0}
.sidebar-section{padding:8px 14px 4px;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.sidebar-item{display:flex;align-items:center;padding:6px 14px;font-size:13px;color:var(--text);
  transition:background .12s;gap:8px;text-decoration:none}
.sidebar-item:hover,.sidebar-item.active{background:rgba(255,255,255,.05);color:var(--accent)}
.sidebar-item .ico{opacity:.5;font-size:12px}
.main{overflow-y:auto;padding:24px}

/* CARDS */
.card{background:var(--surface);border:1px solid var(--border);border-radius:8px;margin-bottom:16px}
.card-head{padding:14px 18px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.card-title{font-weight:700;font-size:13px;flex:1}
.card-body{padding:18px}

/* DATA TABLE */
.tbl-wrap{overflow-x:auto}
table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:12px}
th{padding:9px 12px;text-align:left;background:rgba(255,255,255,.03);border-bottom:1px solid var(--border);
  font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);white-space:nowrap}
td{padding:7px 12px;border-bottom:1px solid var(--border);max-width:260px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}
tr:last-child td{border-bottom:none}
tr:hover td{background:rgba(255,255,255,.025)}
td.null-val{color:var(--muted);font-style:italic}
th.act-col,td.act-col{white-space:nowrap;width:1%;text-align:center}

.act-btn{display:inline-flex;align-items:center;gap:3px;padding:3px 9px;border-radius:4px;
  font-size:11px;font-family:var(--sans);font-weight:700;cursor:pointer;border:none;
  text-decoration:none;transition:opacity .12s;line-height:1.4}
.act-edit{background:rgba(0,120,255,.2);color:#5ab5ff}.act-edit:hover{background:rgba(0,120,255,.35)}
.act-del {background:rgba(255,71,87,.2);color:#ff6b78}.act-del:hover{background:rgba(255,71,87,.35)}

/* SQL textarea */
textarea.sql{width:100%;height:140px;background:var(--bg);border:1px solid var(--border);
  border-radius:var(--radius);color:var(--text);font-family:var(--mono);font-size:13px;
  padding:12px;resize:vertical;outline:none;line-height:1.6;transition:border-color .2s}
textarea.sql:focus{border-color:var(--accent)}

/* PAGINATION */
.pagination{display:flex;align-items:center;gap:8px;padding:10px 14px;
  font-family:var(--mono);font-size:12px;color:var(--muted);border-top:1px solid var(--border)}

/* DB GRID */
.db-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.db-card{padding:16px;background:var(--bg);border:1px solid var(--border);border-radius:8px;
  cursor:pointer;transition:border-color .15s,background .15s;text-align:center;display:block;text-decoration:none;color:inherit}
.db-card:hover{border-color:var(--accent);background:rgba(0,229,160,.05)}
.db-card .ico-db{font-size:28px;margin-bottom:8px}
.db-card .db-name{font-size:12px;font-family:var(--mono)}

/* STATS */
.stats{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:20px}
.stat-card{padding:16px;background:var(--surface);border:1px solid var(--border);border-radius:8px}
.stat-label{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.stat-val{font-size:26px;font-weight:800;letter-spacing:-1px;margin-top:4px}

.badge{display:inline-block;padding:2px 8px;border-radius:20px;font-size:10px;font-family:var(--mono);font-weight:600;text-decoration:none}
.badge-green{background:rgba(0,229,160,.15);color:var(--accent)}
.badge-blue {background:rgba(0,120,255,.15);color:#4da6ff}
.chip-row{display:flex;gap:6px;flex-wrap:wrap}
.page-title{font-size:20px;font-weight:800;letter-spacing:-.5px;margin-bottom:4px}
.page-sub{font-size:12px;color:var(--muted);font-family:var(--mono);margin-bottom:20px}

/* MODAL */
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.75);
  z-index:9999;align-items:center;justify-content:center;padding:20px}
.modal-overlay.open{display:flex}
.modal{background:var(--surface);border:1px solid var(--border);border-radius:10px;
  width:100%;max-width:640px;max-height:92vh;overflow-y:auto;position:relative;box-shadow:0 20px 60px rgba(0,0,0,.5)}
.modal-head{padding:18px 20px;border-bottom:1px solid var(--border);
  display:flex;align-items:center;justify-content:space-between;position:sticky;top:0;background:var(--surface);z-index:1}
.modal-title{font-weight:800;font-size:15px}
.modal-close{background:none;border:none;color:var(--muted);font-size:22px;cursor:pointer;line-height:1;padding:2px 6px;border-radius:4px}
.modal-close:hover{color:var(--danger);background:rgba(255,71,87,.15)}
.modal-body{padding:20px}
.modal-footer{padding:14px 20px;border-top:1px solid var(--border);display:flex;gap:8px;justify-content:flex-end;
  position:sticky;bottom:0;background:var(--surface)}

/* EDIT / INSERT FORM GRID */
.field-grid{display:grid;gap:10px}
.field-row{display:grid;grid-template-columns:140px 1fr;gap:12px;align-items:start}
.field-col-name{font-family:var(--mono);font-size:12px;color:var(--accent);
  padding-top:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.field-col-name .badges{display:flex;gap:3px;margin-top:3px}
.field-input-wrap{display:flex;flex-direction:column;gap:5px}
.field-input-wrap input,.field-input-wrap textarea{
  width:100%;padding:8px 12px;background:var(--bg);border:1px solid var(--border);
  border-radius:var(--radius);color:var(--text);font-family:var(--mono);font-size:12px;
  outline:none;transition:border-color .2s;line-height:1.5}
.field-input-wrap input:focus,.field-input-wrap textarea:focus{border-color:var(--accent)}
.field-input-wrap input:disabled,.field-input-wrap textarea:disabled{opacity:.35;cursor:not-allowed}
.field-input-wrap textarea{min-height:72px;resize:vertical}
.null-check{display:inline-flex;align-items:center;gap:5px;font-size:11px;color:var(--muted);cursor:pointer;user-select:none}
.null-check input[type=checkbox]{accent-color:var(--accent);width:13px;height:13px}

/* delete confirm */
.del-preview{font-family:var(--mono);font-size:12px;background:var(--bg);
  border:1px solid var(--border);border-radius:var(--radius);padding:12px;
  margin:12px 0;max-height:160px;overflow-y:auto;white-space:pre-wrap;word-break:break-all;color:var(--text)}
</style>
</head>
<body>

<?php if (!connected() || $action === 'login'): ?>
<!-- ══════════════════════════ LOGIN ══════════════════════════ -->
<div class="login-wrap">
  <div class="login-card">
    <div class="login-logo">Mini<span>Admin</span></div>
    <div class="login-sub">MySQL manager · v<?= VERSION ?></div>
    <?php if ($message): ?><div class="msg error"><?= h($message) ?></div><?php endif; ?>
    <form method="post" action="?action=connect">
      <div class="row2">
        <div class="field"><label>Host</label>
          <input name="host" value="<?= h($_POST['host'] ?? 'localhost') ?>" placeholder="localhost"></div>
        <div class="field"><label>Port</label>
          <input name="port" value="<?= h($_POST['port'] ?? '3306') ?>" placeholder="3306"></div>
      </div>
      <div class="field"><label>Username</label>
        <input name="user" value="<?= h($_POST['user'] ?? '') ?>" autocomplete="username"></div>
      <div class="field"><label>Password</label>
        <input type="password" name="pass" placeholder="••••••••" autocomplete="current-password"></div>
      <div class="field"><label>Database <span style="font-weight:400;color:var(--muted)">(optional)</span></label>
        <input name="db" value="<?= h($_POST['db'] ?? '') ?>" placeholder="my_database"></div>
      <button type="submit" class="btn btn-primary btn-full">Connect →</button>
    </form>
  </div>
</div>

<?php else: ?>
<!-- ══════════════════════════ SHELL ══════════════════════════ -->
<div class="shell">

  <header class="topbar">
    <div class="topbar-logo">Mini<span>Admin</span></div>
    <?php if (currentDb()): ?>
      <div class="topbar-db"><?= h(currentDb()) ?></div>
    <?php endif; ?>
    <div class="topbar-spacer"></div>
    <div class="topbar-user"><?= h($_SESSION['db_conn_params']['user']) ?>@<?= h($_SESSION['db_conn_params']['host']) ?></div>
    <a href="?action=logout" class="btn btn-ghost" style="padding:5px 12px;font-size:12px">Logout</a>
  </header>

  <nav class="sidebar">
    <div class="sidebar-section">Navigation</div>
    <a class="sidebar-item <?= $action==='home'?'active':'' ?>" href="?action=home"><span class="ico">⬡</span> Home</a>
    <a class="sidebar-item <?= $action==='databases'?'active':'' ?>" href="?action=databases"><span class="ico">◈</span> Databases</a>
    <a class="sidebar-item <?= $action==='sql'?'active':'' ?>" href="?action=sql"><span class="ico">❯</span> SQL Query</a>
    <?php if (currentDb() && $tables): ?>
      <div class="sidebar-section" style="margin-top:8px">Tables</div>
      <?php foreach ($tables as $tbl): ?>
        <a class="sidebar-item <?= ($selectedTable===$tbl&&in_array($action,['browse','structure','edit_row']))?'active':'' ?>"
           href="?action=browse&table=<?= urlencode($tbl) ?>">
          <span class="ico">▤</span> <?= h($tbl) ?>
        </a>
      <?php endforeach; ?>
    <?php endif; ?>
  </nav>

  <main class="main">

  <?php if ($message && $action !== 'login'): ?>
    <div class="msg <?= h($msgType) ?>" id="flashMsg"><?= $msgType==='success'?'✓ ':'' ?><?= h($message) ?></div>
  <?php endif; ?>

  <?php
  // ══ HOME ════════════════════════════════════════════════════
  if ($action === 'home'):
    $db2 = pdo(); $ver = $db2->query("SELECT VERSION()")->fetchColumn();
  ?>
    <div class="page-title">Dashboard</div>
    <div class="page-sub">Connected and ready.</div>
    <div class="stats">
      <div class="stat-card"><div class="stat-label">MySQL</div>
        <div class="stat-val" style="font-size:14px;margin-top:6px;font-family:var(--mono)"><?= h($ver) ?></div></div>
      <div class="stat-card"><div class="stat-label">Databases</div>
        <div class="stat-val"><?= count($databases) ?></div></div>
      <div class="stat-card"><div class="stat-label">Tables</div>
        <div class="stat-val"><?= currentDb()?count($tables):'—' ?></div></div>
    </div>
    <?php if (currentDb() && $tables): ?>
    <div class="card">
      <div class="card-head"><div class="card-title">Tables in <span style="color:var(--accent)"><?= h(currentDb()) ?></span></div></div>
      <div class="card-body" style="padding:0"><div class="tbl-wrap"><table>
        <tr><th>Table</th><th>Rows</th><th>Actions</th></tr>
        <?php foreach ($tables as $tbl):
          try { $cnt = $db2->query("SELECT COUNT(*) FROM `".addslashes($tbl)."`")->fetchColumn(); } catch(Exception $e){$cnt='?';}
        ?>
        <tr>
          <td><a href="?action=browse&table=<?= urlencode($tbl) ?>"><?= h($tbl) ?></a></td>
          <td><?= number_format($cnt) ?></td>
          <td style="white-space:nowrap">
            <a href="?action=browse&table=<?= urlencode($tbl) ?>"    class="badge badge-green">Browse</a>
            <a href="?action=structure&table=<?= urlencode($tbl) ?>" class="badge badge-blue" style="margin-left:5px">Structure</a>
          </td>
        </tr>
        <?php endforeach; ?>
      </table></div></div>
    </div>
    <?php endif; ?>

  <?php
  // ══ DATABASES ══════════════════════════════════════════════
  elseif ($action === 'databases'):
  ?>
    <div class="page-title">Databases</div>
    <div class="page-sub"><?= count($databases) ?> found</div>
    <div class="db-grid">
      <?php foreach ($databases as $d): ?>
        <a href="?action=use_db&db=<?= urlencode($d) ?>" class="db-card">
          <div class="ico-db">🗄</div>
          <div class="db-name"><?= h($d) ?></div>
        </a>
      <?php endforeach; ?>
    </div>

  <?php
  // ══ SQL ════════════════════════════════════════════════════
  elseif ($action === 'sql'):
  ?>
    <div class="page-title">SQL Query</div>
    <div class="page-sub">Run raw SQL against <?= currentDb()?h(currentDb()):'server' ?></div>
    <div class="card"><div class="card-body">
      <form method="post" action="?action=sql">
        <textarea class="sql" name="query" placeholder="SELECT * FROM users LIMIT 10;"><?= h($sqlQuery) ?></textarea>
        <div style="display:flex;gap:8px;margin-top:10px">
          <button class="btn btn-primary" type="submit">▶ Run</button>
          <button class="btn btn-ghost" type="reset">Clear</button>
        </div>
      </form>
    </div></div>
    <?php if ($sqlError): ?>
      <div class="msg error"><?= h($sqlError) ?></div>
    <?php elseif ($sqlResult !== null): ?>
      <?php if (isset($sqlResult['affected'])): ?>
        <div class="msg success">✓ Query OK — <?= $sqlResult['affected'] ?> row(s) affected.</div>
      <?php else: ?>
        <div class="card">
          <div class="card-head"><div class="card-title">Result <span style="color:var(--muted);font-size:12px;font-weight:400"><?= count($sqlResult['rows']) ?> rows</span></div></div>
          <div class="card-body" style="padding:0"><div class="tbl-wrap"><table>
            <tr><?php foreach ($sqlResult['cols'] as $c): ?><th><?= h($c) ?></th><?php endforeach; ?></tr>
            <?php foreach ($sqlResult['rows'] as $row): ?><tr>
              <?php foreach ($row as $val): ?>
                <td class="<?= $val===null?'null-val':'' ?>"><?= $val===null?'NULL':h($val) ?></td>
              <?php endforeach; ?>
            </tr><?php endforeach; ?>
          </table></div></div>
        </div>
      <?php endif; ?>
    <?php endif; ?>

  <?php
  // ══ EDIT ROW ═══════════════════════════════════════════════
  elseif ($action === 'edit_row' && $selectedTable && $editRow):
    $pkJson = $_GET['pk'] ?? '';
    $offset = (int)($_GET['offset'] ?? 0);
  ?>
    <div class="page-title">Edit Row</div>
    <div class="page-sub"><?= h($selectedTable) ?> &nbsp;·&nbsp; <a href="?action=browse&table=<?= urlencode($selectedTable) ?>&offset=<?= $offset ?>">← back to browse</a></div>
    <div class="card"><div class="card-head"><div class="card-title">Editing record</div></div>
    <div class="card-body">
      <form method="post" action="?action=save_edit">
        <input type="hidden" name="table"  value="<?= h($selectedTable) ?>">
        <input type="hidden" name="pk"     value="<?= h($pkJson) ?>">
        <input type="hidden" name="offset" value="<?= $offset ?>">
        <div class="field-grid">
          <?php foreach ($tableStructure as $col):
            $fname  = $col['Field'];
            $ftype  = strtolower($col['Type']);
            $isAuto = stripos($col['Extra'],'auto_increment') !== false;
            $isLong = strpos($ftype,'text')!==false || strpos($ftype,'blob')!==false;
            $isPK   = $col['Key'] === 'PRI';
            $canNull= $col['Null'] === 'YES';
            $val    = $editRow[$fname];
            $isNull = ($val === null);
            $uid    = 'ef_' . preg_replace('/[^a-z0-9]/i','_',$fname);
          ?>
          <div class="field-row">
            <div class="field-col-name">
              <?= h($fname) ?>
              <div class="badges">
                <?php if($isPK)   echo '<span class="badge badge-green" style="font-size:9px">PK</span>'; ?>
                <?php if($isAuto) echo '<span class="badge badge-blue"  style="font-size:9px">AUTO</span>'; ?>
              </div>
            </div>
            <div class="field-input-wrap">
              <?php if ($isAuto): ?>
                <input type="text" value="<?= h($val) ?>" disabled>
                <input type="hidden" name="fields[<?= h($fname) ?>]" value="<?= h($val) ?>">
              <?php elseif ($isLong): ?>
                <textarea name="fields[<?= h($fname) ?>]" id="<?= $uid ?>"
                  rows="4" <?= $isNull?'disabled':'' ?>><?= $isNull?'':h($val) ?></textarea>
                <?php if ($canNull): ?>
                  <label class="null-check">
                    <input type="checkbox" onchange="toggleNull(this,'<?= $uid ?>')" <?= $isNull?'checked':'' ?>>
                    SET NULL
                  </label>
                  <?php if ($isNull): ?><input type="hidden" name="fields[<?= h($fname) ?>]" value="__NULL__"><?php endif; ?>
                <?php endif; ?>
              <?php else: ?>
                <input type="text" name="fields[<?= h($fname) ?>]" id="<?= $uid ?>"
                  value="<?= $isNull?'':h($val) ?>" <?= $isNull?'disabled':'' ?>>
                <?php if ($canNull): ?>
                  <label class="null-check">
                    <input type="checkbox" onchange="toggleNull(this,'<?= $uid ?>')" <?= $isNull?'checked':'' ?>>
                    SET NULL
                  </label>
                  <?php if ($isNull): ?><input type="hidden" name="fields[<?= h($fname) ?>]" value="__NULL__"><?php endif; ?>
                <?php endif; ?>
              <?php endif; ?>
            </div>
          </div>
          <?php endforeach; ?>
        </div>
        <div style="display:flex;gap:10px;margin-top:22px">
          <button type="submit" class="btn btn-primary">💾 Save Changes</button>
          <a href="?action=browse&table=<?= urlencode($selectedTable) ?>&offset=<?= $offset ?>" class="btn btn-ghost">Cancel</a>
        </div>
      </form>
    </div></div>

  <?php
  // ══ BROWSE / STRUCTURE ════════════════════════════════════
  elseif (in_array($action, ['browse','structure']) && $selectedTable):
    $offset = (int)($_GET['offset'] ?? 0);
  ?>
    <div class="page-title"><?= h($selectedTable) ?></div>
    <div class="page-sub" style="margin-bottom:12px">
      <div class="chip-row">
        <a href="?action=browse&table=<?= urlencode($selectedTable) ?>"    class="badge <?= $action==='browse'?'badge-green':'badge-blue' ?>">Browse</a>
        <a href="?action=structure&table=<?= urlencode($selectedTable) ?>" class="badge <?= $action==='structure'?'badge-green':'badge-blue' ?>">Structure</a>
      </div>
    </div>

    <?php if ($action === 'structure' && $tableStructure): ?>
    <div class="card"><div class="card-body" style="padding:0"><div class="tbl-wrap"><table>
      <tr><th>Field</th><th>Type</th><th>Null</th><th>Key</th><th>Default</th><th>Extra</th></tr>
      <?php foreach ($tableStructure as $col): ?>
      <tr>
        <td style="color:var(--accent);font-weight:600"><?= h($col['Field']) ?></td>
        <td><?= h($col['Type']) ?></td><td><?= h($col['Null']) ?></td>
        <td><?php if($col['Key']==='PRI') echo '<span class="badge badge-green">PRI</span>';
                 elseif($col['Key']) echo '<span class="badge badge-blue">'.h($col['Key']).'</span>'; ?></td>
        <td class="<?= $col['Default']===null?'null-val':'' ?>"><?= $col['Default']===null?'NULL':h($col['Default']) ?></td>
        <td><?= h($col['Extra']) ?></td>
      </tr>
      <?php endforeach; ?>
    </table></div></div></div>

    <?php elseif ($action === 'browse' && $tableData): ?>
    <?php $pks = $tableData['pks']; $hasPK = count($pks) > 0; ?>

    <div style="margin-bottom:14px;display:flex;align-items:center;gap:10px">
      <button class="btn btn-primary btn-sm" onclick="openInsertModal()">+ Insert Row</button>
      <?php if (!$hasPK): ?>
        <span style="font-size:11px;color:var(--warning)">⚠ No primary key detected — Edit/Delete unavailable</span>
      <?php endif; ?>
    </div>

    <div class="card">
      <div class="card-head">
        <div class="card-title">Rows <span style="color:var(--muted);font-size:12px;font-weight:400"><?= number_format($tableData['total']) ?> total</span></div>
      </div>
      <div class="card-body" style="padding:0">
        <div class="tbl-wrap">
        <?php if ($tableData['rows']): ?>
        <table>
          <tr>
            <?php if ($hasPK): ?><th class="act-col">Actions</th><?php endif; ?>
            <?php foreach ($tableData['cols'] as $c): ?><th><?= h($c) ?></th><?php endforeach; ?>
          </tr>
          <?php foreach ($tableData['rows'] as $row):
            $pkVals = []; foreach ($pks as $pk) $pkVals[$pk] = $row[$pk];
            $pkJson = json_encode($pkVals);
          ?>
          <tr>
            <?php if ($hasPK): ?>
            <td class="act-col">
              <a href="?action=edit_row&table=<?= urlencode($selectedTable) ?>&pk=<?= urlencode($pkJson) ?>&offset=<?= $offset ?>"
                 class="act-btn act-edit" title="Edit row">✎ Edit</a>
              <button class="act-btn act-del" style="margin-left:4px"
                onclick="openDeleteModal(<?= h(json_encode($pkJson)) ?>, <?= h(json_encode($pkVals)) ?>)"
                title="Delete row">✕ Delete</button>
            </td>
            <?php endif; ?>
            <?php foreach ($row as $val): ?>
              <td class="<?= $val===null?'null-val':'' ?>" title="<?= $val===null?'NULL':h($val) ?>">
                <?= $val===null?'NULL':h($val) ?>
              </td>
            <?php endforeach; ?>
          </tr>
          <?php endforeach; ?>
        </table>
        <?php else: ?>
          <div style="padding:28px;color:var(--muted);text-align:center">
            Table is empty.
            <button class="btn btn-primary btn-sm" onclick="openInsertModal()" style="margin-left:10px">+ Insert Row</button>
          </div>
        <?php endif; ?>
        </div>

        <?php $lim=$tableData['limit'];$tot=$tableData['total'];$off=$tableData['offset']; ?>
        <?php if ($tot > $lim): ?>
        <div class="pagination">
          <?php if ($off > 0): ?>
            <a href="?action=browse&table=<?= urlencode($selectedTable) ?>&offset=<?= max(0,$off-$lim) ?>" class="btn btn-ghost" style="padding:4px 10px;font-size:12px">← Prev</a>
          <?php endif; ?>
          <span>Rows <?= $off+1 ?>–<?= min($off+$lim,$tot) ?> of <?= number_format($tot) ?></span>
          <?php if ($off+$lim < $tot): ?>
            <a href="?action=browse&table=<?= urlencode($selectedTable) ?>&offset=<?= $off+$lim ?>" class="btn btn-ghost" style="padding:4px 10px;font-size:12px">Next →</a>
          <?php endif; ?>
        </div>
        <?php endif; ?>
      </div>
    </div>

    <!-- ════════ DELETE MODAL ════════ -->
    <div class="modal-overlay" id="deleteModal">
      <div class="modal">
        <div class="modal-head">
          <div class="modal-title" style="color:var(--danger)">⚠ Confirm Delete</div>
          <button class="modal-close" onclick="closeModal('deleteModal')">×</button>
        </div>
        <div class="modal-body">
          <p style="color:var(--text)">Are you sure you want to <strong>permanently delete</strong> this row? This cannot be undone.</p>
          <div class="del-preview" id="delPreview"></div>
        </div>
        <div class="modal-footer">
          <form method="post" action="?action=delete_row">
            <input type="hidden" name="table"  value="<?= h($selectedTable) ?>">
            <input type="hidden" name="offset" value="<?= $offset ?>">
            <input type="hidden" name="pk"     id="delPKInput">
            <div style="display:flex;gap:8px">
              <button type="button" class="btn btn-ghost" onclick="closeModal('deleteModal')">Cancel</button>
              <button type="submit" class="btn btn-danger">Yes, Delete Row</button>
            </div>
          </form>
        </div>
      </div>
    </div>

    <!-- ════════ INSERT MODAL ════════ -->
    <div class="modal-overlay" id="insertModal">
      <div class="modal">
        <div class="modal-head">
          <div class="modal-title">+ Insert Row — <span style="color:var(--accent)"><?= h($selectedTable) ?></span></div>
          <button class="modal-close" onclick="closeModal('insertModal')">×</button>
        </div>
        <form method="post" action="?action=insert_row">
          <input type="hidden" name="table" value="<?= h($selectedTable) ?>">
          <div class="modal-body">
            <div class="field-grid">
              <?php foreach ($tableStructure as $col):
                $fname  = $col['Field'];
                $ftype  = strtolower($col['Type']);
                $isAuto = stripos($col['Extra'],'auto_increment') !== false;
                $isLong = strpos($ftype,'text')!==false || strpos($ftype,'blob')!==false;
                $isPK   = $col['Key'] === 'PRI';
                $canNull= $col['Null'] === 'YES';
                $dval   = $col['Default'] ?? '';
                $uid    = 'if_' . preg_replace('/[^a-z0-9]/i','_',$fname);
              ?>
              <div class="field-row">
                <div class="field-col-name">
                  <?= h($fname) ?>
                  <div class="badges">
                    <?php if($isPK)   echo '<span class="badge badge-green" style="font-size:9px">PK</span>'; ?>
                    <?php if($isAuto) echo '<span class="badge badge-blue"  style="font-size:9px">AUTO</span>'; ?>
                  </div>
                </div>
                <div class="field-input-wrap">
                  <?php if ($isAuto): ?>
                    <input type="text" value="AUTO_INCREMENT" disabled>
                    <input type="hidden" name="fields[<?= h($fname) ?>]" value="__SKIP__">
                  <?php elseif ($isLong): ?>
                    <textarea name="fields[<?= h($fname) ?>]" id="<?= $uid ?>" rows="3"><?= h($dval) ?></textarea>
                    <?php if ($canNull): ?>
                      <label class="null-check"><input type="checkbox" onchange="toggleNull(this,'<?= $uid ?>')"> SET NULL</label>
                    <?php endif; ?>
                  <?php else: ?>
                    <input type="text" name="fields[<?= h($fname) ?>]" id="<?= $uid ?>" value="<?= h($dval) ?>">
                    <?php if ($canNull): ?>
                      <label class="null-check"><input type="checkbox" onchange="toggleNull(this,'<?= $uid ?>')"> SET NULL</label>
                    <?php endif; ?>
                  <?php endif; ?>
                </div>
              </div>
              <?php endforeach; ?>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-ghost" onclick="closeModal('insertModal')">Cancel</button>
            <button type="submit" class="btn btn-primary">Insert Row</button>
          </div>
        </form>
      </div>
    </div>

    <?php endif; /* browse/structure */ ?>
  <?php endif; /* action routing */ ?>

  </main>
</div><!-- .shell -->
<?php endif; /* connected */ ?>

<script>
// NULL toggle for edit/insert forms
function toggleNull(cb, uid) {
  const el = document.getElementById(uid);
  if (!el) return;
  const hiddenId = 'nullhid_' + uid;
  if (cb.checked) {
    el.disabled = true;
    let h = document.getElementById(hiddenId);
    if (!h) {
      h = document.createElement('input');
      h.type = 'hidden'; h.id = hiddenId;
      h.name = el.name; h.value = '__NULL__';
      el.parentNode.appendChild(h);
    }
    el.dataset.origName = el.name;
    el.name = '';
  } else {
    el.disabled = false;
    const h = document.getElementById(hiddenId);
    if (h) { el.name = h.name; h.remove(); }
    else if (el.dataset.origName) el.name = el.dataset.origName;
    el.value = '';
  }
}

// Modal helpers
function closeModal(id) {
  document.getElementById(id).classList.remove('open');
}
function openModal(id) {
  document.getElementById(id).classList.add('open');
}

// Close on overlay click
document.addEventListener('click', function(e) {
  if (e.target.classList.contains('modal-overlay')) {
    e.target.classList.remove('open');
  }
});
// Close on Escape
document.addEventListener('keydown', function(e) {
  if (e.key === 'Escape') document.querySelectorAll('.modal-overlay.open').forEach(m => m.classList.remove('open'));
});

// Delete modal
function openDeleteModal(pkJson, pkVals) {
  document.getElementById('delPKInput').value = pkJson;
  let txt = '';
  for (const [k, v] of Object.entries(pkVals)) txt += k + ' = ' + v + '\n';
  document.getElementById('delPreview').textContent = txt.trim();
  openModal('deleteModal');
}

// Insert modal
function openInsertModal() { openModal('insertModal'); }

// Auto-fade success messages
const flash = document.getElementById('flashMsg');
if (flash && flash.classList.contains('success')) {
  setTimeout(() => { flash.style.transition='opacity 1s'; flash.style.opacity='0'; }, 3000);
  setTimeout(() => { flash.remove(); }, 4200);
}
</script>
</body>
</html>