#!/usr/bin/env python

""" standard """
import argparse
import colorama as c
import json
import os
import sys
import traceback
from uuid import uuid4
from collections import OrderedDict
from random import randint
""" third-party """
""" custom """

parser = argparse.ArgumentParser()
parser.add_argument(
    '--config', default='install.json',
    help='The install.json file name. (default: "install.json")')
parser.add_argument(
    '--outfile', help='File to output or append profile.')
args, extra_args = parser.parse_known_args()

c.init(autoreset=True, strip=False)


def main():
    """Generate a profile for an App"""
    if not os.path.isfile(args.config):
        print('{}{}Configuration file ({}) could not be found.'.format(
            c.Style.BRIGHT, c.Fore.CYAN, args.config))

    with open(args.config) as fh:
        data = json.load(fh)

    #
    # args
    #
    config_args = OrderedDict()
    config_args['api_access_id'] = '$env.API_ACCESS_ID'
    config_args['api_secret_key'] = '$envs.API_SECRET_KEY'
    config_args['logging'] = 'debug'
    config_args['tc_api_path'] = '$env.TC_API_PATH'
    config_args['tc_log_path'] = 'log'
    config_args['tc_log_to_api'] = False
    config_args['tc_out_path'] = 'log'
    config_args['tc_temp_path'] = 'log'
    if data.get('runtimeLevel') == 'Playbook':
        config_args['tc_playbook_db_type'] = 'Redis'
        config_args['tc_playbook_db_context'] = str(uuid4())
        config_args['tc_playbook_db_path'] = 'localhost'
        config_args['tc_playbook_db_port'] = '6379'
        config_args['tc_playbook_out_variables'] = ''

    for d in data.get('params', []):
        if d.get('type') == 'Boolean':
            config_args[d.get('name')] = d.get('default', False)
        elif d.get('name') in ['api_secret_id', 'api_secret_key']:
            # leave these parameters set to the value defined above
            pass
        else:
            config_args[d.get('name')] = d.get('default', '')

    #
    # config
    #

    # use displayName if available, otherwise use prefix of install.json file
    profile_name = data.get('displayName')
    if profile_name is None:
        profile_name = args.config.replace('.install.json', 'myprofile')
    profile_name = profile_name.lower().replace(' ', '-')
    print('Building Profile: {}{}{}'.format(c.Style.BRIGHT, c.Fore.CYAN, profile_name))

    config = OrderedDict()
    config['args'] = config_args
    config['description'] = ''
    config['exit_codes'] = [0]
    config['groups'] = ['qa-build']
    config['install_json'] = args.config
    config['profile_name'] = profile_name
    config['quiet'] = False
    config['script'] = data.get('programMain')

    #
    # playbook validation
    #
    if data.get('runtimeLevel') == 'Playbook':
        validations = []
        output_variables = []
        job_id = randint(0, 9999)
        for d in data.get('playbook', {}).get('outputVariables', []):
            variable = '#App:{:04d}:{}!{}'.format(job_id, d.get('name'), d.get('type'))
            output_variables.append(variable)

            # null check
            od = OrderedDict()
            if d.get('type').endswith('Array'):
                od['data'] = [None, []]
                od['operator'] = 'ni'
            else:
                od['data'] = None
                od['operator'] = 'ne'
            od['variable'] = variable
            validations.append(od)

            # type check
            od = OrderedDict()
            if d.get('type').endswith('Array'):
                od['data'] = 'array'
                od['operator'] = 'it'
            elif d.get('type').endswith('Entity') or d.get('type') == 'KeyValue':
                od['data'] = 'entity'
                od['operator'] = 'it'
            else:
                od['data'] = 'string'
                od['operator'] = 'it'
            od['variable'] = variable
            validations.append(od)

        config['validations'] = validations
        config['args']['tc_playbook_out_variables'] = '{}'.format(','.join(output_variables))

    if args.outfile is not None:
        if os.path.isfile(args.outfile):
            # append
            print('Append to File: {}{}{}'.format(c.Style.BRIGHT, c.Fore.CYAN, args.outfile))
            with open(args.outfile, 'r+') as fh:
                try:
                    data = json.load(fh, object_pairs_hook=OrderedDict)
                except ValueError as e:
                    print('{}{}Can not parse JSON data ({}).'.format(c.Style.BRIGHT, c.Fore.RED, e))
                    sys.exit(1)
                # update data
                if isinstance(data, (dict)) and data.get('profiles') is not None:
                    data['profiles'].append(config)
                else:
                    data.append(config)
                fh.seek(0)
                fh.write(json.dumps(data, indent=2))
                fh.truncate()
        else:
            # create
            print('Create File: {}{}{}'.format(c.Style.BRIGHT, c.Fore.CYAN, args.outfile))
            with open(args.outfile, 'w') as fh:
                data = [config]
                fh.write(json.dumps(data, indent=2))
    else:
        print(json.dumps(config, indent=2))


if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        # TODO: Update this, possibly raise
        print('{}{}{}'.format(c.Style.BRIGHT, c.Fore.RED, traceback.format_exc()))
        sys.exit(1)
