// Periodic scheduling for the background context.
//
// The Chrome MV3 service worker is terminated after roughly 30 seconds idle,
// which takes every setInterval/setTimeout with it. The extension alarms API
// is the mechanism that survives: the browser holds the schedule and wakes
// the worker to deliver onAlarm. Firefox MV2 runs a persistent background
// page where timers would survive, but alarms behave identically there, so
// both targets share this path and both manifests declare the "alarms"
// permission.
//
// Periods are whole minutes at or above the browser-enforced one-minute
// minimum, so nothing here is silently clamped to a slower cadence.
//
// Trap for anyone changing a period: each job also carries a freshness guard
// that can veto its own scheduled tick. A guard timed to the alarm period
// halves the real cadence, because the guard is measured from when the last
// run finished and the alarm fires one run-duration earlier than that. Every
// guard must therefore either be strictly shorter than the period it gates or
// be bypassed on the scheduled tick — see backgroundRefresh() in
// src/background/index.js and updatePhishingList() in shared/phishingDomains.js.

const BALANCE_REFRESH_ALARM = "autistmask-balance-refresh";
const PHISHING_REFRESH_ALARM = "autistmask-phishing-refresh";

const MIN_ALARM_PERIOD_MINUTES = 1;
const BALANCE_REFRESH_PERIOD_MINUTES = 1;
const PHISHING_REFRESH_PERIOD_MINUTES = 24 * 60;

// Resolved on use rather than captured at module load: the worker is torn
// down and re-evaluated repeatedly, and tests install a stub after requiring
// the module.
function alarmsApi() {
    if (typeof browser !== "undefined" && browser.alarms) return browser.alarms;
    if (typeof chrome !== "undefined" && chrome.alarms) return chrome.alarms;
    return null;
}

/**
 * Create an alarm unless one with the requested period already exists.
 *
 * The existence check is load-bearing: creating an alarm resets its schedule,
 * and this runs on every worker wake. Creating unconditionally would push the
 * next fire time out on every incoming message, so a busy extension would
 * never see the alarm fire at all.
 *
 * The period comparison is equally load-bearing in the other direction: an
 * alarm created by an older version keeps its old period forever unless a
 * changed constant re-creates it, so a period edit would never reach an
 * existing install. Re-creating on a period change happens once and then
 * settles into the existence check above.
 *
 * @param {string} name
 * @param {number} periodInMinutes
 * @returns {Promise<boolean>} true if the alarm was created by this call.
 */
async function ensureAlarm(name, periodInMinutes) {
    const api = alarmsApi();
    if (!api) return false;
    const period = Math.max(periodInMinutes, MIN_ALARM_PERIOD_MINUTES);
    const existing = await api.get(name);
    if (existing && existing.periodInMinutes === period) return false;
    api.create(name, {
        periodInMinutes: period,
        delayInMinutes: period,
    });
    return true;
}

/**
 * Ensure both recurring background jobs are scheduled. Safe to call on every
 * worker start, on onInstalled and on onStartup.
 *
 * @returns {Promise<{balance: boolean, phishing: boolean}>} which alarms this
 * call had to create.
 */
async function ensureRecurringAlarms() {
    const balance = await ensureAlarm(
        BALANCE_REFRESH_ALARM,
        BALANCE_REFRESH_PERIOD_MINUTES,
    );
    const phishing = await ensureAlarm(
        PHISHING_REFRESH_ALARM,
        PHISHING_REFRESH_PERIOD_MINUTES,
    );
    return { balance, phishing };
}

/**
 * Register per-alarm handlers. One listener dispatches by alarm name so the
 * worker only ever installs a single onAlarm listener.
 *
 * @param {Object<string, function>} handlers
 * @returns {boolean} true if the listener was installed.
 */
function registerAlarmHandlers(handlers) {
    const api = alarmsApi();
    if (!api || !api.onAlarm) return false;
    api.onAlarm.addListener((alarm) => {
        const handler = handlers[alarm && alarm.name];
        if (handler) handler();
    });
    return true;
}

module.exports = {
    BALANCE_REFRESH_ALARM,
    PHISHING_REFRESH_ALARM,
    MIN_ALARM_PERIOD_MINUTES,
    BALANCE_REFRESH_PERIOD_MINUTES,
    PHISHING_REFRESH_PERIOD_MINUTES,
    ensureAlarm,
    ensureRecurringAlarms,
    registerAlarmHandlers,
};
