export const createHeartbeatController = (args: {
  intervalMs: number;
  heartbeat: (jobId: string) => Promise<{ cancelRequested: boolean }>;
  onCancel: (jobId: string) => Promise<void>;
  onError: (error: unknown) => void;
}) => {
  const timers = new Map<string, ReturnType<typeof setInterval>>();
  const inFlight = new Set<string>();

  const stop = (jobId: string) => {
    const timer = timers.get(jobId);
    if (timer) clearInterval(timer);
    timers.delete(jobId);
  };

  const tick = async (jobId: string) => {
    if (inFlight.has(jobId) || !timers.has(jobId)) return;
    inFlight.add(jobId);
    try {
      const result = await args.heartbeat(jobId);
      if (result.cancelRequested) {
        stop(jobId);
        await args.onCancel(jobId);
      }
    } catch (error) {
      args.onError(error);
    } finally {
      inFlight.delete(jobId);
    }
  };

  return {
    start: (jobId: string) => {
      stop(jobId);
      const timer = setInterval(() => void tick(jobId), args.intervalMs);
      timer.unref();
      timers.set(jobId, timer);
    },
    stop,
    has: (jobId: string) => timers.has(jobId),
  };
};
