// Discord bot config store (Phase 1). Mirrors the authProviders model split:
// the DB layer only ever sees ciphertext, and only getWithToken() (used
// internally to push config to the bot process / to the bot-config internal
// endpoint) decrypts it. The admin-facing getSafe() never includes the token.

const db = require('./botConfig.db')
const secretBox = require('../../utils/secretBox')

function toSafe(row) {
  if (!row) {
    return {
      guildId: null,
      applicationId: null,
      enabled: false,
      hasToken: false,
      status: 'disconnected',
      statusDetail: null,
      lastConnectedAt: null,
    }
  }
  return {
    guildId: row.guild_id || null,
    applicationId: row.application_id || null,
    enabled: Boolean(row.enabled),
    hasToken: Boolean(row.bot_token_enc),
    status: row.status || 'disconnected',
    statusDetail: row.status_detail || null,
    lastConnectedAt: row.last_connected_at || null,
  }
}

async function getSafe() {
  return toSafe(await db.get())
}

// Decrypted token included — server-side only (pushing config to the bot, or
// serving the shared-secret-gated /internal/bot-config route).
async function getWithToken() {
  const row = await db.get()
  if (!row) return null
  return { ...toSafe(row), token: row.bot_token_enc ? secretBox.decrypt(row.bot_token_enc) : null }
}

// Save admin-supplied config. `token` undefined or '' means "leave the
// existing token unchanged" (same convention as authProviders.save).
async function save({ guildId, applicationId, token, enabled, updatedBy }) {
  const fields = {}
  if (guildId !== undefined) fields.guild_id = guildId
  if (applicationId !== undefined) fields.application_id = applicationId
  if (token) fields.bot_token_enc = secretBox.encrypt(token)
  if (enabled !== undefined) fields.enabled = enabled ? 1 : 0
  if (updatedBy !== undefined) fields.updated_by = updatedBy
  const row = await db.upsert(fields)
  return toSafe(row)
}

// Mirror the bot's last-reported status into the DB so the admin panel has
// something to show even if the bot is briefly unreachable.
async function recordStatus({ status, statusDetail, lastConnectedAt }) {
  const fields = {}
  if (status !== undefined) fields.status = status
  if (statusDetail !== undefined) fields.status_detail = statusDetail
  // lastConnectedAt arrives over HTTP as a JSON-serialized ISO string (e.g.
  // "2026-07-04T18:49:51.429Z") — MariaDB's DATETIME parser rejects the "T"/
  // "Z"/milliseconds in that format. Convert to a real Date so the mariadb
  // driver formats it correctly on the wire.
  if (lastConnectedAt !== undefined) fields.last_connected_at = lastConnectedAt ? new Date(lastConnectedAt) : null
  if (Object.keys(fields).length === 0) return getSafe()
  const row = await db.upsert(fields)
  return toSafe(row)
}

module.exports = { getSafe, getWithToken, save, recordStatus }
