const _ = require('lodash')
const Promise = require('bluebird')
const execa = require('execa')
const R = require('ramda')
const os = require('os')
const commandExistsModule = require('command-exists')
const log = require('../log')

const isWindows = () => {
  return os.platform() === 'win32'
}

const profiles = {
  '~/.profile': /\/k?sh$/,
  '~/.bash_profile': /\/bash$/,
  '~/.cshrc': /\/csh$/,
  '~/.zshrc': /\/zsh$/,
  '~/.config/fish/config.fish': /\/fish$/,
}

let sourcedProfiles = []

// returns true if Cypress application has been started from
// the terminal shell.
// returns false if Cypress application has been started
// from the Finder / Windows Explorer list
// by double clicking its icon
const startedNormally = () => {
  return Boolean(process.env._)
}

const getProfilePath = function (shellPath) {
  for (let profilePath in profiles) {
    const regex = profiles[profilePath]

    if (regex.test(shellPath)) {
      return profilePath
    }
  }
}

const sourceShellCommand = function (cmd, shell) {
  if (!shell) {
    return cmd
  }

  const profilePath = getProfilePath(shell)

  log('shell %s profile %s', shell, profilePath)
  if (sourcedProfiles.includes(profilePath)) {
    log('profile has already been sourced')

    return cmd
  }

  const haveShell = startedNormally()

  if (haveShell) {
    // we only need to source once
    // IF THE APP HAS NOT BEEN STARTED BY
    // DOUBLE CLICKING IT FROM FINDER / WINDOWS EXPLORER
    // OTHERWISE NEED TO SOURCE EVERY COMMAND
    sourcedProfiles.push(profilePath)
  }

  // sourcing the profile can output un-needed garbage,
  // so suppress it by sending it to /dev/null and ignore
  // any failures with this
  return `source ${profilePath} > /dev/null 2>&1; ${cmd}`
}

const findBash = () => {
  return execa.shell('which bash')
  .then(R.prop('stdout'))
}

const getShell = function (shell) {
  if (shell) {
    return Promise.resolve(shell)
  }

  // if we didn't get a shell such
  // as when we're in docker
  let s = process.env.SHELL

  if (s) {
    return Promise.resolve(s)
  }

  if (isWindows()) {
    log('use default shell on Windows')

    return Promise.resolve()
  }

  return findBash()
}

const commandExists = (command) => {
  return Promise.resolve(commandExistsModule(command))
  .return(true)
  // commandExists rejects with no error if command does not exist
  // otherwise, it's a legitimate error
  .catchReturn(_.isNil, false)
}

// for testing
const reset = () => {
  return sourcedProfiles = []
}

module.exports = {
  reset,
  findBash,
  getShell,
  getProfilePath,
  sourceShellCommand,
  startedNormally,
  commandExists,
}
