const { spawn } = require('child_process');

const DEV_SINGLE_INSTANCE_EXIT_CODE = 23;
const DEV_SINGLE_INSTANCE_EXIT_CODE_ENV = 'METOYOU_SINGLE_INSTANCE_EXIT_CODE';
const DEV_RELOAD_EXISTING_ARG = '--metoyou-dev-reload-existing';

function isWaylandSession(env) {
  const sessionType = String(env.XDG_SESSION_TYPE || '').trim().toLowerCase();

  if (sessionType === 'wayland') {
    return true;
  }

  return String(env.WAYLAND_DISPLAY || '').trim().length > 0;
}

function hasSwitch(args, switchName) {
  const normalizedSwitch = `--${switchName}`;

  return args.some((arg) => arg === normalizedSwitch || arg.startsWith(`${normalizedSwitch}=`));
}

function resolveElectronBinary() {
  const electronModule = require('electron');

  if (typeof electronModule === 'string') {
    return electronModule;
  }

  if (electronModule && typeof electronModule.default === 'string') {
    return electronModule.default;
  }

  throw new Error('Could not resolve the Electron executable.');
}

function buildElectronArgs(argv) {
  const args = [...argv];

  if (isDevelopmentLaunch(process.env) && !args.includes(DEV_RELOAD_EXISTING_ARG)) {
    args.push(DEV_RELOAD_EXISTING_ARG);
  }

  if (
    process.platform === 'linux'
    && isWaylandSession(process.env)
    && !hasSwitch(args, 'ozone-platform')
  ) {
    args.push('--ozone-platform=wayland');
  }

  return args;
}

function isDevelopmentLaunch(env) {
  return String(env.NODE_ENV || '').trim().toLowerCase() === 'development';
}

function buildChildEnv(env) {
  const nextEnv = { ...env };

  if (isDevelopmentLaunch(env)) {
    nextEnv[DEV_SINGLE_INSTANCE_EXIT_CODE_ENV] = String(DEV_SINGLE_INSTANCE_EXIT_CODE);
  }

  return nextEnv;
}

function keepProcessAliveForExistingInstance() {
  console.log(
    'Electron is already running; keeping the dev services alive and routing links to the open window.'
  );

  const intervalId = setInterval(() => {}, 60_000);
  const shutdown = () => {
    clearInterval(intervalId);
    process.exit(0);
  };

  process.once('SIGINT', shutdown);
  process.once('SIGTERM', shutdown);
}

function main() {
  const electronBinary = resolveElectronBinary();
  const args = buildElectronArgs(process.argv.slice(2));
  const child = spawn(electronBinary, args, {
    env: buildChildEnv(process.env),
    stdio: 'inherit'
  });

  child.on('error', (error) => {
    console.error(error instanceof Error ? error.message : String(error));
    process.exit(1);
  });

  child.on('exit', (code, signal) => {
    if (code === DEV_SINGLE_INSTANCE_EXIT_CODE) {
      keepProcessAliveForExistingInstance();
      return;
    }

    if (signal) {
      process.kill(process.pid, signal);
      return;
    }

    process.exit(code ?? 0);
  });
}

main();
