import type { CancellationPolicy, UnixSignal } from "./types.js";

export interface CgroupProcessScope {
  /** Signals every process currently belonging to the job cgroup. */
  signalAll(signal: UnixSignal): Promise<void>;
  /** True only when the cgroup contains no processes. */
  isEmpty(): Promise<boolean>;
}

export type Delay = (milliseconds: number) => Promise<void>;

const systemDelay: Delay = async (milliseconds) => {
  await new Promise<void>((resolve) => setTimeout(resolve, milliseconds));
};

/**
 * Cancels a complete job scope, never a remembered leader PID. SIGKILL is
 * applied after the grace period only when descendants remain.
 */
export async function cancelCgroup(
  scope: CgroupProcessScope,
  policy: CancellationPolicy,
  delay: Delay = systemDelay,
): Promise<void> {
  await scope.signalAll(policy.initialSignal);
  if (await scope.isEmpty()) return;
  await delay(policy.graceMs);
  if (!(await scope.isEmpty())) await scope.signalAll(policy.finalSignal);
}
