import * as cp from "child_process";
import { Emitter } from "vs/base/common/event";

enum ControlMessage {
	okToChild = "ok>",
	okFromChild = "ok<",
}

export type Message = "relaunch";

class IpcMain {
	protected readonly _onMessage = new Emitter<Message>();
	public readonly onMessage = this._onMessage.event;

	public handshake(child?: cp.ChildProcess): Promise<void> {
		return new Promise((resolve, reject) => {
			const target = child || process;
			if (!target.send) {
				throw new Error("Not spawned with IPC enabled");
			}
			target.on("message", (message) => {
				if (message === child ? ControlMessage.okFromChild : ControlMessage.okToChild) {
					target.removeAllListeners();
					target.on("message", (msg) => this._onMessage.fire(msg));
					if (child) {
						target.send!(ControlMessage.okToChild);
					}
					resolve();
				}
			});
			if (child) {
				child.once("error", reject);
				child.once("exit", (code) => {
					const error = new Error(`Unexpected exit with code ${code}`);
					(error as any).code = code;
					reject(error);
				});
			} else {
				target.send(ControlMessage.okFromChild);
			}
		});
	}

	public relaunch(): void {
		if (!process.send) {
			throw new Error("Not a child process with IPC enabled");
		}
		process.send("relaunch");
	}
}

export const ipcMain = new IpcMain();
