при выполнении команды INSERT INTO table_name (field1, field2) VALUES (value1, value2); не сахраняються  значения value1, value2 // app.js
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs').promises; // Используем асинхронные функции
const path = require('path');
const { GPU } = require('gpu.js');
const session = require('express-session');
const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');

// Инициализация GPU.js
const gpu = new GPU();

// Константы для путей и параметров
const PORT = 3000;
const BD_DIR = path.join(__dirname, 'BD');
const USERS_FILE = path.join(BD_DIR, 'users.json');
const SALT_ROUNDS = 10;

// Инициализация Express приложения
const app = express();

// Настройка промежуточного ПО
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));

// Настройка сессий
app.use(session({
  secret: 'your-secret-key', // Замените на ваш секрет
  resave: false,
  saveUninitialized: false,
  cookie: { secure: false } // Для разработки; в продакшене установите secure: true
}));

// Функция для рендеринга HTML страниц с добавлением стилей и анимаций
function renderPage(res, title, content) {
  const html = `
  <!DOCTYPE html>
  <html lang="ru">
  <head>
    <meta charset="UTF-8">
    <title>${title}</title>
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <!-- Animate.css for animations -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>
    <style>
      body {
        padding-top: 70px;
        background-color: #f0f2f5;
        font-family: 'Roboto', sans-serif;
      }
      .table-actions {
        display: flex;
        gap: 5px;
      }
      /* Стиль для консоли */
      #command-console {
        width: 100%;
        height: 200px;
      }
      #command-result {
        white-space: pre-wrap;
        background-color: #ffffff;
        padding: 15px;
        border: 1px solid #ced4da;
        border-radius: 4px;
        height: 200px;
        overflow-y: scroll;
        box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
      }
      /* Кастомные стили */
      .navbar-brand {
        font-weight: bold;
        font-size: 1.5rem;
        animation: fadeInDown 1s;
      }
      table {
        animation: fadeIn 1s;
      }
      .btn-primary {
        transition: background-color 0.3s, transform 0.3s;
      }
      .btn-primary:hover {
        background-color: #0056b3;
        transform: scale(1.05);
      }
      .btn-success, .btn-danger, .btn-secondary {
        transition: transform 0.3s;
      }
      .btn-success:hover, .btn-danger:hover, .btn-secondary:hover {
        transform: scale(1.05);
      }
      /* Анимации для содержимого контейнера */
      .container {
        animation: fadeInUp 1s;
      }
      /* Ховеры для строк таблицы */
      table tbody tr:hover {
        background-color: #f1f1f1;
        transition: background-color 0.3s;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top animate__animated animate__fadeInDown">
      <a class="navbar-brand" href="/">Custom DB Manager</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" 
              aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      ${title !== 'Вход' && title !== 'Регистрация' ? `
      <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item ${title === 'Список Таблиц' ? 'active' : ''}">
            <a class="nav-link" href="/">Таблицы</a>
          </li>
          <li class="nav-item ${title === 'Создать Таблицу' ? 'active' : ''}">
            <a class="nav-link" href="/create-table">Создать Таблицу</a>
          </li>
          <li class="nav-item ${title === 'Выполнить Команду' ? 'active' : ''}">
            <a class="nav-link" href="/execute-command">Выполнить Команду</a>
          </li>
        </ul>
        <span class="navbar-text mr-3">
          Привет, ${app.locals.currentUser || 'Гость'}!
        </span>
        <a href="/logout" class="btn btn-outline-light">Выйти</a>
      </div>
      ` : ''}
    </nav>
    <div class="container mt-4 animate__animated animate__fadeInUp">
      ${content}
    </div>
    <!-- Bootstrap JS и зависимости -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <!-- Дополнительные скрипты для анимаций -->
    <script>
      // Пример анимации при загрузке страницы
      document.addEventListener('DOMContentLoaded', () => {
        const elements = document.querySelectorAll('.animate-on-load');
        elements.forEach(el => {
          el.classList.add('animate__animated', 'animate__fadeIn');
        });
      });
    </script>
  </body>
  </html>
  `;
  res.send(html);
}

// -----------------------------------------------------------------------------------
// Вспомогательные функции
// -----------------------------------------------------------------------------------

// Функция экранирования HTML
function escapeHTML(str) {
  if (typeof str !== 'string') return str;
  return str.replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#039;');
}

// Функция для загрузки пользователей из файла
async function loadUsers() {
  try {
    const data = await fs.readFile(USERS_FILE, 'utf8');
    return JSON.parse(data);
  } catch (err) {
    if (err.code === 'ENOENT') {
      await fs.mkdir(BD_DIR, { recursive: true });
      await fs.writeFile(USERS_FILE, JSON.stringify([]), 'utf8');
      return [];
    } else {
      throw err;
    }
  }
}

// Функция для сохранения пользователей в файл
async function saveUsers(users) {
  await fs.writeFile(USERS_FILE, JSON.stringify(users, null, 2), 'utf8');
  console.log(`Пользователи сохранены в ${USERS_FILE}`);
}

// Функция поиска пользователя по имени
function findUser(users, username) {
  return users.find(user => user.username === username);
}

// Функция поиска пользователя по токену
function findUserByToken(users, token) {
  return users.find(user => user.token === token);
}

// -----------------------------------------------------------------------------------
// Классы Table и Database
// -----------------------------------------------------------------------------------

// Класс Table для управления таблицами
class Table {
  constructor(name, schema, autoIncrement = false) {
    this.name = name;
    this.schema = schema;
    this.autoIncrement = autoIncrement;
    this.autoIncrementValue = 1;

    // Инициализация колонок
    this.columns = {};
    for (let field in schema) {
      this.columns[field] = []; // Можно использовать Typed Arrays для чисел
    }
  }

  // Метод для вставки записи
  insert(record) {
    if (this.autoIncrement) {
      record.id = this.autoIncrementValue++;
    } else {
      if (record.id === undefined || record.id === null) {
        throw new Error('Поле "id" обязательно для вставки записи.');
      }
      const id = record.id;
      if (this.columns['id'].includes(id)) {
        throw new Error(`Запись с id=${id} уже существует.`);
      }
    }

    for (let field in this.schema) {
      if (this.autoIncrement && field === 'id') {
        this.columns[field].push(record[field]);
      } else {
        this.columns[field].push(
          record[field] !== undefined ? record[field] : (this.schema[field] === 'number' ? 0 : '')
        );
      }
    }
  }

  // Метод для удаления записи по id
  deleteRecord(id) {
    const ids = this.columns['id'];
    const index = ids.indexOf(id);
    if (index !== -1) {
      for (let field in this.columns) {
        this.columns[field].splice(index, 1);
      }
      return true;
    }
    return false;
  }

  // Метод для обновления записи по id
  updateRecord(id, newRecord) {
    const ids = this.columns['id'];
    const index = ids.indexOf(id);
    if (index !== -1) {
      for (let field in newRecord) {
        if (this.schema[field]) {
          if (field === 'id' && this.autoIncrement) {
            continue;
          }
          this.columns[field][index] = newRecord[field];
        }
      }
      return true;
    }
    return false;
  }

  // Метод для получения записи по id с использованием GPU
  getGPU(id) {
    if (this.schema['id'] !== 'number') {
      throw new Error('GPU-поиск поддерживается только для числовых id.');
    }

    const ids = this.columns['id'];
    const recordLength = ids.length;

    const idArray = new Float32Array(ids);

    const findIndexGPU = gpu.createKernel(function(idArray, targetId) {
      let index = -1;
      for (let i = 0; i < this.constants.size; i++) {
        if (idArray[i] === targetId) {
          index = i;
          break;
        }
      }
      return index;
    })
      .setOutput([1])
      .setConstants({ size: recordLength });

    const index = findIndexGPU(idArray, id)[0];

    if (index === -1) return null;

    const record = {};
    for (let field in this.columns) {
      record[field] = this.columns[field][index];
    }
    return record;
  }

  getRecord(id) {
    return this.getGPU(id);
  }

  getAll() {
    const recordLength = this.columns['id'].length;
    const records = [];
    for (let i = 0; i < recordLength; i++) {
      const record = {};
      for (let field in this.columns) {
        record[field] = this.columns[field][i];
      }
      records.push(record);
    }
    return records;
  }

  // Добавление новой колонки
  addColumn(columnName, columnType) {
    if (this.schema[columnName]) {
      throw new Error(`Колонка "${columnName}" уже существует.`);
    }
    if (!['number', 'string'].includes(columnType.toLowerCase())) {
      throw new Error('Поддерживаются только типы "number" и "string".');
    }
    this.schema[columnName] = columnType.toLowerCase();
    this.columns[columnName] = this.columns['id'].map(() => (columnType.toLowerCase() === 'number' ? 0 : ''));
  }

  // Удаление колонки
  deleteColumn(columnName) {
    if (!this.schema[columnName]) {
      throw new Error(`Колонка "${columnName}" не найдена.`);
    }
    if (columnName === 'id') {
      throw new Error('Невозможно удалить обязательную колонку "id".');
    }
    delete this.schema[columnName];
    delete this.columns[columnName];
  }
}

// Класс Database с автоматическим сохранением после каждой модификации
class Database {
  constructor(filePath) {
    this.tables = new Map();
    this.filePath = filePath;
    this.isDirty = false; // Флаг изменений для кэширования
    this.saveInterval = 5000; // Сохранение каждые 5 секунд, если есть изменения

    // Запускаем периодическое сохранение
    this.autoSave = setInterval(() => {
      if (this.isDirty) {
        this.saveToFile();
        this.isDirty = false;
      }
    }, this.saveInterval);
  }

  async createTable(tableName, schema, autoIncrement = false) {
    if (this.tables.has(tableName)) {
      throw new Error(`Таблица "${tableName}" уже существует.`);
    }
    const table = new Table(tableName, schema, autoIncrement);
    if (autoIncrement) {
      const ids = table.columns['id'];
      table.autoIncrementValue = ids.length > 0 ? Math.max(...ids) + 1 : 1;
    }
    this.tables.set(tableName, table);
    this.isDirty = true;
  }

  async dropTable(tableName) {
    if (this.tables.delete(tableName)) {
      this.isDirty = true;
      return true;
    }
    return false;
  }

  async insert(tableName, record) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    table.insert(record);
    this.isDirty = true;
  }

  async deleteRecord(tableName, id) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    const result = table.deleteRecord(id);
    if (result) {
      this.isDirty = true;
    }
    return result;
  }

  async updateRecord(tableName, id, newRecord) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    const result = table.updateRecord(id, newRecord);
    if (result) {
      this.isDirty = true;
    }
    return result;
  }

  async getRecord(tableName, id) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.getRecord(id);
  }

  async getAll(tableName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.getAll();
  }

  async getTables() {
    return Array.from(this.tables.keys());
  }

  async getTableSchema(tableName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.schema;
  }

  async getTableAutoIncrement(tableName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    return table.autoIncrement;
  }

  async addColumn(tableName, columnName, columnType) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    table.addColumn(columnName, columnType);
    this.isDirty = true;
  }

  async deleteColumn(tableName, columnName) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }
    table.deleteColumn(columnName);
    this.isDirty = true;
  }

  // Сохранение базы данных в файл
  async saveToFile() {
    try {
      const data = {};
      this.tables.forEach((table, name) => {
        data[name] = {
          schema: table.schema,
          columns: table.columns,
          autoIncrement: table.autoIncrement,
          autoIncrementValue: table.autoIncrementValue
        };
      });
      await fs.writeFile(this.filePath, JSON.stringify(data, null, 2), 'utf8');
      console.log(`Данные сохранены в ${this.filePath}`);
    } catch (err) {
      console.error(`Ошибка сохранения данных: ${err.message}`);
    }
  }

  // Загрузка базы данных из файла
  async loadFromFile() {
    try {
      const rawData = await fs.readFile(this.filePath, 'utf8');
      const data = JSON.parse(rawData);
      for (const tableName in data) {
        const tableData = data[tableName];
        const table = new Table(tableName, tableData.schema, tableData.autoIncrement);
        table.columns = tableData.columns;
        table.autoIncrementValue = tableData.autoIncrementValue || 1;
        this.tables.set(tableName, table);
      }
      console.log(`Данные загружены из ${this.filePath}`);
    } catch (err) {
      if (err.code === 'ENOENT') {
        console.log(`Файл ${this.filePath} не найден. Начинается с пустой базы данных.`);
        await fs.writeFile(this.filePath, JSON.stringify({ tables: {} }, null, 2), 'utf8');
      } else {
        throw err;
      }
    }
  }

  // Метод для выполнения SQL-подобной команды
  async executeSQLCommand(command) {
    const parsed = parseSQL(command);
    if (!parsed) {
      throw new Error('Некорректная команда.');
    }

    const { type } = parsed;

    switch (type.toUpperCase()) {
      case 'SELECT':
        if (parsed.type === 'JOIN') {
          return this.selectQuery(parsed.table1, parsed.fields, parsed.where, parsed.order, parsed);
        }
        return this.selectQuery(parsed.tableName, parsed.fields, parsed.where, parsed.order);
      case 'INSERT':
        await this.insert(parsed.tableName, parsed.values);
        return { inserted: 1 };
      case 'UPDATE':
        const updated = await this.updateRecord(parsed.tableName, parsed.where.id, parsed.fields);
        return { updated: updated ? 1 : 0 };
      case 'DELETE':
        const deleted = await this.deleteRecord(parsed.tableName, parsed.where.id);
        return { deleted: deleted ? 1 : 0 };
      default:
        throw new Error(`Неизвестный тип команды "${type}".`);
    }
  }

  // Методы для поддержки SQL-команд

  selectQuery(tableName, selectedFields = ['*'], where = null, order = null, join = null) {
    const table = this.tables.get(tableName);
    if (!table) {
      throw new Error(`Таблица "${tableName}" не найдена.`);
    }

    let records = table.getAll();

    // Если есть JOIN
    if (join) {
      const joinTable = this.tables.get(join.table2);
      if (!joinTable) {
        throw new Error(`Таблица для JOIN "${join.table2}" не найдена.`);
      }

      const [leftField] = join.joinCondition.left.split('.');
      const [rightField] = join.joinCondition.right.split('.');

      const joinRecords = joinTable.getAll();

      // Выполнение INNER JOIN
      records = records.flatMap(record1 => {
        return joinRecords.filter(record2 => record1[leftField] === record2[rightField])
                          .map(record2 => ({ ...record1, ...record2 }));
      });
    }

    // Применение WHERE
    if (where) {
      records = records.filter(record => evaluateWhere(record, where));
    }

    // Применение ORDER BY
    if (order) {
      const { field, direction } = order;
      if (!records[0] || !(field in records[0])) {
        throw new Error(`Поле "${field}" не найдено в результирующем наборе данных.`);
      }
      records.sort((a, b) => {
        if (a[field] < b[field]) return direction === 'ASC' ? -1 : 1;
        if (a[field] > b[field]) return direction === 'ASC' ? 1 : -1;
        return 0;
      });
    }

    // Выбор полей
    if (!(selectedFields.length === 1 && selectedFields[0] === '*')) {
      records = records.map(record => {
        const selected = {};
        selectedFields.forEach(field => {
          if (!(field in record)) {
            throw new Error(`Поле "${field}" не найдено в таблицах.`);
          }
          selected[field] = record[field];
        });
        return selected;
      });
    }

    return records;
  }
}

// -----------------------------------------------------------------------------------
// Функции парсинга и оценки WHERE
// -----------------------------------------------------------------------------------

function parseSQL(command) {
  const joinRegex = /^SELECT\s+(.+)\s+FROM\s+(\w+)\s+JOIN\s+(\w+)\s+ON\s+(\w+\.\w+)\s*=\s*(\w+\.\w+)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(\w+)\s+(ASC|DESC))?;?$/i;
  const selectRegex = /^SELECT\s+(.+)\s+FROM\s+(\w+)(?:\s+WHERE\s+(.+?))?(?:\s+ORDER\s+BY\s+(\w+)\s+(ASC|DESC))?;?$/i;
  const insertRegex = /^INSERT\s+INTO\s+(\w+)\s*\(([^)]+)\)\s+VALUES\s*\(([^)]+)\);?$/i;
  const updateRegex = /^UPDATE\s+(\w+)\s+SET\s+([^;]+?)(?:\s+WHERE\s+(\w+)\s*=\s*(\d+))?;?$/i;
  const deleteRegex = /^DELETE\s+FROM\s+(\w+)(?:\s+WHERE\s+(\w+)\s*=\s*(\d+))?;?$/i;

  let match = command.match(joinRegex);
  if (match) {
    const fields = match[1].split(',').map(f => f.trim());
    const table1 = match[2];
    const table2 = match[3];
    const joinConditionLeft = match[4];
    const joinConditionRight = match[5];
    const whereClause = match[6];
    const orderField = match[7];
    const orderDirection = match[8] ? match[8].toUpperCase() : 'ASC';

    const where = whereClause ? parseWhere(whereClause) : null;
    const order = orderField ? { field: orderField, direction: orderDirection } : null;

    return { 
      type: 'JOIN',
      fields, 
      table1, 
      table2, 
      joinCondition: { left: joinConditionLeft, right: joinConditionRight },
      where, 
      order 
    };
  }

  match = command.match(selectRegex);
  if (match) {
    const fields = match[1].split(',').map(f => f.trim());
    const tableName = match[2];
    const whereClause = match[3];
    const orderField = match[4];
    const orderDirection = match[5] ? match[5].toUpperCase() : 'ASC';

    const where = whereClause ? parseWhere(whereClause) : null;
    const order = orderField ? { field: orderField, direction: orderDirection } : null;

    return { type: 'SELECT', tableName, fields, where, order };
  }

  match = command.match(insertRegex);
  if (match) {
    const tableName = match[1];
    const fields = match[2].split(',').map(f => f.trim());
    const values = match[3].split(',').map(v => {
      v = v.trim();
      if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
        return v.slice(1, -1);
      }
      return Number(v);
    });
    const record = {};
    fields.forEach((field, index) => {
      record[field] = values[index];
    });
    return { type: 'INSERT', tableName, values: record };
  }

  match = command.match(updateRegex);
  if (match) {
    const tableName = match[1];
    const setClause = match[2];
    const whereField = match[3];
    const whereValue = Number(match[4]);

    const fields = {};
    setClause.split(',').forEach(clause => {
      const [field, value] = clause.split('=').map(s => s.trim());
      fields[field] = isNaN(Number(value)) ? value.replace(/['"]/g, '') : Number(value);
    });

    const where = whereField && whereValue !== undefined ? { field: whereField, operator: '=', value: whereValue, id: whereValue } : null;

    return { type: 'UPDATE', tableName, fields, where };
  }

  match = command.match(deleteRegex);
  if (match) {
    const tableName = match[1];
    const whereField = match[2];
    const whereValue = Number(match[3]);

    const where = whereField && whereValue !== undefined ? { field: whereField, operator: '=', value: whereValue, id: whereValue } : null;

    return { type: 'DELETE', tableName, where };
  }

  return null;
}

function parseWhere(whereClause) {
  const operators = ['>=', '<=', '!=', '=', '>', '<'];
  for (let op of operators) {
    const parts = whereClause.split(op);
    if (parts.length === 2) {
      const field = parts[0].trim();
      let value = parts[1].trim();
      if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
        value = value.slice(1, -1);
      }
      if (!isNaN(Number(value))) {
        value = Number(value);
      }
      // Дополнительно, если используется WHERE для идентификатора
      if (field.toLowerCase() === 'id') {
        return { field, operator: op, value, id: value };
      }
      return { field, operator: op, value };
    }
  }
  return null;
}

function evaluateWhere(record, where) {
  const { field, operator, value } = where;
  const recordValue = record[field];
  switch (operator) {
    case '=':
      return recordValue === value;
    case '!=':
      return recordValue !== value;
    case '>':
      return recordValue > value;
    case '<':
      return recordValue < value;
    case '>=':
      return recordValue >= value;
    case '<=':
      return recordValue <= value;
    default:
      return false;
  }
}

// -----------------------------------------------------------------------------------
// Функции управления пользователями
// -----------------------------------------------------------------------------------

// Загружаем пользователей при старте приложения
let users = [];
(async () => {
  users = await loadUsers();
})();

// -----------------------------------------------------------------------------------
// Middleware для защиты маршрутов
// -----------------------------------------------------------------------------------
function isAuthenticated(req, res, next) {
  if (req.session.username) {
    app.locals.currentUser = req.session.username;
    return next();
  }
  res.redirect('/login');
}

// -----------------------------------------------------------------------------------
// Маршруты аутентификации
// -----------------------------------------------------------------------------------

// Страница регистрации
app.get('/register', (req, res) => {
  const content = `
    <h1 class="animate__animated animate__fadeInDown">Регистрация</h1>
    <form action="/register" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="username">Имя пользователя</label>
        <input type="text" class="form-control" id="username" name="username" placeholder="Введите имя пользователя" required>
      </div>
      <div class="form-group">
        <label for="password">Пароль</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Введите пароль" required>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Зарегистрироваться</button>
      <a href="/login" class="btn btn-secondary animate__animated animate__fadeIn">Войти</a>
    </form>
  `;
  renderPage(res, 'Регистрация', content);
});

// Обработка регистрации
app.post('/register', async (req, res) => {
  const { username, password } = req.body;
  try {
    if (findUser(users, username)) {
      throw new Error('Имя пользователя уже занято.');
    }

    const passwordHash = await bcrypt.hash(password, SALT_ROUNDS);
    const token = uuidv4();

    const newUser = { username, passwordHash, token };
    users.push(newUser);
    await saveUsers(users);

    const userDir = path.join(BD_DIR, username);
    try {
      await fs.mkdir(userDir, { recursive: true });
    } catch (err) {
      console.error(`Ошибка создания директории пользователя: ${err.message}`);
    }

    const userDBPath = path.join(userDir, 'database.json');
    try {
      await fs.writeFile(userDBPath, JSON.stringify({ tables: {} }, null, 2), 'utf8');
    } catch (err) {
      console.error(`Ошибка инициализации базы данных пользователя: ${err.message}`);
    }

    res.redirect('/login');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка регистрации</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/register" class="btn btn-primary animate__animated animate__fadeIn">Попробовать снова</a>
      </div>
    `;
    renderPage(res, 'Ошибка регистрации', content);
  }
});

// Страница входа
app.get('/login', (req, res) => {
  const content = `
    <h1 class="animate__animated animate__fadeInDown">Вход</h1>
    <form action="/login" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="username">Имя пользователя</label>
        <input type="text" class="form-control" id="username" name="username" placeholder="Введите имя пользователя" required>
      </div>
      <div class="form-group">
        <label for="password">Пароль</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Введите пароль" required>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Войти</button>
      <a href="/register" class="btn btn-secondary animate__animated animate__fadeIn">Регистрация</a>
    </form>
  `;
  renderPage(res, 'Вход', content);
});

// Обработка входа
app.post('/login', async (req, res) => {
  const { username, password } = req.body;
  try {
    const user = findUser(users, username);
    if (!user) {
      throw new Error('Неверное имя пользователя или пароль.');
    }

    const passwordMatch = await bcrypt.compare(password, user.passwordHash);
    if (!passwordMatch) {
      throw new Error('Неверное имя пользователя или пароль.');
    }

    req.session.username = username;
    res.redirect('/');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка входа</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/login" class="btn btn-primary animate__animated animate__fadeIn">Попробовать снова</a>
      </div>
    `;
    renderPage(res, 'Ошибка входа', content);
  }
});

// Обработка выхода
app.get('/logout', (req, res) => {
  req.session.destroy(() => {
    res.redirect('/login');
  });
});

// -----------------------------------------------------------------------------
// Веб-интерфейс (Теперь асинхронный и оптимизированный)
// -----------------------------------------------------------------------------

// Главная страница - список таблиц
app.get('/', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const tables = await db.getTables();
    let content = `<h1 class="animate__animated animate__fadeInDown">Список Таблиц</h1>`;

    const user = findUser(users, username);
    content += `
      <script>
        function copyToken() {
          const tokenInput = document.querySelector('input[readonly]');
          tokenInput.select();
          tokenInput.setSelectionRange(0, 99999); 
          document.execCommand('copy');
          alert('Токен скопирован в буфер обмена.');
        }

        function regenerateToken() {
          if (confirm('Вы уверены, что хотите сгенерировать новый токен? Старый токен станет недействительным.')) {
            fetch('/regenerate-token', { method: 'POST' })
              .then(response => response.json())
              .then(data => {
                if (data.success) {
                  alert('Новый токен сгенерирован.');
                  location.reload();
                } else {
                  alert('Ошибка: ' + data.message);
                }
              })
              .catch(err => {
                alert('Произошла ошибка.');
              });
          }
        }
      </script>
    `;

    if (tables.length === 0) {
      content += `<div class="alert alert-info animate__animated animate__fadeIn">Нет созданных таблиц. Создайте первую таблицу <a href="/create-table">здесь</a>.</div>`;
    } else {
      content += `
      <table class="table table-bordered table-hover">
        <thead class="thead-dark">
          <tr>
            <th>Название Таблицы</th>
            <th>Действия</th>
          </tr>
        </thead>
        <tbody>
      `;
      tables.forEach(table => {
        content += `
          <tr>
            <td><a href="/table/${encodeURIComponent(table)}" class="animate__animated animate__fadeInUp">${table}</a></td>
            <td>
              <div class="table-actions">
                <a href="/table/${encodeURIComponent(table)}/manage-schema" class="btn btn-secondary btn-sm animate__animated animate__fadeIn">Управление Структурой</a>
                <form action="/drop-table/${encodeURIComponent(table)}" method="POST" onsubmit="return confirm('Вы уверены, что хотите удалить таблицу ${escapeHTML(table)}?');" class="mb-0">
                  <button type="submit" class="btn btn-danger btn-sm animate__animated animate__fadeIn">Удалить</button>
                </form>
              </div>
            </td>
          </tr>
        `;
      });
      content += `
        </tbody>
      </table>
      `;
    }
    renderPage(res, 'Список Таблиц', content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка запроса на регенерацию токена
app.post('/regenerate-token', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const user = findUser(users, username);
  if (!user) {
    return res.status(400).json({ success: false, message: 'Пользователь не найден.' });
  }
  user.token = uuidv4();
  await saveUsers(users);
  res.json({ success: true });
});

// Страница регистрации новой таблицы
app.get('/create-table', isAuthenticated, (req, res) => {
  const content = `
    <h1 class="animate__animated animate__fadeInDown">Создать Новую Таблицу</h1>
    <form action="/create-table" method="POST" class="animate__animated animate__fadeIn">
      <div class="form-group">
        <label for="tableName">Название Таблицы</label>
        <input type="text" class="form-control" id="tableName" name="tableName" placeholder="Введите название таблицы" required>
      </div>
      <div class="form-group">
        <label>Поля таблицы</label>
        <div id="columns-container">
          <div class="form-row mb-2 animate__animated animate__fadeIn">
            <div class="col-md-4">
              <input type="text" class="form-control" name="columnNames" placeholder="Имя колонки" required>
            </div>
            <div class="col-md-4">
              <select class="form-control" name="columnTypes" required>
                <option value="" disabled selected>Выберите тип</option>
                <option value="number">Number</option>
                <option value="string">String</option>
              </select>
            </div>
            <div class="col-md-4">
              <button type="button" class="btn btn-outline-danger remove-column animate__animated animate__fadeIn">&times;</button>
            </div>
          </div>
        </div>
        <button type="button" class="btn btn-outline-primary" id="add-column">Добавить Колонку</button>
        <small class="form-text text-muted">Минимум одно поле должно быть "id: number".</small>
      </div>
      <div class="form-group form-check">
        <input type="checkbox" class="form-check-input" id="autoIncrement" name="autoIncrement">
        <label class="form-check-label" for="autoIncrement">Автоинкремент для поля "id"</label>
      </div>
      <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Создать Таблицу</button>
      <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
    </form>

    <script>
      document.addEventListener('DOMContentLoaded', function() {
        const addColumnButton = document.getElementById('add-column');
        const columnsContainer = document.getElementById('columns-container');

        addColumnButton.addEventListener('click', function() {
          const newColumn = document.createElement('div');
          newColumn.className = 'form-row mb-2 animate__animated animate__fadeIn';
          newColumn.innerHTML = \`
            <div class="col-md-4">
              <input type="text" class="form-control" name="columnNames" placeholder="Имя колонки" required>
            </div>
            <div class="col-md-4">
              <select class="form-control" name="columnTypes" required>
                <option value="" disabled selected>Выберите тип</option>
                <option value="number">Number</option>
                <option value="string">String</option>
              </select>
            </div>
            <div class="col-md-4">
              <button type="button" class="btn btn-outline-danger remove-column animate__animated animate__fadeIn">&times;</button>
            </div>
          \`;
          columnsContainer.appendChild(newColumn);
        });

        columnsContainer.addEventListener('click', function(e) {
          if (e.target && e.target.classList.contains('remove-column')) {
            const row = e.target.closest('.form-row');
            row.classList.add('animate__animated', 'animate__fadeOut');
            row.addEventListener('animationend', function() {
              row.remove();
            });
          }
        });
      });
    </script>
  `;
  renderPage(res, 'Создать Таблицу', content);
});

// Обработка создания новой таблицы
app.post('/create-table', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');
  const { tableName, autoIncrement } = req.body;
  let { columnNames, columnTypes } = req.body;

  // Обеспечение того, что columnNames и columnTypes являются массивами
  if (!Array.isArray(columnNames)) {
    columnNames = [columnNames];
  }
  if (!Array.isArray(columnTypes)) {
    columnTypes = [columnTypes];
  }

  try {
    const schema = {};
    for (let i = 0; i < columnNames.length; i++) {
      const name = columnNames[i].trim();
      const type = columnTypes[i].trim().toLowerCase();

      if (!name) {
        throw new Error(`Имя колонки в строке ${i + 1} не может быть пустым.`);
      }

      if (!['number', 'string'].includes(type)) {
        throw new Error(`Некорректный тип колонки "${name}" в строке ${i + 1}. Допустимые типы: number, string.`);
      }

      if (schema[name]) {
        throw new Error(`Дублирующееся имя колонки: "${name}" в строке ${i + 1}.`);
      }

      schema[name] = type;
    }

    if (!schema.id) {
      throw new Error('Необходимо указать колонку "id: number" в качестве уникального идентификатора.');
    }

    if (schema.id !== 'number') {
      throw new Error('Колонка "id" должна быть типа "number".');
    }

    const isAutoIncrement = autoIncrement === 'on';

    const db = new Database(userDBPath);
    await db.loadFromFile();

    await db.createTable(tableName, schema, isAutoIncrement);
    res.redirect('/');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/create-table" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница управления структурой таблицы
app.get('/table/:tableName/manage-schema', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const schema = await db.getTableSchema(tableName);
    const autoIncrement = await db.getTableAutoIncrement(tableName);
    let content = `<h1 class="animate__animated animate__fadeInDown">Управление Структурой Таблицы: ${escapeHTML(tableName)}</h1>`;

    // Форма добавления новой колонки
    content += `
      <h3 class="animate__animated animate__fadeInUp">Добавить Новую Колонку</h3>
      <form action="/table/${encodeURIComponent(tableName)}/add-column" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-row">
          <div class="col-md-5 mb-3">
            <label for="columnName">Название Колонки</label>
            <input type="text" class="form-control" id="columnName" name="columnName" placeholder="Например: email" required>
          </div>
          <div class="col-md-5 mb-3">
            <label for="columnType">Тип Колонки</label>
            <select class="form-control" id="columnType" name="columnType" required>
              <option value="" disabled selected>Выберите тип</option>
              <option value="number">Number</option>
              <option value="string">String</option>
            </select>
          </div>
          <div class="col-md-2 mb-3 align-self-end">
            <button type="submit" class="btn btn-success animate__animated animate__fadeIn">Добавить</button>
          </div>
        </div>
      </form>
    `;

    // Таблица текущей схемы
    content += `
      <h3 class="animate__animated animate__fadeInUp">Текущая Структура Таблицы</h3>
      <table class="table table-bordered table-hover">
        <thead class="thead-light">
          <tr>
            <th>Название Колонки</th>
            <th>Тип</th>
            <th>Действия</th>
          </tr>
        </thead>
        <tbody>
    `;
    for (let field in schema) {
      content += `
        <tr>
          <td>${escapeHTML(field)}</td>
          <td>${escapeHTML(schema[field])}</td>
          <td>
            ${field !== 'id' ? `
            <form action="/table/${encodeURIComponent(tableName)}/delete-column" method="POST" onsubmit="return confirm('Вы уверены, что хотите удалить колонку "${escapeHTML(field)}"? Это приведет к потере всех данных в этой колонке.');" class="mb-0 animate__animated animate__fadeIn">
              <input type="hidden" name="columnName" value="${escapeHTML(field)}">
              <button type="submit" class="btn btn-danger btn-sm">Удалить</button>
            </form>
            ` : `
            <span class="text-muted">Обязательная колонка ${autoIncrement ? '(Автоинкремент)' : ''}</span>
            `}
          </td>
        </tr>
      `;
    }
    content += `
        </tbody>
      </table>
      <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-secondary animate__animated animate__fadeIn">Назад</a>
    `;
    renderPage(res, `Управление Структурой ${escapeHTML(tableName)}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка добавления новой колонки
app.post('/table/:tableName/add-column', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const { columnName, columnType } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (columnName.toLowerCase() === 'id') {
      throw new Error('Невозможно добавить колонку с именем "id". Оно зарезервировано.');
    }
    const db = new Database(userDBPath);
    await db.loadFromFile();
    await db.addColumn(tableName, columnName, columnType);
    res.redirect(`/table/${encodeURIComponent(tableName)}/manage-schema`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/manage-schema" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка удаления колонки
app.post('/table/:tableName/delete-column', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const { columnName } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();
    await db.deleteColumn(tableName, columnName);
    res.redirect(`/table/${encodeURIComponent(tableName)}/manage-schema`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/manage-schema" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница отображения таблицы и ее записей
app.get('/table/:tableName', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const records = await db.getAll(tableName);
    const schema = await db.getTableSchema(tableName);
    const autoIncrement = await db.getTableAutoIncrement(tableName);
    let content = `<h1 class="animate__animated animate__fadeInDown">Таблица: ${escapeHTML(tableName)}</h1>`;
    content += `
      <div class="mb-3">
        <a href="/table/${encodeURIComponent(tableName)}/add" class="btn btn-success animate__animated animate__fadeIn">Добавить Запись</a>
        <a href="/table/${encodeURIComponent(tableName)}/manage-schema" class="btn btn-secondary animate__animated animate__fadeIn">Управление Структурой</a>
      </div>
    `;
    content += `
      <div class="table-responsive">
        <table class="table table-bordered table-hover">
          <thead class="thead-dark">
            <tr>
    `;
    for (let field in schema) {
      content += `<th>${escapeHTML(field)}</th>`;
    }
    content += `<th>Действия</th></tr></thead><tbody>`;
    if (records.length === 0) {
      content += `
        <tr>
          <td colspan="${Object.keys(schema).length + 1}" class="text-center">Нет записей.</td>
        </tr>
      `;
    } else {
      records.forEach(record => {
        content += `<tr class="animate__animated animate__fadeInUp">`;
        for (let field in schema) {
          content += `<td>${escapeHTML(String(record[field]))}</td>`;
        }
        content += `
          <td>
            <div class="table-actions">
              <a href="/table/${encodeURIComponent(tableName)}/edit/${encodeURIComponent(record.id)}" class="btn btn-primary btn-sm animate__animated animate__fadeIn">Редактировать</a>
              <form action="/table/${encodeURIComponent(tableName)}/delete/${encodeURIComponent(record.id)}" method="POST" onsubmit="return confirm('Вы уверены, что хотите удалить запись с id=${record.id}?');" class="mb-0">
                <button type="submit" class="btn btn-danger btn-sm">Удалить</button>
              </form>
            </div>
          </td>
        `;
        content += `</tr>`;
      });
    }
    content += `</tbody></table></div>`;
    content += `<a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Назад</a>`;
    renderPage(res, `Таблица: ${escapeHTML(tableName)}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница добавления новой записи
app.get('/table/:tableName/add', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const schema = await db.getTableSchema(tableName);
    const autoIncrement = await db.getTableAutoIncrement(tableName);
    let formFields = '';
    for (let field in schema) {
      if (field === 'id' && autoIncrement) {
        continue;
      }
      formFields += `
        <div class="form-group animate__animated animate__fadeIn">
          <label for="${escapeHTML(field)}">${escapeHTML(field)} (${escapeHTML(schema[field])})</label>
          ${schema[field] === 'number' ? `
            <input type="number" class="form-control" id="${escapeHTML(field)}" name="${escapeHTML(field)}" required>
          ` : `
            <input type="text" class="form-control" id="${escapeHTML(field)}" name="${escapeHTML(field)}" required>
          `}
        </div>
      `;
    }
    const content = `
      <h1 class="animate__animated animate__fadeInDown">Добавить Запись в Таблицу: ${escapeHTML(tableName)}</h1>
      <form action="/table/${encodeURIComponent(tableName)}/add" method="POST" class="animate__animated animate__fadeIn">
        ${formFields}
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Добавить Запись</button>
        <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
    `;
    renderPage(res, `Добавить Запись в ${escapeHTML(tableName)}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка добавления новой записи
app.post('/table/:tableName/add', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const record = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const schema = await db.getTableSchema(tableName);
    const autoIncrement = await db.getTableAutoIncrement(tableName);

    if (autoIncrement && record.id !== undefined) {
      delete record.id;
    }

    for (const field in record) {
      if (schema[field] === 'number') {
        record[field] = Number(record[field]);
        if (isNaN(record[field])) {
          throw new Error(`Поле "${field}" должно быть числом.`);
        }
      }
    }

    await db.insert(tableName, record);
    res.redirect(`/table/${encodeURIComponent(tableName)}`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/add" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Страница редактирования записи
app.get('/table/:tableName/edit/:id', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const id = req.params.id;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const record = await db.getRecord(tableName, Number(id));
    if (!record) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    const schema = await db.getTableSchema(tableName);
    const autoIncrement = await db.getTableAutoIncrement(tableName);
    let formFields = '';
    for (let field in schema) {
      if (field === 'id' && autoIncrement) {
        continue;
      }
      formFields += `
        <div class="form-group animate__animated animate__fadeIn">
          <label for="${escapeHTML(field)}">${escapeHTML(field)} (${escapeHTML(schema[field])})</label>
          ${schema[field] === 'number' ? `
            <input type="number" class="form-control" id="${escapeHTML(field)}" name="${escapeHTML(field)}" value="${escapeHTML(String(record[field]))}" required>
          ` : `
            <input type="text" class="form-control" id="${escapeHTML(field)}" name="${escapeHTML(field)}" value="${escapeHTML(String(record[field]))}" required>
          `}
        </div>
      `;
    }
    const content = `
      <h1 class="animate__animated animate__fadeInDown">Редактировать Запись в Таблице: ${escapeHTML(tableName)}</h1>
      <form action="/table/${encodeURIComponent(tableName)}/edit/${encodeURIComponent(id)}" method="POST" class="animate__animated animate__fadeIn">
        ${formFields}
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Сохранить Изменения</button>
        <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
    `;
    renderPage(res, `Редактировать Запись в ${escapeHTML(tableName)}`, content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка редактирования записи
app.post('/table/:tableName/edit/:id', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const id = req.params.id;
  const newRecord = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const schema = await db.getTableSchema(tableName);
    const autoIncrement = await db.getTableAutoIncrement(tableName);

    if (autoIncrement && newRecord.id !== undefined) {
      delete newRecord.id;
    }

    for (const field in newRecord) {
      if (schema[field] === 'number') {
        newRecord[field] = Number(newRecord[field]);
        if (isNaN(newRecord[field])) {
          throw new Error(`Поле "${field}" должно быть числом.`);
        }
      }
    }

    const success = await db.updateRecord(tableName, Number(id), newRecord);
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.redirect(`/table/${encodeURIComponent(tableName)}`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}/edit/${encodeURIComponent(id)}" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка удаления записи
app.post('/table/:tableName/delete/:id', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const id = req.params.id;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const success = await db.deleteRecord(tableName, Number(id));
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.redirect(`/table/${encodeURIComponent(tableName)}`);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/table/${encodeURIComponent(tableName)}" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка удаления таблицы
app.post('/drop-table/:tableName', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const tableName = req.params.tableName;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    await db.dropTable(tableName);
    res.redirect('/');
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// -----------------------------------------------------------------------------------
// Вкладка "Выполнить Команду" с аккордеоном примеров
// -----------------------------------------------------------------------------------

app.get('/execute-command', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const exampleQueries = `
      <div class="accordion" id="exampleAccordion">
        <div class="card">
          <div class="card-header" id="headingOne">
            <h2 class="mb-0">
              <button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
                Пример 1: Простый SELECT
              </button>
            </h2>
          </div>

          <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#exampleAccordion">
            <div class="card-body">
              <code>SELECT * FROM users;</code>
            </div>
          </div>
        </div>
        
        <div class="card">
          <div class="card-header" id="headingTwo">
            <h2 class="mb-0">
              <button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
                Пример 2: SELECT с WHERE и ORDER BY
              </button>
            </h2>
          </div>
          <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#exampleAccordion">
            <div class="card-body">
              <code>SELECT id, name FROM users WHERE age &gt;= 18 ORDER BY name ASC;</code>
            </div>
          </div>
        </div>
        
        <div class="card">
          <div class="card-header" id="headingThree">
            <h2 class="mb-0">
              <button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
                Пример 3: SELECT с JOIN
              </button>
            </h2>
          </div>
          <div id="collapseThree" class="collapse" aria-labelledby="headingThree" data-parent="#exampleAccordion">
            <div class="card-body">
              <code>
                SELECT users.name, orders.id FROM users JOIN orders ON users.id = orders.user_id WHERE users.age &gt; 25;
              </code>
            </div>
          </div>
        </div>
        
        <!-- Добавьте дополнительные примеры по необходимости -->
      </div>
    `;

    const user = findUser(users, username);

    const content = `
      <h1 class="animate__animated animate__fadeInDown">Выполнить Команду</h1>
      <div class="mb-4">
        <h3>Ваш API Токен</h3>
        <p>Используйте этот токен для API-запросов:</p>
        <div class="input-group mb-3">
          <input type="text" class="form-control" value="${escapeHTML(user.token)}" readonly>
          <div class="input-group-append">
            <button class="btn btn-outline-secondary" type="button" onclick="copyToken()">Копировать</button>
          </div>
        </div>
        <button class="btn btn-warning" onclick="regenerateToken()">Сгенерировать новый токен</button>
      </div>
      <form action="/execute-command" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-group">
          <label for="command">Введите вашу SQL-подобную команду:</label>
          <textarea class="form-control" id="command" name="command" rows="4" placeholder="Например: SELECT * FROM users ORDER BY name ASC;" required></textarea>
        </div>
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Выполнить</button>
        <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
      <hr>
      <h3>Примеры запросов:</h3>
      ${exampleQueries}
      <script>
        function copyToken() {
          const tokenInput = document.querySelector('input[readonly]');
          tokenInput.select();
          tokenInput.setSelectionRange(0, 99999);
          document.execCommand('copy');
          alert('Токен скопирован в буфер обмена.');
        }

        function regenerateToken() {
          if (confirm('Вы уверены, что хотите сгенерировать новый токен? Старый токен станет недействительным.')) {
            fetch('/regenerate-token', { method: 'POST' })
              .then(response => response.json())
              .then(data => {
                if (data.success) {
                  alert('Новый токен сгенерирован.');
                  location.reload();
                } else {
                  alert('Ошибка: ' + data.message);
                }
              })
              .catch(err => {
                alert('Произошла ошибка.');
              });
          }
        }
      </script>
    `;
    renderPage(res, 'Выполнить Команду', content);
  } catch (error) {
    const content = `
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
        <hr>
        <a href="/" class="btn btn-primary animate__animated animate__fadeIn">Назад</a>
      </div>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// Обработка выполнения команды
app.post('/execute-command', isAuthenticated, async (req, res) => {
  const username = req.session.username;
  const { command } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const result = await db.executeSQLCommand(command);
    let displayResult;

    if (Array.isArray(result)) {
      displayResult = result;
    } else if (result.inserted !== undefined || result.updated !== undefined || result.deleted !== undefined) {
      displayResult = result;
    } else {
      displayResult = result;
    }

    const content = `
      <h1 class="animate__animated animate__fadeInDown">Выполнить Команду</h1>
      <form action="/execute-command" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-group">
          <label for="command">Введите вашу SQL-подобную команду:</label>
          <textarea class="form-control" id="command" name="command" rows="4" required>${escapeHTML(command)}</textarea>
        </div>
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Выполнить</button>
        <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
      <hr class="animate__animated animate__fadeIn">
      <h3 class="animate__animated animate__fadeInUp">Результат:</h3>
      <pre id="command-result" class="animate__animated animate__fadeInUp">${escapeHTML(JSON.stringify(displayResult, null, 2))}</pre>
      <a href="/execute-command" class="btn btn-secondary mt-3 animate__animated animate__fadeIn">Выполнить другую команду</a>
    `;
    renderPage(res, 'Выполнить Команду', content);
  } catch (error) {
    const content = `
      <h1 class="animate__animated animate__fadeInDown">Выполнить Команду</h1>
      <form action="/execute-command" method="POST" class="animate__animated animate__fadeIn">
        <div class="form-group">
          <label for="command">Введите вашу SQL-подобную команду:</label>
          <textarea class="form-control" id="command" name="command" rows="4" required>${escapeHTML(command)}</textarea>
        </div>
        <button type="submit" class="btn btn-primary animate__animated animate__fadeIn">Выполнить</button>
        <a href="/" class="btn btn-secondary animate__animated animate__fadeIn">Отмена</a>
      </form>
      <hr class="animate__animated animate__fadeIn">
      <div class="alert alert-danger animate__animated animate__fadeIn" role="alert">
        <h4 class="alert-heading">Ошибка</h4>
        <p>${escapeHTML(error.message)}</p>
      </div>
      <a href="/execute-command" class="btn btn-secondary animate__animated animate__fadeIn">Попробовать снова</a>
    `;
    renderPage(res, 'Ошибка', content);
  }
});

// -----------------------------------------------------------------------------------
// API-интерфейс с токен-аутентификацией
// -----------------------------------------------------------------------------------

// Middleware для проверки токена
function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  if (!authHeader) return res.status(401).json({ error: 'Нет заголовка авторизации.' });

  const tokenParts = authHeader.split(' ');
  if (tokenParts.length !== 2 || tokenParts[0] !== 'Bearer') {
    return res.status(401).json({ error: 'Неверный формат заголовка авторизации.' });
  }

  const token = tokenParts[1];
  const user = findUserByToken(users, token);
  if (!user) {
    return res.status(403).json({ error: 'Неверный токен.' });
  }

  req.user = user;
  next();
}

// Пример API маршрута: Получение списка таблиц
app.get('/api/tables', authenticateToken, async (req, res) => {
  const username = req.user.username;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();
    const tables = await db.getTables();
    res.json({ tables });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Пример API маршрута: Создание таблицы
app.post('/api/create-table', authenticateToken, async (req, res) => {
  const username = req.user.username;
  const { tableName, schema, autoIncrement } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (!tableName || !schema || typeof schema !== 'object') {
      throw new Error('Необходимо указать tableName и схемы таблицы.');
    }

    const db = new Database(userDBPath);
    await db.loadFromFile();

    await db.createTable(tableName, schema, autoIncrement);
    res.json({ success: true, message: `Таблица "${tableName}" создана.` });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Пример API маршрута: Вставка записи
app.post('/api/insert', authenticateToken, async (req, res) => {
  const username = req.user.username;
  const { tableName, record } = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (!tableName || !record || typeof record !== 'object') {
      throw new Error('Необходимо указать tableName и запись.');
    }

    const db = new Database(userDBPath);
    await db.loadFromFile();

    await db.insert(tableName, record);
    res.json({ success: true, message: 'Запись вставлена успешно.' });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Пример API маршрута: Получение записи по id
app.get('/api/record/:tableName/:id', authenticateToken, async (req, res) => {
  const username = req.user.username;
  const { tableName, id } = req.params;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const record = await db.getRecord(tableName, Number(id));
    if (!record) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.json({ record });
  } catch (error) {
    res.status(404).json({ error: error.message });
  }
});

// Пример API маршрута: Обновление записи по id
app.put('/api/update/:tableName/:id', authenticateToken, async (req, res) => {
  const username = req.user.username;
  const { tableName, id } = req.params;
  const newRecord = req.body;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    if (!newRecord || typeof newRecord !== 'object') {
      throw new Error('Необходимо предоставить новые данные для записи.');
    }

    const db = new Database(userDBPath);
    await db.loadFromFile();

    const success = await db.updateRecord(tableName, Number(id), newRecord);
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.json({ success: true, message: `Запись с id=${id} обновлена.` });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Пример API маршрута: Удаление записи по id
app.delete('/api/delete/:tableName/:id', authenticateToken, async (req, res) => {
  const username = req.user.username;
  const { tableName, id } = req.params;
  const userDBPath = path.join(BD_DIR, username, 'database.json');

  try {
    const db = new Database(userDBPath);
    await db.loadFromFile();

    const success = await db.deleteRecord(tableName, Number(id));
    if (!success) {
      throw new Error(`Запись с id=${id} не найдена.`);
    }
    res.json({ success: true, message: `Запись с id=${id} удалена.` });
  } catch (error) {
    res.status(404).json({ error: error.message });
  }
});

// -----------------------------------------------------------------------------------
// Завершение работы и сохранение данных
// -----------------------------------------------------------------------------------

app.listen(PORT, () => {
  console.log(`Сервер запущен на http://localhost:${PORT}`);
});

// Останавливаем периодическое сохранение при завершении работы
process.on('SIGINT', () => {
  console.log('\nЗавершение работы...');
  // Здесь можно добавить дополнительное сохранение, если необходимо
  process.exit(0);
});