// Recurring + one-off scheduled channel messages. Recurring rows are each
// registered as their own node-cron task; one-off rows are picked up by a
// once-a-minute sweep that checks for anything due and marks it sent so it
// never reposts. Needs a live discord.js Client to actually send — wired up
// by discordManager.js (start() once the client is ready, stop() alongside
// client teardown).
const cron = require('node-cron')

const scheduledMessages = require('../model/scheduledMessages')
const createLogger = require('../utils/logger')

const log = createLogger('scheduler')

let discordClient = null
const recurringTasks = new Map() // id -> node-cron ScheduledTask
let sweepTask = null

async function sendToChannel(channelId, content) {
  try {
    const channel = await discordClient.channels.fetch(channelId)
    if (!channel || !channel.isTextBased()) {
      log.warn('scheduled message skipped — channel missing or not text-based', { channelId })
      return
    }
    await channel.send({ content })
    log.info('sent scheduled message', { channelId })
  } catch (err) {
    log.warn('failed to send scheduled message', { channelId, message: err.message })
  }
}

async function loadRecurring() {
  for (const task of recurringTasks.values()) task.stop()
  recurringTasks.clear()

  const rows = await scheduledMessages.listEnabledRecurring()
  for (const row of rows) {
    if (!cron.validate(row.cron_expression)) {
      log.warn('skipping scheduled message with invalid cron expression', { id: row.id, cron: row.cron_expression })
      continue
    }
    const task = cron.schedule(row.cron_expression, () => sendToChannel(row.channel_id, row.content))
    recurringTasks.set(row.id, task)
  }
  log.info('loaded recurring scheduled messages', { count: recurringTasks.size })
}

async function sweepDueOneOff() {
  try {
    const due = await scheduledMessages.listDueOneOff()
    for (const row of due) {
      await sendToChannel(row.channel_id, row.content)
      await scheduledMessages.markSent(row.id)
    }
  } catch (err) {
    log.error('one-off sweep failed', { message: err.message })
  }
}

async function start(client) {
  discordClient = client
  await loadRecurring()
  sweepTask = cron.schedule('* * * * *', sweepDueOneOff)
  log.info('scheduler started')
}

// Called by /schedule after any add/remove so changes apply without a restart.
async function refresh() {
  if (!discordClient) return
  await loadRecurring()
}

function stop() {
  for (const task of recurringTasks.values()) task.stop()
  recurringTasks.clear()
  if (sweepTask) {
    sweepTask.stop()
    sweepTask = null
  }
  discordClient = null
}

module.exports = { start, stop, refresh }
