const fs = require('fs')
const path = require('path')

// @ts-ignore
Array.prototype.diff = function(a) {
  return this.filter(function(i) {return a.indexOf(i) < 0;});
}

const flattenArray = list => list.reduce(
  (a, b) => a.concat(Array.isArray(b) ? flattenArray(b) : b), []
)

const distinctArray = list => [...new Set(list)]

const reconcileLists = (current, previous, protected_items) => {

  let remove = previous
    .filter(env => !current.includes(env) && !protected_items.includes(env))

  let add = current
    .filter(env => !previous.includes(env) && !protected_items.includes(env))

  return { add, remove }
}

const isValidDomain = (v) => {
  if (!v) return false;
  var re = /^(?!:\/\/)([a-zA-Z0-9-\*]+\.){0,5}[a-zA-Z0-9-][a-zA-Z0-9-]+\.[a-zA-Z]{2,64}?$/gi;
  return re.test(v);
}

const requireValue = (name) => {
  throw new Error(`A value for ${name} is required`.red)
}

const logger = (msg) => {
  console.log('ViewDO Pipe: '.blue + msg)
}

const execShell = (cmd, options = {}) => {
  const shell = require('shelljs')
  console.log(cmd.blue)
  let command = shell.exec(cmd, options)
  if(command.code > 0)
    throw new Error(command.stdout)
  return command
}

const findFiles = (dir, file_list = []) => {
  return fs.readdirSync(dir)
    .map(file => fs.statSync(path.join(dir, file)).isDirectory()
      ? findFiles(path.join(dir, file), file_list)
      : file_list.concat(path.join(dir, file))[0])
}

const replaceInText = (vars, text) => {
  let result = text.toString()
  Object.getOwnPropertyNames(vars).forEach(p => {
    result = result.replace('$' + p.toUpperCase(), vars[p].toString())
  })
  return result
}
const _normalize = (value = '') => {
  let normalized = value
      .replace('origin/', '')
      .replace('/','-')
      .replace('_','-')
      .replace(' ','-')
      .replace('.','-')
      .toLocaleLowerCase()

  let lastDash = _nthIndex(normalized, '-', 3)

  if(lastDash == -1)
    lastDash = _nthIndex(normalized, '-', 2)

  if(lastDash == -1)
    lastDash = _nthIndex(normalized, '-', 1)

  let cutoff = normalized.length > 30 ? 30 : normalized.length
  // if there were dashes, cut off at a nice spot -- otherwise just return the value
  return (lastDash < cutoff ? normalized.substring(0, lastDash) : normalized) || normalized
}

const _nthIndex = (str, pat, n) => {
  var L= str.length, i= -1;
  while(n-- && i++<L){
      i= str.indexOf(pat, i);
      if (i < 0) break;
  }
  return i;
}

const getNormalizedBranchName = (branch) => {
  return _normalize(branch)}

module.exports = {
  distinctArray,
  findFiles,
  isValidDomain,
  flattenArray,
  getNormalizedBranchName,
  requireValue,
  reconcileLists,
  replaceInText,
  execShell,
  logger
}
