#!/usr/bin/env python3
"""DeployHub's CLI using the dhapi module"""

__version__ = '9.3.68'

import json
import os
import re
import stat
import subprocess
import sys
import time
from pathlib import Path
from pprint import pprint

import click
import configobj
import qtoml
from configobj import ConfigObj
from flatten_dict import flatten
from deployhub import dhapi



@click.command()
@click.argument('action', required=True)
@click.option('--dhurl', help='DeployHub Url', envvar='DHURL')
@click.option('--dhuser', help='DeployHub User', envvar='DHUSER')
@click.option('--dhpass', help='DeployHub Password', envvar='DHPASS')
@click.option('--appname', help='Application Name', envvar='COMPONENT_APPLICATION')
@click.option('--appversion', help='Application Version', envvar='COMPONENT_APPLICATION_VERSION')
@click.option('--appautoinc', help='Application Auto Increment Version', envvar='COMPONENT_APPLICATION_AUTOINC')
@click.option('--deployenv', help='Deployment Environment')
@click.option('--compname', help='Component Name', envvar='COMPONENT_NAME')
@click.option('--compvariant', help='Component Variant')
@click.option('--compversion', help='Component Version', envvar='COMPONENT_VERSION')
@click.option('--compautoinc', help='Component Auto Increment Version', envvar='COMPONENT_AUTOINC')
@click.option('--kvconfig', help='Directory containing the json and properties file', envvar='KVCONFIG')
@click.option('--from_domain', help='Move from domain')
@click.option('--task', help='Task to use for move')
@click.option('--envvars', help='Env Variables TOML file')
@click.option('--envvars_sh', help='Env Variables Output sh file')
@click.option('--docker', 'kind', flag_value='docker', default=True, help='Component Item Type')
@click.option('--file', 'kind', flag_value='file')
@click.option('--compattr', help='Component Attributes, use multiple time for each attr', multiple=True)
@click.option('--envs', help='Environments to Associate App to, use multiple time for each env', multiple=True)
@click.option('--importfile', help='File to Import')
@click.option('--fromdom', help='From Domain')
@click.option('--todom', help='To Domain')
def main(dhurl, dhuser, dhpass, action, appname, appversion, appautoinc, compname, compvariant, compversion, compautoinc, kind, deployenv, envs, compattr, kvconfig, from_domain, task, envvars, envvars_sh, importfile, fromdom, todom):
    """
    ACTION is (deploy, updatecomp, approve, move, envscript, kv, export, import) for the type of action to perform.

    deploy: deploy the application to the evironment\n
    approve: approve the application version\n
    move: move the application version using the supplied task\n
    updatecomp: create/replace the component version for the application verion\n
    assign: assigns a component version to an application verion\n
    kv: assigns the key/values pairs to the component verion\n
    envscript: creates a bash file from the component toml file\n
    export: exports a domain including all objects to stdout\n
    import: imports the export file into the new domain\n
    """

    if (action.lower() == "kv" or action.lower() == "deploy" or action.lower() == "updatecomp" or action.lower() == "approve"  or action.lower() == "export"  or action.lower() == "import" or action.lower() == "assign"):
        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        errors = []

        cookies = dhapi.login(dhurl, dhuser, dhpass, errors)

        if cookies is None:
            if (errors):
                print(errors[0])
            sys.exit(1)

    if (action.lower() == "deploy"):
        # Deploy Application to Environment
        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(appname)):
            print("--appname is required")
            sys.exit(1)

        if (dhapi.is_empty(deployenv)):
            print("--deployenv is required")
            sys.exit(1)

        if (dhapi.is_empty(appversion)):
            parts = appname.split(';')
            if (len(parts) == 3):
                appname = parts[0] + ';' + parts[1]
                appversion = parts[2]

        data = dhapi.get_application(dhurl, cookies, appname, appversion, True)
        appid = data[0]
        appname = data[1]
        print(f'Deploying {appname} to {deployenv}')
        data = dhapi.deploy_application(dhurl, cookies, appname, "", deployenv)

        deployid = data[0]
        if (deployid < 0):
            print(data[1])
            sys.exit(1)

        print(f"Fetching Logs for {deployid}")
        data = dhapi.get_logs(dhurl, cookies, deployid)

        print(data[1])
        if (data[0]):
            print("Successful")
            sys.exit(0)
        else:
            print("Failed")
            sys.exit(1)
    elif (action.lower() == "updatecomp"):

        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(compname)):
            print("--compname is required")
            sys.exit(1)

        if (dhapi.is_empty(compvariant)):
            compvariant = ""

        if (dhapi.is_empty(compvariant) and "-v" in compversion):
            compvariant = compversion.split("-v")[0]
            compversion = "v" + compversion.split("-v")[1]

        if (dhapi.is_empty(compvariant) and "-V" in compversion):
            compvariant = compversion.split("-V")[0]
            compversion = "v" + compversion.split("-V")[1]

        saveappver = ""
        if (dhapi.is_not_empty(appversion)):
            saveappver = appversion

        cnt = 1
        while True:
            # create component version
            print("Creating Component")
            compid = dhapi.new_component_version(dhurl, cookies, compname, compvariant, compversion, kind, None, compautoinc)
            print("Creation Done: " + dhapi.get_component_name(dhurl, cookies, compid))

            attrs = {}
            print("Updating Component Attributes\n")
            for attr in compattr:
                if (':' in attr):
                    key = attr.split(':')[0]
                    value = ':'.join(attr.split(':')[1:])
                else:
                    key = attr
                    value = ""

                if ("@sha256:" in value):
                    value = value.split("@sha256:")[1]

                if (value.startswith('@')):
                    value = value[1:]
                    if (os.path.exists(value)):
                        value = open(value, 'r').read().replace('\n', '')
                        attrs[key] = value
                    else:
                        attrs[key] = ""
                else:
                    attrs[key] = value

            gittag = attrs.get("GitTag", None)
            if (dhapi.is_empty(gittag)):
                attrs['GitTag'] = attrs.get('GitBranch', '')

            comptype = attrs.get("CompType", None)
            if (dhapi.is_empty(comptype)):
                attrs['CompType'] = "Application File"

            pprint(attrs)
            print("")

            data = dhapi.update_component_attrs(dhurl, cookies, compname, compvariant, compversion, attrs)
            print("Attribute Update Done")

            if (dhapi.is_not_empty(appname)):

                if (dhapi.is_not_empty(saveappver)):
                    appversion = saveappver

                if (dhapi.is_empty(appversion)):
                    parts = appname.split(';')
                    if (len(parts) == 3):
                        appname = parts[0] + ';' + parts[1]
                        appversion = parts[2]

                if (dhapi.is_empty(appversion)):
                    parts = appname.split(';')
                    if (len(parts) == 3):
                        appname = parts[0] + ';' + parts[1]
                        appversion = parts[2]

                if (dhapi.is_empty(appversion)):
                    appversion = ""

                print("Creating Application Version '" + str(appname) + "' '" + appversion + "'")
                data = dhapi.new_application(dhurl, cookies, appname, appversion, appautoinc, envs)
                appid = data[0]
                print("Creation Done: " + dhapi.get_application_name(dhurl, cookies, appid, True))

                print("Assigning Component Version to Application Version " + str(appid))

                data = dhapi.add_compver_to_appver(dhurl, cookies, appid, compid)
                print("Assignment Done")

            compname = os.environ.get("COMPONENT_NAME_" + str(cnt), None)
            compversion = os.environ.get("COMPONENT_VERSION_" + str(cnt), None)
            appname = os.environ.get("COMPONENT_APPLICATION_" + str(cnt), None)
            appversion = os.environ.get("COMPONENT_APPLICATION_VERSION_" + str(cnt), None)

            cnt = cnt + 1

            if (compname is None):  # leave loop if no more components defined in env
                break

    elif (action.lower() == "kv"):

        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(compname)):
            print("--compname is required")
            sys.exit(1)

        if (dhapi.is_empty(kvconfig)):
            print("--kvconfig is required")
            sys.exit(1)

        if (dhapi.is_empty(compvariant)):
            compvariant = ""

        if (dhapi.is_empty(compvariant) and "-v" in compversion):
            compvariant = compversion.split("-v")[0]
            compversion = "v" + compversion.split("-v")[1]

        if (dhapi.is_empty(compvariant) and "-V" in compversion):
            compvariant = compversion.split("-V")[0]
            compversion = "v" + compversion.split("-V")[1]

        saveappver = ""
        if (dhapi.is_not_empty(appversion)):
            saveappver = appversion

        normal_dict = {}
        for file_path in Path(kvconfig).glob('**/*.properties'):
            filename = os.fspath(file_path)

            try:
                print(filename)
                config = ConfigObj(filename, encoding='iso-8859-1')
                filename = filename[len(kvconfig)+1:]
                normal_dict[filename] = config.dict()
            except configobj.ConfigObjError as error:
                print(error)

        flat_dict = flatten(normal_dict, reducer='path')

        attrs = {}
        for key, value in flat_dict.items():
            if (isinstance(value, list)):
                value = ' '.join(value)

            attrs[key] = value

        print("")

        # create component version
        print("Getting Latest Component")
        data = dhapi.get_component(dhurl, cookies, compname, compvariant, compversion, False, True)
        latest_compid = data[0]

        old_attrs = []
        if (latest_compid > 0):
            comp_attrs = dhapi.get_component_attrs(dhurl, cookies, latest_compid)

            for attr in comp_attrs:
                key = list(attr.keys())[0]
                value = attr[key]
                old_attrs.append(key + "=" + value)

        new_attrs = []
        for key, value in attrs.items():
            new_attrs.append(key + "=" + value)

        diffs = set(new_attrs) ^ set(old_attrs)

        print(f"Comparing KV: %d Changes" %(len(diffs)))

        if (len(diffs) > 0):
            pprint(list(diffs))
            compid = dhapi.new_component_version(dhurl, cookies, compname, compvariant, compversion, kind, None, compautoinc)
            print("Creation Done: " + dhapi.get_component_name(dhurl, cookies, compid))

            print("Updating Component Attributes\n")

            data = dhapi.update_compid_attrs(dhurl, cookies, compid, attrs)

            print("Attribute Update Done")

            if (dhapi.is_not_empty(appname)):

                if (dhapi.is_not_empty(saveappver)):
                    appversion = saveappver

                if (dhapi.is_empty(appversion)):
                    parts = appname.split(';')
                    if (len(parts) == 3):
                        appname = parts[0] + ';' + parts[1]
                        appversion = parts[2]

                if (dhapi.is_empty(appversion)):
                    parts = appname.split(';')
                    if (len(parts) == 3):
                        appname = parts[0] + ';' + parts[1]
                        appversion = parts[2]

                if (dhapi.is_empty(appversion)):
                    appversion = ""

                print("Creating Application Version '" + str(appname) + "' '" + appversion + "'")
                data = dhapi.new_application(dhurl, cookies, appname, appversion, appautoinc, envs)
                appid = data[0]
                print("Creation Done: " + dhapi.get_application_name(dhurl, cookies, appid, True))

                print("Assigning Component Version to Application Version " + str(appid))

                data = dhapi.add_compver_to_appver(dhurl, cookies, appid, compid)
                print("Assignment Done")

    elif (action.lower() == "assign"):

        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(appname)):
            print("--appname is required")
            sys.exit(1)

        if (dhapi.is_empty(compname)):
            print("--compname is required")
            sys.exit(1)

        if (dhapi.is_empty(compvariant)):
            compvariant = ""

        if (dhapi.is_empty(compvariant) and "-v" in compversion):
            compvariant = compversion.split("-v")[0]
            compversion = "v" + compversion.split("-v")[1]

        if (dhapi.is_empty(compvariant) and "-V" in compversion):
            compvariant = compversion.split("-V")[0]
            compversion = "v" + compversion.split("-V")[1]

        saveappver = ""
        if (dhapi.is_not_empty(appversion)):
            saveappver = appversion

        assign_completed = []

        cnt = 1
        while True:
            # create component version
            [compid, name] = dhapi.get_component(dhurl, cookies, compname, compvariant, compversion, True, False)

            if (compid > 0):
                print("Found " + name)

                if (dhapi.is_not_empty(saveappver)):
                    appversion = saveappver

                if (dhapi.is_empty(appversion)):
                    parts = appname.split(';')
                    if (len(parts) == 3):
                        appname = parts[0] + ';' + parts[1]
                        appversion = parts[2]

                if (dhapi.is_empty(appversion)):
                    parts = appname.split(';')
                    if (len(parts) == 3):
                        appname = parts[0] + ';' + parts[1]
                        appversion = parts[2]

                if (dhapi.is_empty(appversion)):
                    appversion = ""

                data = dhapi.get_application(dhurl, cookies, appname, appversion, True)
                appid = data[0]

                if (appid < 0):
                    print("Creating Application Version '" + str(appname) + "' '" + appversion + "'")
                    data = dhapi.new_application(dhurl, cookies, appname, appversion, envs)
                    appid = data[0]
                    print("Creation Done: " + dhapi.get_application_name(dhurl, cookies, appid, True))

                if (appname not in [assign_completed]):
                    dhapi.assign_app_to_env(dhurl, cookies, appname, envs)
                    assign_completed.append(appname)

                print("Assigning Component Version to Application Version " + str(appid))

                data = dhapi.add_compver_to_appver(dhurl, cookies, appid, compid)
                print("Assignment Done")

            compname = os.environ.get("COMPONENT_NAME_" + str(cnt), None)
            compversion = os.environ.get("COMPONENT_VERSION_" + str(cnt), None)
            appname = os.environ.get("COMPONENT_APPLICATION_" + str(cnt), None)
            appversion = os.environ.get("COMPONENT_APPLICATION_VERSION_" + str(cnt), None)

            cnt = cnt + 1

            if (compname is None):  # leave loop if no more components defined in env
                break

    elif (action.lower() == "approve"):
        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(appname)):
            print("--appname is required")
            sys.exit(1)

        if (dhapi.is_empty(appversion)):
            parts = appname.split(';')
            if (len(parts) == 3):
                appname = parts[0] + ';' + parts[1]
                appversion = parts[2]

        print(f'Approving {appname} {appversion}')
        data = dhapi.approve_application(dhurl, cookies, appname, appversion)
        print(data[1])
    elif (action.lower() == "move"):
        if (dhapi.is_empty(appname)):
            print("--appname is required")
            sys.exit(1)

        if (dhapi.is_empty(from_domain)):
            print("--from_domain is required")
            sys.exit(1)

        if (dhapi.is_empty(task)):
            print("--task is required")
            sys.exit(1)

        if (dhapi.is_empty(appversion)):
            parts = appname.split(';')
            if (len(parts) == 3):
                appname = parts[0] + ';' + parts[1]
                appversion = parts[2]

        print(f'Moving {appname} {appversion} from {from_domain}')
        data = dhapi.move_application(dhurl, cookies, appname, appversion, from_domain, task)
        print(data[1])
    elif (action.lower() == "envscript"):
        if (dhapi.is_empty(envvars)):
            print("--envvars is required")
            sys.exit(1)

        print(f'Creating env shell script from {envvars}')
        envscript(envvars, envvars_sh)
    elif (action.lower() == "export"):
        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(fromdom)):
            print("--fromdom is required")
            sys.exit(1)

        allobjs = {}
        filterdict(dhurl, cookies, "users", fromdom, allobjs)
        filterdict(dhurl, cookies, "groups", fromdom, allobjs)
        filterdict(dhurl, cookies, "comptypes", fromdom, allobjs)
        filterdict(dhurl, cookies, "credentials", fromdom, allobjs)
        filterdict(dhurl, cookies, "endpoints", fromdom, allobjs)
        filterdict(dhurl, cookies, "datasources", fromdom, allobjs)
        filterdict(dhurl, cookies, "tasks", fromdom, allobjs)
        filterdict(dhurl, cookies, "engines", fromdom, allobjs)
        filterdict(dhurl, cookies, "repositories", fromdom, allobjs)
        filterdict(dhurl, cookies, "environments", fromdom, allobjs)
        filterdict(dhurl, cookies, "components", fromdom, allobjs)
        filterdict(dhurl, cookies, "applications", fromdom, allobjs)
        filterdict(dhurl, cookies, "releases", fromdom, allobjs)

        jstr = json.dumps(allobjs, indent=2)
        print(jstr)
    elif (action.lower() == "import"):
        if (dhapi.is_empty(dhurl)):
            print("--dhurl is required")
            sys.exit(1)

        if (dhapi.is_empty(dhuser)):
            print("--dhuser is required")
            sys.exit(1)

        if (dhapi.is_empty(dhpass)):
            print("--dhpass is required")
            sys.exit(1)

        if (dhapi.is_empty(fromdom)):
            print("--fromdom is required")
            sys.exit(1)

        if (dhapi.is_empty(todom)):
            print("--todom is required")
            sys.exit(1)

        if (dhapi.is_empty(importfile)):
            print("--importfile is required")
            sys.exit(1)

        file = open(importfile, 'r')
        all_of_it = file.read()
        file.close()
        jstr = re.sub(fromdom, todom, all_of_it, flags=re.IGNORECASE)
        allobjs = json.loads(jstr)

        importdict(dhurl, cookies, "users", allobjs)
        importdict(dhurl, cookies, "groups", allobjs)
        importdict(dhurl, cookies, "comptypes", allobjs)
        importdict(dhurl, cookies, "credentials", allobjs)
        importdict(dhurl, cookies, "endpoints", allobjs)
        importdict(dhurl, cookies, "datasources", allobjs)
        importdict(dhurl, cookies, "tasks", allobjs)
        importdict(dhurl, cookies, "engines", allobjs)
        importdict(dhurl, cookies, "repositories", allobjs)
        importdict(dhurl, cookies, "environments", allobjs)
        importdict(dhurl, cookies, "components", allobjs)
        importdict(dhurl, cookies, "applications", allobjs)
        importdict(dhurl, cookies, "releases", allobjs)
    else:
        print("Action is not defined.  Use deploy, envscript, approve, move or updatecomp for action")
        sys.exit(1)

def envscript(envvars, envvars_sh):

    lines = subprocess.run(['cat', envvars], check=False, stdout=subprocess.PIPE).stdout.decode('utf-8')

    vardict = qtoml.loads(lines)

    if (dhapi.is_empty(envvars_sh)):
        envvars_sh = 'cloudbuild.sh'

    fp_script = open(envvars_sh, 'a')

    if ("Component" in vardict):
        vardict = vardict["Component"]

    fp_script.write("export BLDDATE=\"" + time.ctime(time.time()) + "\"\n")

    for key in vardict:
        if (key.upper() == "COMPONENTS"):
            comp_to_app = vardict[key]

            cnt = 0
            for compapp in comp_to_app:
                if (cnt == 0):
                    fp_script.write("export COMPONENT_NAME=\"" + compapp.get("Name", "") + "\"\n")
                    fp_script.write("export COMPONENT_VERSION=\"" + vardict.get("Version", "") + "\"\n")
                    fp_script.write("export COMPONENT_APPLICATION=\"" + compapp.get("Application", "") + "\"\n")
                    fp_script.write("export COMPONENT_APPLICATION_VERSION=\"" + compapp.get("AppVersion", "") + "\"\n")
                else:
                    fp_script.write("export COMPONENT_NAME_" + str(cnt) + "=\"" + compapp.get("Name", "") + "\"\n")
                    fp_script.write("export COMPONENT_VERSION_" + str(cnt) + "=\"" + vardict.get("Version", "") + "\"\n")
                    fp_script.write("export COMPONENT_APPLICATION_" + str(cnt) + "=\"" + compapp.get("Application", "") + "\"\n")
                    fp_script.write("export COMPONENT_APPLICATION_VERSION_" + str(cnt) + "=\"" + compapp.get("AppVersion", "") + "\"\n")

                cnt = cnt + 1
        else:
            fp_script.write("export COMPONENT_" + key.upper() + '="' + str(vardict[key]) + "\"\n")

    fp_script.close()
    os.chmod(envvars_sh, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)

def filterdict(dhurl, cookies, objtype, fromdom, allobjs):

    data = dhapi.get_json(dhurl + "/dmadminweb/API/export/" + objtype, cookies)

    objlist = []
    for obj in data.get(objtype, []):
        objname = obj.get("objname", "")
        if (fromdom.lower() in objname.lower()):
            objlist.append(obj)

    allobjs[objtype] = objlist


def importdict(dhurl, cookies, objtype, allobjs):

    print(objtype)

    for obj in allobjs.get(objtype, []):
        pprint(obj)
        jstr = json.dumps(obj, indent=2)
        data = dhapi.post_json(dhurl + "/dmadminweb/API/import/", jstr, cookies)
        pprint(data)

if __name__ == '__main__':
    main()
