import { existsSync } from 'fs';
import { ChildProcess, execSync, spawn } from 'child_process';
import { parse } from 'shell-quote';

function isTerminalEditor(editor: string): boolean {
  switch (editor) {
    case 'vim':
    case 'emacs':
    case 'nano':
      return true;
    default:
      return false;
  }
}

const COMMON_EDITORS = {
  '/Applications/Atom.app/Contents/MacOS/Atom': 'atom',
  '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta': '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',
  '/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':
    '/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',
  '/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':
    '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',
  '/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',
};

function guessEditor(): Array<string> {
  if (process.env.REACT_EDITOR) {
    return parse(process.env.REACT_EDITOR).map(val => val.toString());
  }

  if (process.platform === 'darwin') {
    try {
      const output = execSync('ps x').toString();
      const processNames = Object.keys(COMMON_EDITORS);
      for (let i = 0; i < processNames.length; i++) {
        const processName = processNames[i];
        if (output.indexOf(processName) !== -1) {
          return [(COMMON_EDITORS as any)[processName]];
        }
      }
    } catch (error) {
      // Ignore...
    }
  }

  if (process.env.VISUAL) {
    return [process.env.VISUAL];
  } else if (process.env.EDITOR) {
    return [process.env.EDITOR];
  }

  return [];
}

let childProcess: ChildProcess | null = null;

function getValidFilePath(pathToFile: string): string | null {
  if (existsSync(pathToFile)) {
    return pathToFile;
  }
  return null;
}

export function launchEditor(pathToFile: string) {
  const filePath = getValidFilePath(pathToFile);
  if (filePath === null) {
    return;
  }

  const [editor, ...destructuredArgs] = guessEditor();
  if (!editor) {
    return;
  }

  let args = destructuredArgs;
  args.push(filePath);

  if (childProcess && isTerminalEditor(editor)) {
    childProcess.kill('SIGKILL');
  }

  var spawn_env = JSON.parse(JSON.stringify(process.env));
  delete spawn_env.ATOM_SHELL_INTERNAL_RUN_AS_NODE;
  delete spawn_env.ELECTRON_RUN_AS_NODE;

  if (process.platform === 'win32') {
    // On Windows, launch the editor in a shell because spawn can only
    // launch .exe files.
    childProcess = spawn('cmd.exe', ['/C', editor].concat(args), {
      env: spawn_env,
      detached: true,
    });
  } else {
    childProcess = spawn(editor, args, { env: spawn_env, detached: true });
  }
  childProcess.on('error', function() {});
  childProcess.on('exit', function(errorCode: any) {
    childProcess = null;
  });
}
