import os
import sys
import time
import datetime
import logging
from subprocess import getoutput, getstatusoutput


try:
    sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.
        realpath(__file__)))))))
    from scripts.verifyGaussPython.src.python import gaussDBThread
    from scripts.verifyGaussPython.src.python.PropertyFile import read_file
    from scripts.verifyGaussPython.src.python.gaussDBThread import gaussdbexecutiontask
    from scripts.verifyGaussPython.src.python.querycount import writeandprintoutput, print_log_check, \
        writeandprintoutputdbt, clearlogfile, gettotalquerystatus, gettypecountstatus
    from scripts.verifyGaussPython.src.python.run_utils import rungaussdbtconnection, rungaussdbaconnection, \
        run_pre_setup_file_a, run_pre_setup_file_t
    from scripts.verifyGaussPython.src.python.shell_utils import getquerycount, setquerycount


except ImportError as err:
    print("Verification Module inclusion failed.  Error: " + str(err))
    sys.exit(1)

configdata = dict()
outputfol = None
homepath = None
dbtype = None
logpath = None


def main():
    start = datetime.datetime.now()
    result = precheck()
    if result == 1:
        postcleanup(outputfol)
        print("\n********************** Verification Completed ****************************\n\n")
        return result

    print("Sql script execution on Gauss DB start time :", getoutput('date'))

    importddltogauss(configdata)
    if dbtype == 'gaussdba':
        gettotalquerystatus(outputfol, homepath)
        gettypecountstatus(logpath)
        writeandprintoutput(logpath)
    else:
        writeandprintoutputdbt(logpath)

    relationexistancecheck()

    postcleanup(outputfol)

    result = print_log_check()
    print("Gauss Execution Log file : {0} ".format(os.path.join(logpath, 'gaussexecutionlog.log')))
    if result == 1:
        print("Gauss Execution Error Log file : {0} ".format(os.path.join(logpath, 'gaussexecutionerror.log')))
    finish = datetime.datetime.now()

    print("Verification finished in {0} seconds".format((finish - start).seconds))
    print("\n********************** Verification Completed ****************************\n\n")
    return result


def importddltogauss(config_data):
    """  Take the migrated script and execute on gaussdb """
    outputfolder = os.path.join(outputfol, 'output')
    totalquery = totalquerycountdir(outputfolder)
    if totalquery == 0:
        print("No sql files found")
        logging.info("Total query is %s", totalquery)
        return
    argument = ([totalquery])
    progressthreads = gaussDBThread.Thread(target=importprogress, args=argument)
    progressthreads.daemon = True
    progressthreads.start()
    logging.info("Gaussdb execution started")
    for dirs_file_name in sorted(os.walk(outputfolder)):
        currentcounttemp = getquerycount()
        totalfoldercounttemp = totalquerycountdirtemp(dirs_file_name)
        totalcounttemp = currentcounttemp + totalfoldercounttemp
        gaussdbexecutiontask(dirs_file_name, config_data, homepath, outputfol, logpath)
        while True:
            if totalcounttemp == 0:
                break
            if getquerycount() >= totalcounttemp:
                break
            time.sleep(1)

    if progressthreads.is_alive():
        progressthreads.join()
    setquerycount(0)
    print("\rSql script execution on Gauss DB end time :", getoutput('date'))

    logging.info("Gaussdb execution completed")


def importprogress(totalquery):
    """ Import to gaussdb progress """

    time.sleep(1)
    if totalquery == 0:
        logging.error("Total query is %s", totalquery)
        return

    while True:
        currentqueryno = getquerycount()

        num = "{0}%   [FILE ({1}/{2})]      ".format(int((currentqueryno * 100) / totalquery), currentqueryno,
                                                     totalquery)
        if currentqueryno >= totalquery:
            time.sleep(0.5)
            print("\r  100% Completed                            ", end="")
            sys.stdout.flush()
            return
        print("\r Compilation Progress  {0}".format(num), end="")
        sys.stdout.flush()
        time.sleep(1)


def relationexistancecheck():
    """ This method will print message, if there is some dependent objects in scripts """
    log_path = os.path.join(logpath, 'gaussexecutionerror.log')

    cmd = "grep -w \"does not exist\" {0}|wc -l".format(log_path)
    output = getoutput(cmd)
    value = None
    if output.isdigit():
        value = int(output)
    if value is not None:
        if value == 0:
            cmd = "grep -w \"doesn't exist\" {0}|wc -l".format(log_path)
            output = getoutput(cmd)
            if output.isdigit():
                value = int(output)

        if value > 0:
            print("[WARN]: We recognized that some dependent relations (Schema/Objects) are missing in the "
                  "db/scripts, which is affecting the overall Success Rate. ")
            print("Please check the errors in the below error log file and take necessary action.\n")


def totalquerycountdirtemp(dir_name):
    """ Returns the sql file count """
    return len(dir_name[2])


def totalquerycountdir(input_path):
    """ Returns the sql file count in folder """
    count = 0
    for dirs_file_name in os.walk(input_path):
        count = count + len(dirs_file_name[2])
    return count


def postcleanup(output_fol):
    """ Post clean up of range mapper folder """
    if output_fol is not None:
        folder = os.path.join(output_fol, 'rangeMapper')
        if os.path.exists(folder):
            cmd = "rm -rf {flename}*".format(flename=folder)
            getstatusoutput(cmd)


def run_pre_execution_file(argumentlist):
    ip = configdata.get('gaussdb-ip')
    port = configdata.get('gaussdb-port')
    username = configdata.get('gaussdb-user')
    password = configdata.get('gaussdb-password')
    dbname = configdata.get('gaussdb-name')
    querypath = None
    if len(argumentlist) == 6:
        querypath = argumentlist[5].strip()

    if querypath is None or '' == querypath.strip():
        return 0
    logoutputfile = os.path.join(logpath, 'preverificationexecution.log')
    if not os.path.exists(logoutputfile):
        cmd = "touch {0}".format(logoutputfile)
        getstatusoutput(cmd)
        cmd = "chmod 600 {0} ".format(logoutputfile)
        getstatusoutput(cmd)
    logoutputerrorfile = os.path.join(logpath, 'preverificationexecutionerror.log')
    if not os.path.exists(logoutputerrorfile):
        cmd = "touch {0}".format(logoutputerrorfile)
        getstatusoutput(cmd)
        cmd = "chmod 600 {0} ".format(logoutputerrorfile)
        getstatusoutput(cmd)

    stime = getoutput('date')
    logfile = os.fdopen(os.open(logoutputfile, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    logfile.writelines("Pre Verification step start time : {}".format(stime))
    logfile.writelines('\n')
    logfile.close()
    print("Pre Verification step start time : {}".format(stime))
    error_present = False
    for dirs_file_name in sorted(os.walk(querypath)):
        for fle in sorted(dirs_file_name[2], key=str.lower):
            filename = os.path.join(dirs_file_name[0], fle)
            writelog(logoutputfile, "Pre Verification executing the file : {}".format(filename))
            if dbtype == 'gaussdba':
                pre_result = run_pre_setup_file_a(dbname, port, username, password, ip, filename,
                                                  logoutputfile, logoutputerrorfile)
                if pre_result[1]:
                    error_present = True
            else:
                pre_result = run_pre_setup_file_t(username, password, ip, port, filename,
                                                  logoutputfile, logoutputerrorfile)
                if pre_result[1]:
                    error_present = True

    etime = getoutput('date')
    print("Pre Verification step end time : {}".format(etime))
    writelog(logoutputfile, "Pre Verification end time : {}".format(etime))

    if error_present:
        print("\nPre Verification execution step failed, Verification step will not be executed. ")
        print("Check the error information in the log and correct the issues in pre verification.\n")
        print("Pre Verification Log file : {0} ".format(logoutputfile))
        print("Pre Verification Error Log file : {0} \n".format(logoutputerrorfile))
        return 1

    print("Pre Verification Log file : {0} \n".format(logoutputfile))
    return 0


def writelog(logoutputfile, message):
    logfile = os.fdopen(os.open(logoutputfile, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    logfile.writelines(message)
    logfile.writelines('\n')
    logfile.close()


def precheck():
    """ Precheck """
    try:
        argumentlist = sys.argv

        # no of argumnet check
        if len(argumentlist) != 5 and len(argumentlist) != 6:
            print("Invalid number of arguments")
            return 1

        global homepath
        homepath = argumentlist[1].strip()

        # home path check
        if not os.path.exists(homepath):
            print("Home path does not exist")
            return 1

        outputfolder = argumentlist[2].strip()
        # output path check
        if not os.path.exists(outputfolder):
            print("Output folder path does not exist")
            return 1

        global outputfol
        outputfol = outputfolder

        logfolder = argumentlist[4].strip()
        # log path check
        if not os.path.exists(logfolder):
            print("Log folder path does not exist")
            return 1

        global logpath
        logpath = logfolder

        path = os.path.join(homepath, 'config', 'gaussdb.properties')
        # config path check
        if not os.path.exists(path):
            print("Migration config path does not exist")
            return 1

        global configdata
        configdata = read_file(path)

        log_file_name = os.path.join(logpath, 'verification.log')
        if not os.path.exists(log_file_name):
            cmd = "touch {0}".format(log_file_name)
            getstatusoutput(cmd)
            cmd = "chmod 600 {0} ".format(log_file_name)
            getstatusoutput(cmd)

        # clear the log
        clearlogfile(logpath)

        gaussdbpass = os.environ['gaussdb-password'].strip()
        gaussdbpass = "\"" + gaussdbpass.replace("\"", "\\\"") + "\""
        os.environ['gaussdb-password'] = ''
        global dbtype
        dbtype = argumentlist[3].strip()
        configdata['gaussdb-type'] = dbtype
        # Gauss DB Password check
        if '' == gaussdbpass:
            print("GaussDB Password cannot be empty")
            return 1

        # update gaussdbpassword
        configdata['gaussdb-password'] = gaussdbpass

        logging.basicConfig(filename=log_file_name, level=logging.DEBUG,
                            format='%(asctime)s:%(levelname)s:%(filename)s:%(lineno)s:%(message)s')

        # DB connection check
        gaussresult = None
        if configdata['gaussdb-type'] == 'gaussdbt':
            gaussresult = rungaussdbtconnection(configdata)
            if gaussresult[0] == 0:
                pre_result = run_pre_execution_file(argumentlist)
                if pre_result != 0:
                    return 1
        else:
            gaussresult = rungaussdbaconnection(configdata)
            if gaussresult[0] == 0:
                pre_result = run_pre_execution_file(argumentlist)
                if pre_result != 0:
                    return 1
        if gaussresult[0] != 0:
            print("Gauss DB connection failed")
            logging.error("DB connection failed :%s", gaussresult[1])
            return 1
        return 0

    except (IOError, OSError) as exception:
        logging.error("Error occurred %s", exception)
        return 1


if __name__ == '__main__':
    try:
        res = main()
        if res == 1:
            logging.error("Gauss DB Execution Failed\n")
        else:
            logging.info("Task Completed Successfully")
    except (Exception) as error:
        logging.error("Error occurred %s ", error)
