// Outbound email config store (Gmail OAuth2). Mirrors the botConfig model split:
// the DB layer only ever sees ciphertext, and only getWithSecret() (used by the
// mailer at send time) decrypts the refresh token. The admin-facing getSafe()
// never includes it — callers see only `hasRefreshToken`.

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

function toSafe(row) {
  if (!row) {
    return {
      provider: 'gmail_oauth2',
      enabled: false,
      senderEmail: null,
      senderName: null,
      hasRefreshToken: false,
      status: 'unconfigured',
      statusDetail: null,
      lastVerifiedAt: null,
    }
  }
  return {
    provider: row.provider || 'gmail_oauth2',
    enabled: Boolean(row.enabled),
    senderEmail: row.sender_email || null,
    senderName: row.sender_name || null,
    hasRefreshToken: Boolean(row.refresh_token_enc),
    status: row.status || 'unconfigured',
    statusDetail: row.status_detail || null,
    lastVerifiedAt: row.last_verified_at || null,
  }
}

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

// Decrypted refresh token included — server-side only (building the mailer's
// OAuth2 transport). Returns null when no row exists yet.
async function getWithSecret() {
  const row = await db.get()
  if (!row) return null
  return {
    ...toSafe(row),
    refreshToken: row.refresh_token_enc ? secretBox.decrypt(row.refresh_token_enc) : null,
  }
}

// Save admin-supplied / connect-flow config. `refreshToken` undefined or '' means
// "leave the existing token unchanged" (same convention as botConfig.save).
async function save({ senderEmail, senderName, refreshToken, enabled, status, statusDetail, updatedBy }) {
  const fields = {}
  if (senderEmail !== undefined) fields.sender_email = senderEmail
  if (senderName !== undefined) fields.sender_name = senderName
  if (refreshToken) fields.refresh_token_enc = secretBox.encrypt(refreshToken)
  if (enabled !== undefined) fields.enabled = enabled ? 1 : 0
  if (status !== undefined) fields.status = status
  if (statusDetail !== undefined) fields.status_detail = statusDetail
  if (updatedBy !== undefined) fields.updated_by = updatedBy
  const row = await db.upsert(fields)
  return toSafe(row)
}

// Clear the stored credential and disable sending (admin "Disconnect").
async function disconnect(updatedBy) {
  const row = await db.upsert({
    refresh_token_enc: null,
    sender_email: null,
    enabled: 0,
    status: 'unconfigured',
    status_detail: null,
    last_verified_at: null,
    updated_by: updatedBy ?? null,
  })
  return toSafe(row)
}

// Record the outcome of the last send / verification so the admin panel has
// something to show. `lastVerifiedAt` may arrive as a Date or ISO string.
async function recordStatus({ status, statusDetail, lastVerifiedAt } = {}) {
  const fields = {}
  if (status !== undefined) fields.status = status
  if (statusDetail !== undefined) fields.status_detail = statusDetail ? String(statusDetail).slice(0, 500) : null
  if (lastVerifiedAt !== undefined) {
    fields.last_verified_at = lastVerifiedAt ? new Date(lastVerifiedAt) : null
  }
  if (Object.keys(fields).length === 0) return getSafe()
  const row = await db.upsert(fields)
  return toSafe(row)
}

module.exports = { getSafe, getWithSecret, save, disconnect, recordStatus }
