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

const COLS =
  'id, post_id, status, ' +
  'towncrier_status, towncrier_attempts, towncrier_last_error, towncrier_next_attempt_at, ' +
  'discord_status, discord_attempts, discord_last_error, discord_next_attempt_at, ' +
  'created_at, updated_at'

// Whitelist so a `leg` value can be interpolated into a column name safely — it
// never comes from raw user input, but keep the guard explicit.
const LEGS = ['towncrier', 'discord']
function assertLeg(leg) {
  if (!LEGS.includes(leg)) throw new Error(`unknown announce leg: ${leg}`)
}

async function create(postId) {
  const res = await query('INSERT INTO announce_jobs (post_id) VALUES (?)', [postId])
  return res.insertId
}

async function findById(id) {
  const rows = await query(`SELECT ${COLS} FROM announce_jobs WHERE id = ? LIMIT 1`, [id])
  return rows[0] || null
}

async function findByPostId(postId) {
  const rows = await query(
    `SELECT ${COLS} FROM announce_jobs WHERE post_id = ? ORDER BY id DESC LIMIT 1`,
    [postId],
  )
  return rows[0] || null
}

// Jobs with at least one leg that is due now: pending and either never scheduled
// (next_attempt_at IS NULL — a fresh enqueue) or past its backoff time.
async function findDue(now = new Date(), limit = 25) {
  return query(
    `SELECT ${COLS} FROM announce_jobs
      WHERE (towncrier_status = 'pending'
             AND (towncrier_next_attempt_at IS NULL OR towncrier_next_attempt_at <= ?))
         OR (discord_status = 'pending'
             AND (discord_next_attempt_at IS NULL OR discord_next_attempt_at <= ?))
      ORDER BY id ASC
      LIMIT ?`,
    [now, now, limit],
  )
}

// Update one leg's columns. `fields` uses leg-agnostic keys (status, attempts,
// lastError, nextAttemptAt); we map them onto the leg-prefixed columns.
async function updateLeg(id, leg, { status, attempts, lastError, nextAttemptAt }) {
  assertLeg(leg)
  await query(
    `UPDATE announce_jobs SET
       ${leg}_status = ?,
       ${leg}_attempts = ?,
       ${leg}_last_error = ?,
       ${leg}_next_attempt_at = ?
     WHERE id = ?`,
    [status, attempts, lastError ?? null, nextAttemptAt ?? null, id],
  )
}

async function setStatus(id, status) {
  await query('UPDATE announce_jobs SET status = ? WHERE id = ?', [status, id])
}

module.exports = { LEGS, create, findById, findByPostId, findDue, updateLeg, setStatus }
