import logging
import os
import subprocess

from math import ceil
from shlex import split

from subprocess import getstatusoutput

current_query_count = 0
total_query = 0
failed_query = 0
logcount = 1
errorlogcount = 1


def file_check(file):
    filesize = ceil((os.path.getsize(file) / 1024) / 1024)

    # File size limited to 5MB
    if filesize >= 5:
        if 'error' in file:
            global errorlogcount
            cmd = "mv {0} {0}.{1}".format(file, errorlogcount)
            getstatusoutput(cmd)
            errorlogcount = errorlogcount + 1
            cmd = "touch {0}".format(file)
            getstatusoutput(cmd)
        else:
            global logcount
            cmd = "mv {0} {0}.{1}".format(file, logcount)
            getstatusoutput(cmd)
            logcount = logcount + 1
            cmd = "touch {0}".format(file)
            getstatusoutput(cmd)

        cmd = "chmod 600 {0} ".format(file)
        getstatusoutput(cmd)


def get_log_count():
    return logcount


def get_error_log_count():
    return errorlogcount


def execute_script(cmd):
    """Execute the given command and write to file"""
    args = split_command(cmd)
    try:
        process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, unused_err = process.communicate(timeout=20)
        output = output.decode()
        return process.poll(), unused_err or output
    except (OSError, IOError) as error:
        logging.error(error)
        return 1, str(error.strerror)


def execute_script_write(cmd, outputfilename, file_name, errorlogfile):
    """Execute the given command and write to file"""
    args = split_command(cmd)
    file_check(outputfilename)
    file_check(errorlogfile)
    filename = os.fdopen(os.open(outputfilename, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    errorfilename = os.fdopen(os.open(errorlogfile, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    global current_query_count
    try:
        process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, unused_err = process.communicate(timeout=20)
        output = output.decode()
        filename.writelines(file_name)
        filename.writelines('\n')
        filename.writelines(output)
        if unused_err is not None:
            unused_err = unused_err.decode()
            if 'error' in unused_err or 'ERROR' in unused_err:
                filename.writelines(unused_err)
                errorfilename.writelines('Compiling the file ')
                errorfilename.writelines(file_name)
                errorfilename.writelines('\n')
                errorfilename.writelines(unused_err)
        current_query_count = current_query_count + 1
        return process.poll(), unused_err or output
    except (OSError, IOError, UnicodeDecodeError) as error:
        current_query_count = current_query_count + 1
        logging.error(error)
        return 1, str(error)
    finally:
        filename.close()
        errorfilename.close()


def execute_script_write_t(cmd, outputfilename, errorlogfile, file_name, line_number, flag):
    """Execute the given command and write to file"""
    args = split_command(cmd)
    file_check(outputfilename)
    file_check(errorlogfile)
    filename = os.fdopen(os.open(outputfilename, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    errorfilename = os.fdopen(os.open(errorlogfile, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    global total_query
    global failed_query
    try:
        process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, unused_err = process.communicate(timeout=20)
        output = output.decode()
        if flag:
            filename.writelines("Compiling the file ")
            filename.writelines(file_name)
            filename.writelines('\n')
        if 'GS-' in output or 'error' in output:
            errorlines = output.split('\n')
            errorfilename.writelines('\n')
            errorfilename.writelines(file_name)
            filename.writelines(file_name)
            filename.writelines('\n')
            for lne in errorlines:
                if len(lne) > 0 and lne[0] == '[':
                    value = lne[1:lne.find(':')]
                    if value.isdigit:
                        string = int(value) + line_number - 1
                        lne = lne.replace(value, str(string))
                        errorfilename.writelines(lne)
                        filename.writelines(lne)
                    else:
                        errorfilename.writelines(lne)
                        filename.writelines(lne)
                else:
                    errorfilename.writelines(lne)
                    filename.writelines(lne)
                filename.writelines('\n')
                errorfilename.writelines('\n')
            failed_query = failed_query + 1

        else:
            filename.writelines(output)
        if unused_err is not None:
            unused_err = unused_err.decode()
            if 'error' in unused_err or 'ERROR' in unused_err:
                filename.writelines(unused_err)
                errorfilename.writelines(unused_err)
        total_query = total_query + 1
        return process.poll(), unused_err or output
    except (OSError, IOError, UnicodeDecodeError) as error:
        total_query = total_query + 1
        logging.error(error)
        return 1, str(error)
    finally:
        filename.close()
        errorfilename.close()


def total_dbt_query():
    return total_query


def failed_dbt_query():
    return failed_query


def split_command(cmd):
    """Split command for subprocess execution"""
    return split(cmd)


def getquerycount():
    return current_query_count


def setquerycount(value):
    global current_query_count
    current_query_count = value


def execute_pre_setup_file(cmd, outputfilename, outputerrorfilename, filename):
    """Execute the given command and write to file"""
    args = split_command(cmd)
    logfile = os.fdopen(os.open(outputfilename, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    errorlogfile = os.fdopen(os.open(outputerrorfilename, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    error_flag = False
    try:
        process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, unused_err = process.communicate(timeout=20)
        output = output.decode()

        logfile.writelines(output)
        if unused_err is not None:
            unused_err = unused_err.decode()
            if 'error' in unused_err or 'ERROR' in unused_err:
                logfile.writelines('\n')
                logfile.writelines(unused_err)
                logfile.writelines('\n')
                errorlogfile.writelines("Pre Verification executing the file : {}".format(filename))
                errorlogfile.writelines('\n')
                errorlogfile.writelines(unused_err)
                errorlogfile.writelines('\n')
                error_flag = True
        return process.poll(), error_flag
    except (OSError, IOError, UnicodeDecodeError) as error:
        logging.error(error)
        return 1, str(error)
    finally:
        logfile.close()
        errorlogfile.close()


def execute_pre_setup_file_t(cmd, outputfilename, outputerrorfilename, filename):
    """Execute the given command and write to file"""
    args = split_command(cmd)
    logfile = os.fdopen(os.open(outputfilename, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    errorlogfile = os.fdopen(os.open(outputerrorfilename, os.O_WRONLY | os.O_CREAT, 0o640), 'a')
    error_flag = False
    try:
        process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        output, unused_err = process.communicate(timeout=20)
        output = output.decode()

        logfile.writelines(output)
        if 'GS-' in output or 'error' in output or 'ERROR' in output:
            errorlogfile.writelines("Pre Verification executing the file : {}".format(filename))
            errorlogfile.writelines('\n')
            errorlogfile.writelines(output)
            errorlogfile.writelines('\n')
            error_flag = True
        if unused_err is not None:
            unused_err = unused_err.decode()
            if 'error' in unused_err or 'ERROR' in unused_err:
                logfile.writelines(unused_err)
                errorlogfile.writelines(unused_err)
        return process.poll(), error_flag
    except (OSError, IOError, UnicodeDecodeError) as error:
        logging.error(error)
        return 1, str(error)
    finally:
        logfile.close()
