import { fork } from "node:child_process";
import EventEmitter from "node:events";
import { platform } from "node:os";
import { pid } from "node:process";
function getMessage(type, data) {
  if (Array.isArray(data) && data.length === 2 && data[0] === type) {
    return data[1];
  }
  return null;
}
function onMessageType(e, type, handler) {
  return e.on("message", (data, sendHandle) => {
    const msg = getMessage(type, data);
    if (msg) {
      handler(msg, sendHandle);
    }
  });
}
function onceMessageType(e, type, handler) {
  const listener = (data, sendHandle) => {
    const msg = getMessage(type, data);
    if (msg) {
      e.off("message", listener);
      handler(msg, sendHandle);
    }
  };
  return e.on("message", listener);
}
function wrap(proc) {
  return new Proxy(proc, {
    get(target, prop, receiver) {
      switch (prop) {
        case "onMessageType":
          return (type, handler) => {
            onMessageType(target, type, handler);
            return receiver;
          };
        case "onceMessageType":
          return (type, handler) => {
            onceMessageType(target, type, handler);
            return receiver;
          };
      }
      return Reflect.get(target, prop, receiver);
    }
  });
}
const parentWorker = process.send ? wrap(process) : null;
const SINGLE_PROCESS = "SINGLE_PROCESS";
function singleProcessMode() {
  return (process.env[SINGLE_PROCESS] ?? "0") !== "0";
}
function childWorker(moduleUrl, env, ...args) {
  args.push(...process.argv.slice(2));
  if (singleProcessMode()) {
    const [parent, child2] = inProcChannel();
    import(moduleUrl.href).then(async ({ default: runWorker }) => {
      try {
        await runWorker(parent, env ?? process.env, ...args);
        child2.emit("close", 0);
        return;
      } catch (err) {
        child2.emit("error", err);
        child2.emit("close", -1);
      }
    }).catch((err) => child2.emit("error", err));
    return child2;
  }
  const child = fork(moduleUrl, args, {
    // For production / non-windows, set `detached` to `true` so that SIGINT is
    // not automatically propagated and graceful shutdown happens as intended.
    // For Win32, detached: true causes all subprocesses to open in separate
    // terminals and breaks inter-process kill signals, so set it to false.
    detached: platform() !== "win32",
    serialization: "advanced",
    // use structured clone for IPC
    env
  });
  return wrap(child);
}
function inProcChannel() {
  const worker1 = new EventEmitter();
  const worker2 = new EventEmitter();
  const sendTo = (dest) => (message, sendHandle, callback) => {
    dest.emit("message", message, sendHandle);
    if (callback) {
      callback(null);
    }
    return true;
  };
  const kill = (dest) => (signal = "SIGTERM") => dest.emit(signal, signal);
  return [
    wrap(
      Object.assign(worker1, { send: sendTo(worker2), kill: kill(worker2), pid })
    ),
    wrap(
      Object.assign(worker2, { send: sendTo(worker1), kill: kill(worker1), pid })
    )
  ];
}
export {
  childWorker,
  inProcChannel,
  parentWorker,
  singleProcessMode
};
//# sourceMappingURL=processes.js.map
