#!/usr/bin/env node
'use strict'

/*
  https://github.com/tj/commander.js
*/
const program = require('commander')
const env = require('dotenv').config()
const colors = require('colors')
// @ts-ignore
const pkg = require('../package.json')
const { logger } = require('./commands/services/utils')

/* GLOBAL ============================== */
program.version(pkg.version)

let command_found = false

const runCommand = async (cmd = {}, command_name, params = {}) => {

  // flatten options
  let options = Object.assign(params, cmd.parent || {}, cmd)

  try {
    let path = `./commands/${command_name}`
    let command = require(path)
    command_found = true

    if(typeof options.version == 'function') {
      options.version = undefined
    }

    let exitCode = await command(options, logger)
    switch(typeof exitCode) {
      case 'object':
        process.stdout.write(JSON.stringify(exitCode, null, 2))
        process.exit(0)
        break
      case 'string':
        process.stdout.write(exitCode)
        process.exit(0)
        break
      default:
        process.exit(exitCode)
        return
    }
  } catch (err) {
    console.error(err)
    process.exit(1)
  }
}

/* DOCKER PUBLISH COMMAND =================================== */
program
  .command('docker-publish').alias('dp')
  .description('Push a docker image to docker hub.')
  .option('-o, --org <org>', 'Docker org (Default: viewdo')
  .option('-u, --user <user>', 'Docker Hub username')
  .option('-p, --password <password>', 'Docker Hub password')
  .option('-d, --path <path>', 'Path to image context')
  .option('-i, --image <image>', 'Image name (Default: Reposotory slug')
  .option('-v, --version <version>', 'Image version')
  .option('-b, --build_id <build>', 'Build ID to tag with')
  .option('-t, --tag <tag>', 'Tag (Default: latest)')
  .option('-D, --debug', 'Debug', false)
  .action(async (cmd) => {
    await runCommand(cmd, 'docker-publish')
  })


/* GCR AUTH COMMAND =================================== */
program
  .command('gcp-auth').alias('gcr-auth')
  .description('Authenticate gcloud with using a keyfile.')
  .option('-k, --keyfile <keyfile>', 'Keyfile with service-accoun.json')
  .option('-p, --project <project>', 'GCR project')
  .option('-D, --debug', 'Debug', false)
  .action(async (cmd) => {
    await runCommand(cmd, 'gcp-auth')
  })

/* GCR PUBLISH COMMAND =================================== */
program
  .command('gcr-publish').alias('gp')
  .description('Push a docker image to gcr.')
  .option('-k, --keyfile <keyfile>', 'Key file with service-account.json')
  .option('-p, --project <project>', 'GCR project')
  .option('-r, --repository <repository>', 'GCP repository URL')
  .option('-d, --path <path>', 'Path to image context')
  .option('-i, --image <image>', 'Image name (Default: Repository slug')
  .option('-v, --version <version>', 'Image version')
  .option('-b, --build_id <build>', 'Build ID to tag with')
  .option('-t, --tag <tag>', 'Tag (Default: latest)')
  .option('-D, --debug', 'Debug', false)
  .action(async (cmd) => {
    await runCommand(cmd, 'gcr-publish')
  })

/* GET NAMESPACE COMMAND =================================== */
program
.command('get-namespace <branch>').alias('ns')
.description('Translate a namespace from the passed in branch.')
.action(async (branch, cmd) => {
  await runCommand(cmd, 'get-namespace', {branch})
})

/* GIT TAG COMMAND =================================== */
program
  .command('git-tag [version]').alias('tag')
  .option('-v, --version <version>', ' Version')
  .option('-b, --build_id <build>', 'Build ID')
  .option('-D, --debug', 'Debug', false)
  .description('Tags git with the version and build info')
  .action(async (version, cmd) => {
    await runCommand(cmd, 'git-tag', {version})
  })

/* GIT VERSION COMMAND =================================== */
program
  .command('git-version').alias('version')
  .option('-v, --version <version>', ' Version')
  .description('Uses gitverion to write version.json to the clone directory.')
  .action(async (cmd) => {
    await runCommand(cmd, 'git-version')
  })

/* JIRA RELEASE COMMAND =================================== */
program
  .command('jira-release <project> [version]').alias('release')
  .description('Create a release in Jira with the specified version, and release all done issues.')
  .option('-D, --debug', 'Debug', false)
  .action(async (project, version, cmd) => {
    await runCommand(cmd, 'jira-release', {project, version})
  })

/* KUBE AUTH COMMAND =================================== */
program
  .command('kube-auth').alias('auth')
  .description('Runs the steps to authenticate with k8s in bitbucket.')
  .option('-u, --user <user>', 'Kube User')
  .option('-t, --token <token>', 'Kube token')
  .option('-a, --authority <authority>', 'Kube CA')
  .option('-c, --cluster <cluster>', 'Kube cluster')
  .option('-s, --server <server>', 'Kube server')
  .option('-n, --namespace <namespace>', 'Default namespace')
  .action(async (cmd) => {
    await runCommand(cmd, 'kube-auth')
  });

/* KUBE BUILD =================================== */
program
  .command('kube-build [source] [output]').alias('kb')
  .description('Copies all files from .kube to ./kube and replaces all variables.')
  .option('-v, --version <version>', 'Replace $VERSION')
  .option('-b, --build_id <build>', 'Replace $BUILD_ID')
  .option('-n, --namespace <namespace>', 'Replace $NAMESPACE')
  .option('-B, --branch','Replace $BRANCH')
  .option('-w, --watch','Watch the .kube folder for changes')
  .action(async (source, destination, cmd) => {
    await runCommand(cmd, 'kube-build', {source, destination})
  })


/* PIPELINE RUN =================================== */
program
  .command('run-pipeline [pipeline]').alias('pipeline')
  .description('Run any pipeline within this organization.')
  .option('-u, --user <user>', 'Bitbucket User')
  .option('-p, --password <password>', 'Bitbucket Password')
  .option('-r, --repository <repository>', 'Bitbucket repository slug')
  .option('-b, --branch <branch>', 'Git branch to run pipeline on (default: master)', 'master')
  .option('-D, --debug', 'Debug', false)
  .action(async (pipeline, cmd) => {
    await runCommand(cmd, 'pipeline-run', {pipeline})
  })

/* RUN CONFIGURE DNS PIPELINE =================================== */
program
  .command('run-configure-environments').alias('dns')
  .description('Run the DNS/Environments control pipeline on devops-dns-control master branch.')
  .option('-u, --user <user>', 'Bitbucket User')
  .option('-p, --password <password>', 'Bitbucket Password')
  .option('-D, --debug', 'Debug', false)
  .action(async (cmd) => {
    await runCommand(cmd, 'pipeline-run', {
      repository: 'devops-dns-control',
      pipeline: 'configure_environments',
      branch: 'master'
    })
  })

/* VAR SET COMMAND =================================== */
program
.command('variable-set <key> <value>').alias('set-var')
.option('-u, --user <user>', 'Bitbucket User')
.option('-p, --password <password>', 'Bitbucket Password')
.option('-P, --project <project>', 'Repository / project key')
.description('Create or update a repo-level variable in the given repository')
.action(async (key, value, cmd) => {
  await runCommand(cmd, 'variable-set', {key, value})
})

/* VARS GET COMMAND =================================== */
program
.command('variables-get').alias('vars-get').alias('get-vars')
.option('-v, --version <version>', 'Replace $VERSION')
.option('-b, --build_id <build>', 'Override $BUILD_ID')
.option('-n, --namespace <namespace>', 'Override $NAMESPACE')
.description('Creates vars: VERSION, ASSEMBLY_VERSION, NAMESPACE & BUILD_ID (Requires: version.json).')
.action(async (cmd) => {
  await runCommand(cmd, 'variables-get')
})


/* VARS REPLACE COMMAND =================================== */
program
  .command('variables-replace [path]').alias('rv').alias('replace-vars')
  .option('-v, --version <version>', 'Replace $VERSION')
  .option('-b, --build_id <build>', 'Replace $BUILD_ID')
  .option('-n, --namespace <namespace>', 'Replace $NAMESPACE')
  .option('-B, --branch','Replace $BRANCH')
  .description('Replaces environment $VARIABLES in text files at a given path (default: /kube)')
  .action(async (path, cmd) => {
    await runCommand(cmd, 'variables-replace', {path})
  })

/* SEND SLACK COMMAND =================================== */
program
  .command('send-slack <text>').alias('slack')
  .description('Send a slack message to the #delivery-log channel.')
  .option('-c, --channel <channel>', 'Override the channel')
  .option('-u, --url <url>', 'Slack webhook URL')
  .option('-D, --debug', 'Debug', false)
  .action(async (text, cmd) => {
    cmd.text = text
    await runCommand(cmd, 'send-slack')
  })


/* HELP COMMAND =================================== */
program
  .command('help').alias('h')
  .action(() => {
    program.outputHelp()
  })


program.parse(process.argv)

if (!process.argv.slice(2).length) {
  program.outputHelp()
  process.exit(1)
}

program.on('option:verbose', () => {
  process.env.VERBOSE = 'true';
});

// error on unknown commands
if(!command_found) {
  console.error('Invalid command: %s\n', program.args.join(' '));
  program.outputHelp()
  process.exit(1);
}

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason)
});
