const { query } = require('../../utils/db')

const PUBLIC_COLS = 'id, username, role, totp_enabled, created_at, last_login_at'

async function insertUser({ username, passwordHash, role = 'admin' }) {
  const res = await query(
    'INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)',
    [username, passwordHash, role],
  )
  return res.insertId
}

async function findByUsername(username) {
  const rows = await query('SELECT * FROM users WHERE username = ? LIMIT 1', [username])
  return rows[0] || null
}

async function findById(id) {
  const rows = await query('SELECT * FROM users WHERE id = ? LIMIT 1', [id])
  return rows[0] || null
}

async function listUsers() {
  return query(`SELECT ${PUBLIC_COLS} FROM users ORDER BY id ASC`)
}

async function updateUser(id, fields) {
  const cols = []
  const params = []
  for (const [key, val] of Object.entries(fields)) {
    cols.push(`${key} = ?`)
    params.push(val)
  }
  if (cols.length === 0) return
  params.push(id)
  await query(`UPDATE users SET ${cols.join(', ')} WHERE id = ?`, params)
}

async function deleteUser(id) {
  return query('DELETE FROM users WHERE id = ?', [id])
}

async function countUsers() {
  const rows = await query('SELECT COUNT(*) AS c FROM users')
  return Number(rows[0].c)
}

async function countAdmins() {
  const rows = await query("SELECT COUNT(*) AS c FROM users WHERE role = 'admin'")
  return Number(rows[0].c)
}

async function touchLastLogin(id) {
  return query('UPDATE users SET last_login_at = NOW() WHERE id = ?', [id])
}

// Move the "tokens valid after" cutoff to now, invalidating every session token
// issued before this instant (password change / log out everywhere). requireAuth
// compares each session's issued-at against this column.
async function bumpTokensValidAfter(id) {
  return query('UPDATE users SET tokens_valid_after = NOW() WHERE id = ?', [id])
}

// Store a (not-yet-enabled) TOTP secret for a user. Enabling is a separate step
// so a secret is never trusted until the user has confirmed one code.
async function setTotpSecret(id, secret) {
  return query('UPDATE users SET totp_secret = ?, totp_enabled = 0 WHERE id = ?', [secret, id])
}

async function enableTotp(id) {
  return query('UPDATE users SET totp_enabled = 1 WHERE id = ?', [id])
}

async function disableTotp(id) {
  return query('UPDATE users SET totp_secret = NULL, totp_enabled = 0 WHERE id = ?', [id])
}

module.exports = {
  insertUser,
  findByUsername,
  findById,
  listUsers,
  updateUser,
  deleteUser,
  countUsers,
  countAdmins,
  touchLastLogin,
  bumpTokensValidAfter,
  setTotpSecret,
  enableTotp,
  disableTotp,
}
