const UPGRADE_CHECK_INTERVAL_ENV = "DIMCODE_UPGRADE_CHECK_INTERVAL_MS";

const DEFAULT_UPGRADE_CHECK_INTERVAL_MS = 60 * 60 * 1000;
const MIN_UPGRADE_CHECK_INTERVAL_MS = 60 * 1000;

type TimerApi = Readonly<{
  setInterval: typeof setInterval;
  clearInterval: typeof clearInterval;
}>;

function unrefTimer(timer: ReturnType<TimerApi["setInterval"]>): void {
  if (
    typeof timer === "object" &&
    timer != null &&
    "unref" in timer &&
    typeof timer.unref === "function"
  ) {
    timer.unref();
  }
}

export function resolveBackgroundUpgradeCheckIntervalMs(
  env: Record<string, string | undefined>,
): number {
  const raw = String(env[UPGRADE_CHECK_INTERVAL_ENV] ?? "").trim();
  if (!raw) return DEFAULT_UPGRADE_CHECK_INTERVAL_MS;

  const parsed = Number(raw);
  if (!Number.isFinite(parsed)) return DEFAULT_UPGRADE_CHECK_INTERVAL_MS;
  if (parsed <= 0) return 0;

  return Math.max(MIN_UPGRADE_CHECK_INTERVAL_MS, Math.floor(parsed));
}

export function createUpgradeMessageReporter(
  notify: (message: string) => void,
): (message: string | null | undefined) => void {
  const seen = new Set<string>();
  return (message) => {
    const text = String(message ?? "").trim();
    if (!text || seen.has(text)) return;
    seen.add(text);
    notify(text);
  };
}

export function startBackgroundUpgradeChecks(
  opts: Readonly<{
    intervalMs: number;
    checkUpgrade: () => Promise<string | null>;
    onMessage: (message: string | null | undefined) => void;
    onError?: (error: unknown) => void;
    timerApi?: TimerApi;
  }>,
): () => void {
  if (!Number.isFinite(opts.intervalMs) || opts.intervalMs <= 0) return () => {};

  const timerApi = opts.timerApi ?? globalThis;
  let stopped = false;
  let inFlight = false;

  const runCheck = async () => {
    if (stopped || inFlight) return;
    inFlight = true;
    try {
      const message = await opts.checkUpgrade();
      if (!stopped) opts.onMessage(message);
    } catch (error) {
      if (!stopped) opts.onError?.(error);
    } finally {
      inFlight = false;
    }
  };

  const timer = timerApi.setInterval(() => {
    void runCheck();
  }, opts.intervalMs);

  unrefTimer(timer);

  return () => {
    if (stopped) return;
    stopped = true;
    timerApi.clearInterval(timer);
  };
}
