/**
 * jobs/weeklyDigest.js
 *
 * Cron worker that runs every hour, checks which digest subscriptions
 * are due (weekly: every Monday 09:00 UTC; daily: every day at the
 * configured hour), builds the digest via services/digest.js, sends
 * via the active email transport, and records last_sent_at.
 *
 * 8ms typical — no I/O unless a digest is due.
 */

'use strict';

const { db } = require('../config/db');
const digest = require('../services/digest');
const email = require('../services/email');

let timer = null;
const TICK_MS = 60 * 60 * 1000;   // 1h — the smallest unit we can wake up to align on a wall-clock hour

/**
 * Find all digest subscriptions that are due RIGHT NOW.
 *   - active = 1
 *   - last_sent_at is NULL OR older than (cadence window) — we
 *     re-send if the cron was off for a while
 *   - the day-of-week matches (for weekly)
 *   - the hour-of-day in UTC matches
 */
function listDue() {
  const now = new Date();
  const dow = now.getUTCDay();
  const hour = now.getUTCHours();
  return db.prepare(`
    SELECT s.*, u.email as user_email
      FROM email_digest_subscriptions s
      LEFT JOIN users u ON u.id = s.user_id
     WHERE s.active = 1
       AND s.hour_utc = ?
       AND (s.cadence = 'daily' OR s.day_of_week = ?)
       AND (s.last_sent_at IS NULL OR s.last_sent_at < ?)
  `).all(hour, dow, now.getTime() - 23 * 3600 * 1000);
}

async function sendOne(sub) {
  // Pick the window: weekly = last 7d, daily = last 24h
  const since = sub.cadence === 'daily' ? Date.now() - 25 * 3600 * 1000 : Date.now() - 7 * 86400 * 1000;
  const d = digest.build({ userId: sub.user_id, since });
  if (!d) return null;
  await email.sendRaw(sub.email || sub.user_email, d.subject, d.text, { html: d.html });
  db.prepare('UPDATE email_digest_subscriptions SET last_sent_at = ? WHERE id = ?').run(Date.now(), sub.id);
  return d;
}

async function tick() {
  const due = listDue();
  if (!due.length) return { sent: 0 };
  let sent = 0, errors = 0;
  for (const sub of due) {
    try {
      await sendOne(sub);
      sent++;
    } catch (e) {
      console.warn('[digest] subscription #' + sub.id + ' failed:', e.message);
      errors++;
    }
  }
  if (sent || errors) console.log(`[digest] sent=${sent} errors=${errors}`);
  return { sent, errors };
}

function start() {
  if (timer) return;
  // Run once on start (catches up any due digests from a downtime)
  tick().catch(e => {
    if (global.__ncii_workers) global.__ncii_workers.weeklyDigest = 'failed';
    console.error('[digest] initial tick:', e.message);
  });
  timer = setInterval(() => {
    tick()
      .then(() => { if (global.__ncii_workers) global.__ncii_workers.weeklyDigest = 'running'; })
      .catch(e => {
        if (global.__ncii_workers) global.__ncii_workers.weeklyDigest = 'failed';
        console.error('[digest] tick:', e.message);
      });
  }, TICK_MS);
  console.log('[digest] cron started (every 1h, checks for due subscriptions)');
}

module.exports = { start, tick, listDue, sendOne };
