'use babel';

/* @flow */
import { existsSync, readFile, writeFileSync, unlink } from 'fs';
import { basename, dirname, join } from 'path';
import { has, forEach, get, indexOf, remove, subtract, union } from 'lodash';
import { EOL, tmpdir } from 'os';
import { BufferedProcess } from 'atom';
/* flow-include
import type { TextEditor } from 'atom'
*/

function parseReporterOutput(data/* :string*/, filePath/* :string*/, textEditor /* :TextEditor*/) {
  return new Promise((res, rej) => {
    try {
      data = JSON.parse(data);
    } catch (error) {
      atom.notifications.addError('Tester Jest: Could not parse data to JSON.');
      return rej(error);
    }
    const messages = [];
    if (has(data, 'testResults[0].assertionResults') && data.testResults[0].assertionResults.length > 0) {
      forEach(data.testResults[0].assertionResults, (testResult) => {
        textEditor.scan(new RegExp(testResult.title.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')), (scanResult) => {
          if (testResult.status === 'pending') {
            testResult.status = 'skipped';
          }
          messages.push({
            state: testResult.status,
            title: testResult.title,
            error: {
              name: 'Failure Messages',
              message: toString(get(testResult, 'failureMessages')),
            },
            duration: subtract(get(data, 'testResults[0].endTime') - get(data, 'testResults[0].startTime')),
            lineNumber: scanResult.row,
            filePath,
          });
        });
      });
    }
    return res(messages);
  });
}

export function run(textEditor/* :TextEditor*/) {
  return new Promise((resolve) => {
    let processOutput = `\u001b[1mTester Jest\u001b[0m${EOL}`;
    const fileName = textEditor.getPath();
    let outputFilePath = fileName;
    const projectPath = atom.project.relativizePath(fileName)[0];
    let cwd = projectPath;
    if (!(cwd)) {
      cwd = dirname(fileName);
    }
    const fileModified = textEditor.isModified();
    if (fileModified) {
      outputFilePath = `${dirname(fileName)}/.${basename(fileName)}`;
      writeFileSync(outputFilePath, textEditor.getText());
    }
    const jsonOutputFilePath = join(tmpdir(), `tester-jest_${basename(fileName)}.json`);

    const userConfigArgs = atom.config.get('tester-jest.args');
    const prohibitedArgs = ['--json', '--outputFile', '--watch', '--watchAll', '--watchman'];
    const removedArgs = remove(userConfigArgs, a => indexOf(prohibitedArgs, a) !== -1);
    if (removedArgs && removedArgs.length > 0) {
      atom.notifications.addWarning(`Tester: The args "${toString(removedArgs)}" are not allowed and removed from command.`);
    }
    const belowEighteen = atom.config.get('tester-jest.jestMajorVersion') < 18;
    const outputArg = belowEighteen ? '--jsonOutputFile' : '--outputFile';
    let args = union(userConfigArgs, ['--json', outputArg, jsonOutputFilePath, outputFilePath]);
    const env = Object.create(process.env);
    // Jest NODE_ENV default is 'test'
    // https://github.com/facebook/jest/blob/master/packages/jest-cli/bin/jest.js#L13
    env.NODE_ENV = atom.config.get('tester-jest.nodeEnv');
    // To use our own commands in create-react, we need to tell the command that
    // we're in a CI environment, or it will always append --watch
    env.CI = 'true';
    // set NODE_PATH otherwise will set atom own path
    // https://github.com/atom/atom/blob/master/src/initialize-application-window.coffee#L71
    env.NODE_PATH = cwd;
    const options = { cwd, env };
    let jestBinary = atom.config.get('tester-jest.binaryPath');
    const jestBinaryProject = `${cwd}/node_modules/.bin/jest`;
    const jestBinaryPackage = `${atom.packages.resolvePackagePath('tester-jest')}/node_modules/.bin/jest`;
    let command = '';
    if (jestBinary) {
      const runtimeExecutable = jestBinary;
      const parameters = runtimeExecutable.split(' ');
      command = parameters.shift();
      args = union(parameters, args);
    } else {
      jestBinary = existsSync(jestBinaryProject) ? jestBinaryProject : jestBinaryPackage;
      command = jestBinary;
    }
    processOutput += `\u001b[1mcommand:\u001b[0m ${command} ${args.join(' ')}${EOL}`;
    processOutput += `\u001b[1mcwd:\u001b[0m ${cwd}${EOL}`;
    const stdout = (data) => {
      if (!data.startsWith('Test results written to:')) {
        processOutput += data;
      }
    };
    const stderr = data => processOutput += data;
    const exit = () => {
      if (fileModified) {
        unlink(outputFilePath);
      }
      this.bufferedProcess = null;
      readFile(jsonOutputFilePath, 'utf8', (error, data) => {
        if (error) {
          processOutput += `${EOL}JSON report not found at ${this.outputPath}`;
          resolve({ messages: [], output: processOutput });
        } else {
          parseReporterOutput(data, outputFilePath, textEditor)
          .then(messages => resolve({ messages, output: processOutput }))
          .catch(reason => resolve({ messages: [], output: processOutput + EOL + reason }));
        }
      });
    };
    this.bufferedProcess = new BufferedProcess({ command, args, options, stdout, stderr, exit });

    this.bufferedProcess.onWillThrowError(() => {
      atom.notifications.addError('Tester is unable to locate the jest command. Please ensure process.env.PATH can access jest.');
    });
  });
}

export function stop() {
  if (this.bufferedProcess) {
    this.bufferedProcess.kill();
    this.bufferedProcess = null;
  }
}

@@ -52,31 +52,8 @@
 File
-, writeFileSync, unlink
  %7D f
@@ -1723,20 +1723,20 @@
 nst file
-Name
+Path
  = textE
@@ -1756,43 +1756,8 @@
 ();%0A
-    let outputFilePath = fileName;%0A
     
@@ -1808,20 +1808,20 @@
 ath(file
-Name
+Path
 )%5B0%5D;%0A  
@@ -1891,221 +1891,12 @@
 file
-Name);%0A    %7D%0A    const fileModified = textEditor.isModified();%0A    if (fileModified) %7B%0A      outputFilePath = %60$%7Bdirname(fileName)%7D/.$%7Bbasename(fileName)%7D%60;%0A      writeFileSync(outputFilePath, textEditor.getText()
+Path
 );%0A 
@@ -1978,12 +1978,12 @@
 file
-Name
+Path
 )%7D.j
@@ -2651,23 +2651,17 @@
 lePath, 
-outputF
+f
 ilePath%5D
@@ -4214,74 +4214,8 @@
 %3E %7B%0A
-      if (fileModified) %7B%0A        unlink(outputFilePath);%0A      %7D%0A
     
@@ -4521,23 +4521,17 @@
 t(data, 
-outputF
+f
 ilePath,

remove testOnChange feature