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

__version__ = '9.3.55'

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

import click
import qtoml

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('--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, kind, deployenv, envs, compattr, from_domain, task, envvars, envvars_sh, importfile, fromdom, todom):
    """
    ACTION is (deploy, updatecomp, approve, move, envscript, 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
    assign: assigns a component version to an application verion
    envscript: creates a bash file from the component toml file
    export: exports a domain including all objects to stdout
    import: imports the export file into the new domain
    """

    if (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]

        if (appversion.lower() == "latest"):
            data = dhapi.get_application(dhurl, cookies, appname, "", False)
            latest_appid = data[2]
            appname = dhapi.get_application_name(dhurl, cookies, latest_appid, True)
            appversion = ""
            
        print(f'Deploying {appname} {appversion} 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(f"Creating Component")
            compid = dhapi.new_component_version(dhurl, cookies, compname, compvariant, compversion, kind, None)
            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() == "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)

            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()
