"""
Copyright 2019-2021 VMware, Inc.  All rights reserved. -- VMware Confidential
Utility Module
"""

import os
import sys
import shutil
import logging

sys.path.append(os.environ['VMWARE_PYTHON_PATH'])
from cis.utils import readprop, replace_properties_in_file, write_props_to_file
from cis.utils import invoke_command
from cis.defaults import get_psql_bin
from cis.exceptions import InvokeCommandException
from patch_errors import UserError

COMPONENT_NAME = 'vstats'
vstats_patch_key = 'vstats.patch.version'

logger = logging.getLogger(__name__)


def get_config_dir():
    return '/etc/vmware-%s' % COMPONENT_NAME

# The file will be installed as part of the target deployment 
# in case of a nondisruptive upgrade.
# During upgrade, we need to preserve its original content in the
# @Expand hook in order to be
# available in the target appliance.
__VERSION_FILE__ = '%s/vstats_version.txt' % get_config_dir()
__VERSION_FILE_NAME__ = 'vstats_version.txt'

VPOSTGRES_DEFAULT_PORT = 5432
VTSDB_DEFAULT_PORT = 5433
cfg = {}
cfg['VSTATS_SERVICE_USER'] = 'vstatsuser'
# Database
cfg['VTSDB_CORE_DB'] = 'VCDB'
cfg['VTSDB_STATS_DB'] = 'vstats_db'
# Path to Socket directory of vpostgres
cfg['VPOSTGRES_SOCKET_DIR'] = '/var/run/vpostgres'
# Path to Socket directory of vtsdb
cfg['VTSDB_SOCKET_DIR'] = '/var/run/vtsdb'
# vTsdb server port
cfg['VTSDB_SERV_PORT'] = VTSDB_DEFAULT_PORT

cfg['PG_SERV_PORT'] = VPOSTGRES_DEFAULT_PORT

def getSourceVersion(parentDir, fileName=__VERSION_FILE_NAME__):
    ''' Loads current component version from file located at @parentDir
    and named @fileName
    '''
    filePath = os.path.join(parentDir, fileName)
    if os.path.exists(filePath):
            version = readprop(filePath, vstats_patch_key)
    else:
        version = None
    return version

def is_patch_needed(curr_version, target_patch_version):
    """
    This function will check if the patch to target_patch_version is required
    :param curr_version:
    :param target_patch_version:
    :return:
    """
    if curr_version < target_patch_version:
        return True
    return False

def preserveVersionFile(stageDir, filePath=__VERSION_FILE__):
    """ Persists the version file in the stage directory

    @param stageDir: Directory to preserve the version file in.
    """
    if os.path.exists(filePath):
        shutil.copy(filePath, stageDir)
    else:
        logger.info("Version file doesn't exist!! This may be a fresh install of vstats")

def runCoreDBScript(coredb_patch_script):
    """
    This function will apply the vstats schema changes
    on VCDB
    """
    core_db_patch_cmd = [get_psql_bin(),
           '-U', 'vstatsuser',
           '-d%s' %cfg['VTSDB_CORE_DB'],
           '-f', coredb_patch_script,
           '-p%s' %cfg['PG_SERV_PORT'],
           '-w',
           '-X',
           '-h%s' %cfg['VPOSTGRES_SOCKET_DIR'],
           '-v', 'ON_ERROR_STOP=ON']
    try:
        logger.info("Running the coredb patch script")
        logger.info("Running command: " + str(core_db_patch_cmd))
        invoke_command(core_db_patch_cmd, log_command=False)
        logger.info('Core DB patch script executed successfully')
    except InvokeCommandException as e:
        err_msg = "Failed to execute core DB patch script {} on database {}"\
        .format(coredb_patch_script, cfg['VTSDB_CORE_DB'])
        logger.error(err_msg)
        user_error = UserError(err_msg)
        raise user_error

def runStateDBScript(sttdb_patch_script):
    """
    This function will apply the vstats schema changes
    on vstats_db
    """
    stt_db_patch_cmd = [get_psql_bin(),
                        '-U%s' % cfg['VSTATS_SERVICE_USER'],
                        '-d%s' % cfg['VTSDB_STATS_DB'],
                        '-f', sttdb_patch_script,
                        '-p%s' % cfg['VTSDB_SERV_PORT'],
                        '-w',
                        '-X',
                        '-h%s' % cfg['VTSDB_SOCKET_DIR'],
                        '-v', 'ON_ERROR_STOP=ON']
    try:
        logger.info("Running the state db patch script")
        logger.info("Running command: " + str(stt_db_patch_cmd))
        invoke_command(stt_db_patch_cmd, log_command=False)
        logger.info('State DB patch script executed successfully')
    except InvokeCommandException as e:
        err_msg = "Failed to execute state DB patch script {} on database {}"\
        .format(stt_db_patch_cmd, cfg['VTSDB_STATS_DB'])
        logger.error(err_msg)
        user_error = UserError(err_msg)
        raise user_error
