import fs from 'node:fs';
import { path } from './utils/pathUtils.js';
import { DatabaseSync } from 'node:sqlite';
import bcrypt from 'bcryptjs';
import { nanoid } from 'nanoid';
import { config } from './config.js';
import { settingDefinitions } from './settingsRegistry.js';

fs.mkdirSync(path.dirname(config.databasePath), { recursive: true });
fs.mkdirSync(config.fileLockerDir, { recursive: true });
fs.mkdirSync(config.toolsDir, { recursive: true });

export const db = new DatabaseSync(config.databasePath);
db.exec('PRAGMA foreign_keys = ON; PRAGMA journal_mode = WAL;');

export function id(prefix) {
  return `${prefix}_${nanoid(12)}`;
}

export function now() {
  return new Date().toISOString();
}

export function json(value, fallback = []) {
  if (value == null || value === '') return JSON.stringify(fallback);
  return JSON.stringify(value);
}

export function parseJson(value, fallback = []) {
  try {
    return value ? JSON.parse(value) : fallback;
  } catch {
    return fallback;
  }
}

function ensureColumn(table, column, definition) {
  const columns = db.prepare(`PRAGMA table_info(${table})`).all();
  if (!columns.some((row) => row.name === column)) {
    db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
  }
}

export function migrate() {
  db.exec(`
    CREATE TABLE IF NOT EXISTS users (
      id TEXT PRIMARY KEY,
      email TEXT NOT NULL UNIQUE,
      display_name TEXT NOT NULL,
      password_hash TEXT,
      auth_provider TEXT NOT NULL DEFAULT 'local',
      role TEXT NOT NULL DEFAULT 'user',
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS groups (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL UNIQUE,
      description TEXT,
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS user_groups (
      user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      group_id TEXT NOT NULL REFERENCES groups(id) ON DELETE CASCADE,
      PRIMARY KEY (user_id, group_id)
    );

    CREATE TABLE IF NOT EXISTS credentials (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      kind TEXT NOT NULL,
      username TEXT,
      secret_cipher TEXT NOT NULL,
      secret_iv TEXT NOT NULL,
      secret_tag TEXT NOT NULL,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS hosts (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      fqdn TEXT,
      address TEXT NOT NULL,
      os_family TEXT NOT NULL DEFAULT 'windows',
      transport TEXT NOT NULL DEFAULT 'winrm',
      port INTEGER,
      credential_id TEXT REFERENCES credentials(id) ON DELETE SET NULL,
      tags TEXT NOT NULL DEFAULT '[]',
      notes TEXT,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS folders (
      id TEXT PRIMARY KEY,
      parent_id TEXT REFERENCES folders(id) ON DELETE CASCADE,
      name TEXT NOT NULL,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS scripts (
      id TEXT PRIMARY KEY,
      folder_id TEXT REFERENCES folders(id) ON DELETE SET NULL,
      name TEXT NOT NULL,
      description TEXT,
      content TEXT NOT NULL,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      version INTEGER NOT NULL DEFAULT 1,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS asset_folders (
      id TEXT PRIMARY KEY,
      parent_id TEXT REFERENCES asset_folders(id) ON DELETE CASCADE,
      name TEXT NOT NULL,
      description TEXT,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS assets (
      id TEXT PRIMARY KEY,
      folder_id TEXT REFERENCES asset_folders(id) ON DELETE SET NULL,
      name TEXT NOT NULL,
      original_name TEXT NOT NULL,
      description TEXT,
      kind TEXT NOT NULL DEFAULT 'generic',
      mime_type TEXT,
      size_bytes INTEGER NOT NULL DEFAULT 0,
      checksum TEXT NOT NULL,
      storage_path TEXT NOT NULL,
      package_path TEXT,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS asset_links (
      id TEXT PRIMARY KEY,
      asset_id TEXT NOT NULL REFERENCES assets(id) ON DELETE CASCADE,
      target_type TEXT NOT NULL,
      target_id TEXT NOT NULL,
      link_role TEXT NOT NULL DEFAULT 'reference',
      package_path TEXT,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS custom_variables (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      description TEXT,
      category TEXT NOT NULL DEFAULT 'Custom',
      value_type TEXT NOT NULL DEFAULT 'string',
      secret_cipher TEXT NOT NULL,
      secret_iv TEXT NOT NULL,
      secret_tag TEXT NOT NULL,
      sensitive INTEGER NOT NULL DEFAULT 0,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS psadt_profiles (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      app_vendor TEXT,
      app_name TEXT NOT NULL,
      app_version TEXT,
      app_arch TEXT,
      app_lang TEXT,
      app_revision TEXT,
      toolkit_version TEXT NOT NULL DEFAULT 'v4',
      template_version TEXT NOT NULL DEFAULT 'v4',
      deployment_type TEXT NOT NULL DEFAULT 'Install',
      deploy_mode TEXT NOT NULL DEFAULT 'Interactive',
      require_admin INTEGER NOT NULL DEFAULT 1,
      zero_config INTEGER NOT NULL DEFAULT 0,
      suppress_reboot INTEGER NOT NULL DEFAULT 0,
      close_processes TEXT NOT NULL DEFAULT '[]',
      install_tasks TEXT NOT NULL DEFAULT '[]',
      ui_plan TEXT NOT NULL DEFAULT '{}',
      config_plan TEXT NOT NULL DEFAULT '{}',
      admx_plan TEXT NOT NULL DEFAULT '{}',
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS intune_deployments (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      profile_id TEXT REFERENCES psadt_profiles(id) ON DELETE SET NULL,
      script_id TEXT REFERENCES scripts(id) ON DELETE SET NULL,
      source_folder TEXT,
      intunewin_file TEXT,
      app_type TEXT NOT NULL DEFAULT 'Windows app (Win32)',
      command_style TEXT NOT NULL DEFAULT 'v4',
      install_behavior TEXT NOT NULL DEFAULT 'system',
      restart_behavior TEXT NOT NULL DEFAULT 'return-code',
      ui_mode TEXT NOT NULL DEFAULT 'native-v4',
      requirements TEXT NOT NULL DEFAULT '{}',
      install_command TEXT NOT NULL,
      uninstall_command TEXT NOT NULL,
      detection_type TEXT NOT NULL DEFAULT 'custom-script',
      detection_rule TEXT NOT NULL DEFAULT '',
      return_codes TEXT NOT NULL DEFAULT '[]',
      assignments TEXT NOT NULL DEFAULT '[]',
      status TEXT NOT NULL DEFAULT 'draft',
      graph_app_id TEXT,
      notes TEXT,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS graph_connections (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      tenant_id TEXT NOT NULL,
      client_id TEXT NOT NULL,
      secret_cipher TEXT NOT NULL,
      secret_iv TEXT NOT NULL,
      secret_tag TEXT NOT NULL,
      cloud TEXT NOT NULL DEFAULT 'global',
      graph_base_url TEXT NOT NULL DEFAULT 'https://graph.microsoft.com',
      authority_host TEXT NOT NULL DEFAULT 'https://login.microsoftonline.com',
      default_api_version TEXT NOT NULL DEFAULT 'v1.0',
      enabled INTEGER NOT NULL DEFAULT 1,
      last_test_status TEXT,
      last_test_message TEXT,
      last_test_at TEXT,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS intune_deployment_statuses (
      id TEXT PRIMARY KEY,
      deployment_id TEXT NOT NULL REFERENCES intune_deployments(id) ON DELETE CASCADE,
      connection_id TEXT REFERENCES graph_connections(id) ON DELETE SET NULL,
      graph_app_id TEXT NOT NULL,
      scope TEXT NOT NULL DEFAULT 'device',
      principal_id TEXT,
      principal_name TEXT,
      device_id TEXT,
      device_name TEXT,
      user_id TEXT,
      user_principal_name TEXT,
      install_state TEXT,
      install_state_detail TEXT,
      error_code TEXT,
      error_description TEXT,
      last_sync_datetime TEXT,
      raw_json TEXT NOT NULL DEFAULT '{}',
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS intune_deployment_sync_runs (
      id TEXT PRIMARY KEY,
      deployment_id TEXT NOT NULL REFERENCES intune_deployments(id) ON DELETE CASCADE,
      connection_id TEXT REFERENCES graph_connections(id) ON DELETE SET NULL,
      graph_app_id TEXT NOT NULL,
      status TEXT NOT NULL,
      message TEXT,
      summary TEXT NOT NULL DEFAULT '{}',
      started_at TEXT NOT NULL,
      ended_at TEXT
    );

    CREATE TABLE IF NOT EXISTS applications (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      vendor TEXT,
      publisher TEXT,
      current_version TEXT,
      latest_known_version TEXT,
      version_source TEXT NOT NULL DEFAULT 'manual',
      version_source_ref TEXT,
      graph_connection_id TEXT REFERENCES graph_connections(id) ON DELETE SET NULL,
      current_graph_app_id TEXT,
      auto_check INTEGER NOT NULL DEFAULT 0,
      last_checked_at TEXT,
      last_check_message TEXT,
      notes TEXT,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS change_requests (
      id TEXT PRIMARY KEY,
      deployment_id TEXT REFERENCES intune_deployments(id) ON DELETE CASCADE,
      connection_id TEXT REFERENCES graph_connections(id) ON DELETE SET NULL,
      action TEXT NOT NULL,
      status TEXT NOT NULL DEFAULT 'pending',
      requested_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      requester_email TEXT,
      approver_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      approver_email TEXT,
      reason TEXT,
      decided_at TEXT,
      executed_at TEXT,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS graph_audit_log (
      id TEXT PRIMARY KEY,
      connection_id TEXT REFERENCES graph_connections(id) ON DELETE SET NULL,
      deployment_id TEXT REFERENCES intune_deployments(id) ON DELETE SET NULL,
      actor_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      actor_email TEXT,
      action TEXT NOT NULL,
      target_graph_id TEXT,
      status TEXT NOT NULL,
      message TEXT,
      request_json TEXT NOT NULL DEFAULT '{}',
      response_json TEXT NOT NULL DEFAULT '{}',
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS script_versions (
      id TEXT PRIMARY KEY,
      script_id TEXT NOT NULL REFERENCES scripts(id) ON DELETE CASCADE,
      version INTEGER NOT NULL,
      content TEXT NOT NULL,
      created_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS runplans (
      id TEXT PRIMARY KEY,
      name TEXT NOT NULL,
      description TEXT,
      script_id TEXT NOT NULL REFERENCES scripts(id) ON DELETE CASCADE,
      visibility TEXT NOT NULL DEFAULT 'personal',
      owner_user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
      group_id TEXT REFERENCES groups(id) ON DELETE SET NULL,
      parallel INTEGER NOT NULL DEFAULT 1,
      created_at TEXT NOT NULL,
      updated_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS runplan_hosts (
      runplan_id TEXT NOT NULL REFERENCES runplans(id) ON DELETE CASCADE,
      host_id TEXT NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,
      PRIMARY KEY (runplan_id, host_id)
    );

    CREATE TABLE IF NOT EXISTS jobs (
      id TEXT PRIMARY KEY,
      runplan_id TEXT REFERENCES runplans(id) ON DELETE SET NULL,
      script_id TEXT REFERENCES scripts(id) ON DELETE SET NULL,
      status TEXT NOT NULL,
      triggered_by TEXT REFERENCES users(id) ON DELETE SET NULL,
      started_at TEXT,
      ended_at TEXT,
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS job_hosts (
      id TEXT PRIMARY KEY,
      job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
      host_id TEXT REFERENCES hosts(id) ON DELETE SET NULL,
      status TEXT NOT NULL,
      exit_code INTEGER,
      started_at TEXT,
      ended_at TEXT
    );

    CREATE TABLE IF NOT EXISTS job_logs (
      id TEXT PRIMARY KEY,
      job_id TEXT NOT NULL REFERENCES jobs(id) ON DELETE CASCADE,
      host_id TEXT REFERENCES hosts(id) ON DELETE SET NULL,
      stream TEXT NOT NULL,
      line TEXT NOT NULL,
      created_at TEXT NOT NULL
    );

    CREATE TABLE IF NOT EXISTS settings (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL,
      source TEXT NOT NULL DEFAULT 'db',
      updated_at TEXT NOT NULL
    );
  `);

  ensureColumn('users', 'theme', "TEXT NOT NULL DEFAULT 'dashtreme'");
  ensureColumn('users', 'job_title', 'TEXT');
  ensureColumn('users', 'phone', 'TEXT');
  ensureColumn('users', 'timezone', 'TEXT');
  ensureColumn('users', 'avatar_url', 'TEXT');
  ensureColumn('users', 'updated_at', 'TEXT');
  ensureColumn('intune_deployments', 'source_folder', 'TEXT');
  ensureColumn('intune_deployments', 'intunewin_file', 'TEXT');
  ensureColumn('intune_deployments', 'command_style', "TEXT NOT NULL DEFAULT 'v4'");
  ensureColumn('intune_deployments', 'install_behavior', "TEXT NOT NULL DEFAULT 'system'");
  ensureColumn('intune_deployments', 'restart_behavior', "TEXT NOT NULL DEFAULT 'return-code'");
  ensureColumn('intune_deployments', 'ui_mode', "TEXT NOT NULL DEFAULT 'native-v4'");
  ensureColumn('intune_deployments', 'requirements', "TEXT NOT NULL DEFAULT '{}'");
  ensureColumn('intune_deployments', 'graph_app_id', 'TEXT');
  ensureColumn('intune_deployments', 'graph_connection_id', 'TEXT');
  ensureColumn('intune_deployments', 'relationships', "TEXT NOT NULL DEFAULT '[]'");
  ensureColumn('intune_deployments', 'application_id', 'TEXT REFERENCES applications(id) ON DELETE SET NULL');
  // Auto-promote: after the soak window elapses, advance a rollout ring's intent.
  ensureColumn('intune_deployments', 'auto_promote_after_hours', 'INTEGER NOT NULL DEFAULT 0');
  ensureColumn('intune_deployments', 'auto_promote_ring', 'TEXT');
  ensureColumn('intune_deployments', 'auto_promote_intent', "TEXT NOT NULL DEFAULT 'required'");
  ensureColumn('intune_deployments', 'soak_started_at', 'TEXT');
  ensureColumn('intune_deployments', 'promoted_at', 'TEXT');
  // Host visibility scoping. Existing rows default to 'shared' so prior global
  // hosts remain visible to everyone; new hosts can be personal/group-scoped.
  ensureColumn('hosts', 'visibility', "TEXT NOT NULL DEFAULT 'shared'");
  ensureColumn('hosts', 'owner_user_id', 'TEXT REFERENCES users(id) ON DELETE SET NULL');
  ensureColumn('hosts', 'group_id', 'TEXT REFERENCES groups(id) ON DELETE SET NULL');
  // Tenant write-back is opt-in per Graph connection. Default 0 so existing
  // read-only connections can never be used to change a tenant by accident.
  ensureColumn('graph_connections', 'allow_write', 'INTEGER NOT NULL DEFAULT 0');
  // When set, tenant-changing actions through this connection require an
  // approved change request before they run.
  ensureColumn('graph_connections', 'require_approval', 'INTEGER NOT NULL DEFAULT 0');
  // Optional named-RBAC lists (JSON arrays of user ids). Empty = no restriction
  // beyond the allow_write/admin gates.
  ensureColumn('graph_connections', 'publisher_ids', "TEXT NOT NULL DEFAULT '[]'");
  ensureColumn('graph_connections', 'approver_ids', "TEXT NOT NULL DEFAULT '[]'");
}

export function seed() {
  const userCount = db.prepare('SELECT COUNT(*) AS count FROM users').get().count;
  if (userCount === 0) {
    const adminId = id('usr');
    db.prepare(`
      INSERT INTO users (id, email, display_name, password_hash, auth_provider, role, created_at)
      VALUES (?, ?, ?, ?, 'local', 'admin', ?)
    `).run(
      adminId,
      config.defaultAdminEmail.toLowerCase(),
      config.defaultAdminName,
      bcrypt.hashSync(config.defaultAdminPassword, 12),
      now()
    );
    const groupId = id('grp');
    db.prepare('INSERT INTO groups (id, name, description, created_at) VALUES (?, ?, ?, ?)').run(
      groupId,
      'Operations',
      'Default shared operations group',
      now()
    );
    db.prepare('INSERT INTO user_groups (user_id, group_id) VALUES (?, ?)').run(adminId, groupId);

    const folderId = id('fld');
    db.prepare(`
      INSERT INTO folders (id, parent_id, name, visibility, owner_user_id, group_id, created_at, updated_at)
      VALUES (?, NULL, 'Examples', 'shared', ?, NULL, ?, ?)
    `).run(folderId, adminId, now(), now());

    const scriptId = id('scr');
    const sample = [
      'Write-Output "POSHManager sample run"',
      'Write-Output "Target host: $env:POSHM_HOST_NAME"',
      'Get-Date'
    ].join('\n');
    db.prepare(`
      INSERT INTO scripts (id, folder_id, name, description, content, visibility, owner_user_id, group_id, version, created_at, updated_at)
      VALUES (?, ?, ?, ?, ?, 'shared', ?, NULL, 1, ?, ?)
    `).run(scriptId, folderId, 'Sample Health Check.ps1', 'Simple smoke-test script for local execution.', sample, adminId, now(), now());
    db.prepare(`
      INSERT INTO script_versions (id, script_id, version, content, created_by, created_at)
      VALUES (?, ?, 1, ?, ?, ?)
    `).run(id('ver'), scriptId, sample, adminId, now());
  }

  // Env-pinned settings are refreshed from the environment on every boot and
  // marked source='env' (locked in the UI). Unpinned settings are seeded once
  // as editable defaults so admin edits in the Config screen survive restarts.
  const pinned = db.prepare(`
    INSERT INTO settings (key, value, source, updated_at)
    VALUES (?, ?, 'env', ?)
    ON CONFLICT(key) DO UPDATE SET value = excluded.value, source = 'env', updated_at = excluded.updated_at
  `);
  const defaulted = db.prepare(`
    INSERT INTO settings (key, value, source, updated_at)
    VALUES (?, ?, 'default', ?)
    ON CONFLICT(key) DO NOTHING
  `);
  for (const def of settingDefinitions()) {
    if (def.pinned) pinned.run(def.key, def.value, now());
    else defaulted.run(def.key, def.value, now());
  }
}

export function visibleClause(alias = '') {
  const p = alias ? `${alias}.` : '';
  return `(${p}visibility = 'shared' OR ${p}owner_user_id = ? OR ${p}group_id IN (SELECT group_id FROM user_groups WHERE user_id = ?))`;
}
