'''
Usage: kubedev <command> [args...]

  Where [args] depend on the command, and the following commands are available:

Commands
  generate      Based on a kubedev.json, generate all files required for the development- and CI/CD-workflow:
                - A helm-chart
                - A Tiltfile
                - A CI-configuration (.gitlab-ci.yml)
                - Directories and Dockerfiles for each defined container
  help          Display this help message
'''

import argparse
import os
import sys
import traceback

import colorama

from .kubedev import Kubedev, RealEnvAccessor, RealFileAccessor, RealPrinter
from .utils import CouldNotPullImageInCIException


def add_common_arguments(argParser):
  argParser.add_argument(
      '-c', '--config', help='Path to config file', required=False, default='kubedev.json')


def main_impl(argv, env_accessor=RealEnvAccessor(), printer=RealPrinter(), file_accessor=RealFileAccessor()):
  generatorArgParser = argparse.ArgumentParser()
  add_common_arguments(generatorArgParser)

  templateArgParser = argparse.ArgumentParser()
  add_common_arguments(templateArgParser)

  deployArgParser = argparse.ArgumentParser()
  add_common_arguments(deployArgParser)

  buildArgParser = argparse.ArgumentParser()
  add_common_arguments(buildArgParser)
  buildArgParser.add_argument('container', metavar='Container', type=str,
                              help="The name of the deployment to build the container for.")

  pushArgParser = argparse.ArgumentParser()
  add_common_arguments(pushArgParser)
  pushArgParser.add_argument('container', metavar='Container', type=str,
                             help="The name of the deployment to push the container image for.")

  auditArgParser = argparse.ArgumentParser()
  add_common_arguments(auditArgParser)

  checkArgParser = argparse.ArgumentParser()
  add_common_arguments(checkArgParser)
  checkArgParser.add_argument('command', metavar='Command', type=str, nargs='*',
                              help="An optional sub-command to check for. If provided, only the required environment for this sub-command will be checked.")

  runArgParser = argparse.ArgumentParser()
  add_common_arguments(runArgParser)
  runArgParser.add_argument('container', metavar='Container', type=str,
                             help="The name of the deployment to run locally.")

  systemTestArgParser = argparse.ArgumentParser()
  add_common_arguments(systemTestArgParser)
  systemTestArgParser.add_argument('app', metavar='App', type=str,
                             help="The name of the app to run the system tests for.")
  systemTestArgParser.add_argument('--reuse-cluster', dest='reuseCluster', type=str, required=False, default=None,
                             help="Optionally reuse an existing kind-cluster for system-tests. The cluster will be created if it does not yet exist.")
  systemTestArgParser.add_argument('--build-service-container', dest='buildServiceContainer', action='store_true', required=False, default=None,
                             help="A flag that represents whether service containers for system tests should be built before the system tests run. Default is 'no' in CI and 'true' outside of CI.")

  def print_help(argv):
    print('HELP: TODO')

  def bool_to_returncode(boolValue):
    if boolValue:
      return 0
    else:
      return 1

  def generate(argv):
    args = generatorArgParser.parse_args(argv)
    kubedev = Kubedev()  # TODO: Find templates dir
    return bool_to_returncode(kubedev.generate(args.config))

  def template(argv):
    args = templateArgParser.parse_args(argv)
    kubedev = Kubedev()
    return kubedev.template(args.config)

  def deploy(argv):
    args = deployArgParser.parse_args(argv)
    kubedev = Kubedev()
    return kubedev.deploy(args.config)

  def build(argv):
    args = buildArgParser.parse_args(argv)
    kubedev = Kubedev()
    return kubedev.build(args.config, args.container)

  def push(argv):
    args = pushArgParser.parse_args(argv)
    kubedev = Kubedev()
    return kubedev.push(args.config, args.container)

  def audit(argv):
    args = auditArgParser.parse_args(argv)
    kubedev = Kubedev()
    return kubedev.audit(args.config)

  def check(argv):
    args = checkArgParser.parse_args(argv)
    kubedev = Kubedev()
    return bool_to_returncode(kubedev.check(args.config, args.command,
                         env_accessor=env_accessor, printer=printer, file_accessor=file_accessor))

  def run(argv):
    args, unknown_args = runArgParser.parse_known_args(argv)
    kubedev = Kubedev()
    return kubedev.run(args.config, args.container,
                         env_accessor=env_accessor, printer=printer, file_accessor=file_accessor, extra_args=unknown_args)

  def systemTest(argv):
    args = systemTestArgParser.parse_args(argv)
    kubedev = Kubedev()
    if args.buildServiceContainer is None:
      buildServiceContainer = os.getenv('CI') is not None
    else:
      buildServiceContainer = bool(args.buildServiceContainer)
    try:
      return 0 if kubedev.system_test(args.config, args.app, args.reuseCluster, buildServiceContainer) else 1
    except CouldNotPullImageInCIException as e:
      print(f'''
{colorama.Fore.RED}Failed to pull image "{e.imageName}"

Note that images are *not* being built my `kubedev system-test` when run in a CI environment.

Make sure that you build and push your images in jobs that run before this CI job.{colorama.Fore.RESET}''')
      return 1
    except:
      traceback.print_exc()
      return 1

  commands = {
      'generate': generate,
      'template': template,
      'build': build,
      'push': push,
      'deploy': deploy,
      'check': check,
      'audit': audit,
      'run': run,
      'system-test': systemTest,
      'help': print_help
  }

  if len(argv) < 2:
    print_help([])
    return 0
  else:
    command = argv[1]
    if command not in commands:
      print_help(argv[2:])
      return 0
    else:
      return commands[command](argv[2:])


def main():
  return main_impl(sys.argv)
