(() => {
  const MIN_INTERVAL_MINUTES = 1;
  const MAX_INTERVAL_MINUTES = 1440;
  const DEFAULT_INTERVAL_MINUTES = 5;

  function parseIntervalMinutes(value) {
    const numeric = Number(value);
    if (!Number.isInteger(numeric) || numeric < MIN_INTERVAL_MINUTES || numeric > MAX_INTERVAL_MINUTES) {
      return null;
    }
    return numeric;
  }

  function normalizeIntervalMinutes(value, fallback = DEFAULT_INTERVAL_MINUTES) {
    return parseIntervalMinutes(value) ?? parseIntervalMinutes(fallback) ?? DEFAULT_INTERVAL_MINUTES;
  }

  function intervalMilliseconds(value) {
    return normalizeIntervalMinutes(value) * 60 * 1000;
  }

  function isDue(lastRunAt, value, now = Date.now()) {
    const previous = Number(lastRunAt || 0);
    return !Number.isFinite(previous) || previous <= 0 || Number(now) - previous >= intervalMilliseconds(value);
  }

  function nextRunAt(lastRunAt, value) {
    const previous = Number(lastRunAt || 0);
    return previous > 0 ? previous + intervalMilliseconds(value) : 0;
  }

  const api = {
    MIN_INTERVAL_MINUTES,
    MAX_INTERVAL_MINUTES,
    DEFAULT_INTERVAL_MINUTES,
    parseIntervalMinutes,
    normalizeIntervalMinutes,
    intervalMilliseconds,
    isDue,
    nextRunAt
  };
  if (typeof window !== "undefined") window.MMWQianchuanTaskPatrol = api;
  if (typeof module !== "undefined" && module.exports) module.exports = api;
})();
