/* eslint-disable
    camelcase,
    handle-callback-err,
    no-return-assign,
    no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS103: Rewrite code to no longer use __guard__
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
let LatexRunner
const Path = require('path')
const Settings = require('settings-sharelatex')
const logger = require('logger-sharelatex')
const Metrics = require('./Metrics')
const CommandRunner = require('./CommandRunner')
const fs = require('fs')

const ProcessTable = {} // table of currently running jobs (pids or docker container names)

module.exports = LatexRunner = {
  runLatex(project_id, options, callback) {
    let command
    if (callback == null) {
      callback = function (error) {}
    }
    let {
      directory,
      mainFile,
      compiler,
      timeout,
      image,
      environment,
      flags,
      compileGroup
    } = options
    if (!compiler) {
      compiler = 'pdflatex'
    }
    if (!timeout) {
      timeout = 60000
    } // milliseconds

    logger.log(
      {
        directory,
        compiler,
        timeout,
        mainFile,
        environment,
        flags,
        compileGroup
      },
      'starting compile'
    )

    // We want to run latexmk on the tex file which we will automatically
    // generate from the Rtex/Rmd/md file.
    mainFile = mainFile.replace(/\.(Rtex|md|Rmd)$/, '.tex')

    if (compiler === 'pdflatex') {
      command = LatexRunner._pdflatexCommand(mainFile, flags)
    } else if (compiler === 'latex') {
      command = LatexRunner._latexCommand(mainFile, flags)
    } else if (compiler === 'xelatex') {
      command = LatexRunner._xelatexCommand(mainFile, flags)
    } else if (compiler === 'lualatex') {
      command = LatexRunner._lualatexCommand(mainFile, flags)
    } else {
      return callback(new Error(`unknown compiler: ${compiler}`))
    }

    if (Settings.clsi != null ? Settings.clsi.strace : undefined) {
      command = ['strace', '-o', 'strace', '-ff'].concat(command)
    }

    const id = `${project_id}` // record running project under this id

    return (ProcessTable[id] = CommandRunner.run(
      project_id,
      command,
      directory,
      image,
      timeout,
      environment,
      compileGroup,
      function (error, output) {
        delete ProcessTable[id]
        if (error != null) {
          return callback(error)
        }
        const runs =
          __guard__(
            __guard__(output != null ? output.stderr : undefined, (x1) =>
              x1.match(/^Run number \d+ of .*latex/gm)
            ),
            (x) => x.length
          ) || 0
        const failed =
          __guard__(output != null ? output.stdout : undefined, (x2) =>
            x2.match(/^Latexmk: Errors/m)
          ) != null
            ? 1
            : 0
        // counters from latexmk output
        const stats = {}
        stats['latexmk-errors'] = failed
        stats['latex-runs'] = runs
        stats['latex-runs-with-errors'] = failed ? runs : 0
        stats[`latex-runs-${runs}`] = 1
        stats[`latex-runs-with-errors-${runs}`] = failed ? 1 : 0
        // timing information from /usr/bin/time
        const timings = {}
        const stderr = output != null ? output.stderr : undefined
        timings['cpu-percent'] =
          __guard__(
            stderr != null
              ? stderr.match(/Percent of CPU this job got: (\d+)/m)
              : undefined,
            (x3) => x3[1]
          ) || 0
        timings['cpu-time'] =
          __guard__(
            stderr != null
              ? stderr.match(/User time.*: (\d+.\d+)/m)
              : undefined,
            (x4) => x4[1]
          ) || 0
        timings['sys-time'] =
          __guard__(
            stderr != null
              ? stderr.match(/System time.*: (\d+.\d+)/m)
              : undefined,
            (x5) => x5[1]
          ) || 0
        // record output files
        LatexRunner.writeLogOutput(project_id, directory, output, () => {
          return callback(error, output, stats, timings)
        })
      }
    ))
  },

  writeLogOutput(project_id, directory, output, callback) {
    if (!output) {
      return callback()
    }
    // internal method for writing non-empty log files
    function _writeFile(file, content, cb) {
      if (content && content.length > 0) {
        fs.writeFile(file, content, (err) => {
          if (err) {
            logger.error({ project_id, file }, 'error writing log file') // don't fail on error
          }
          cb()
        })
      } else {
        cb()
      }
    }
    // write stdout and stderr, ignoring errors
    _writeFile(Path.join(directory, 'output.stdout'), output.stdout, () => {
      _writeFile(Path.join(directory, 'output.stderr'), output.stderr, () => {
        callback()
      })
    })
  },

  killLatex(project_id, callback) {
    if (callback == null) {
      callback = function (error) {}
    }
    const id = `${project_id}`
    logger.log({ id }, 'killing running compile')
    if (ProcessTable[id] == null) {
      logger.warn({ id }, 'no such project to kill')
      return callback(null)
    } else {
      return CommandRunner.kill(ProcessTable[id], callback)
    }
  },

  _latexmkBaseCommand(flags) {
    let args = [
      'latexmk',
      '-cd',
      '-f',
      '-jobname=output',
      '-auxdir=$COMPILE_DIR',
      '-outdir=$COMPILE_DIR',
      '-synctex=1',
      '-interaction=batchmode'
    ]
    if (flags) {
      args = args.concat(flags)
    }
    return (
      __guard__(
        Settings != null ? Settings.clsi : undefined,
        (x) => x.latexmkCommandPrefix
      ) || []
    ).concat(args)
  },

  _pdflatexCommand(mainFile, flags) {
    return LatexRunner._latexmkBaseCommand(flags).concat([
      '-pdf',
      Path.join('$COMPILE_DIR', mainFile)
    ])
  },

  _latexCommand(mainFile, flags) {
    return LatexRunner._latexmkBaseCommand(flags).concat([
      '-pdfdvi',
      Path.join('$COMPILE_DIR', mainFile)
    ])
  },

  _xelatexCommand(mainFile, flags) {
    return LatexRunner._latexmkBaseCommand(flags).concat([
      '-xelatex',
      Path.join('$COMPILE_DIR', mainFile)
    ])
  },

  _lualatexCommand(mainFile, flags) {
    return LatexRunner._latexmkBaseCommand(flags).concat([
      '-lualatex',
      Path.join('$COMPILE_DIR', mainFile)
    ])
  }
}

function __guard__(value, transform) {
  return typeof value !== 'undefined' && value !== null
    ? transform(value)
    : undefined
}
