# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
#          http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
#############################################################################
import pwd
import time
import subprocess
import logging.handlers
import os
from gspylib.common.Common import DefaultValue
from gspylib.common.ErrorCode import ErrorCode
from base_utils.common.constantsbase import ConstantsBase

# max log file size
# 16M
MAXLOGFILESIZE = 16 * 1024 * 1024
KEY_FILE_MODE = 600


class LoggerFactory():
    def __init__(self):
        pass

    @staticmethod
    def getLogger(module, logFile, user=""):
        """
        function : config log handler
        input : module, logFileName, logLevel
        output : log
        """
        afilename = LoggerFactory.getLogFileName(os.path.realpath(logFile))
        if (not os.path.exists(afilename)):
            dirName = os.path.dirname(afilename)
            cmd = "if [ ! -d %s ]; then mkdir %s -p -m %s;fi" % (
                dirName, dirName, DefaultValue.KEY_DIRECTORY_MODE)
            cmd += ";touch %s && chmod %s %s" % (
                afilename, KEY_FILE_MODE, afilename)
            # The user exists and is not the current user
            if (user and pwd.getpwnam(user).pw_uid != os.getuid()):
                cmd = "su - %s -c \"%s\" " % (user, cmd)
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status != 0):
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50206"]
                                % ("log file [%s]" % afilename) +
                                "Error:\n%s" % output +
                                "The cmd is %s " % cmd)
        log = logging.getLogger(module)
        LoggerFactory._addFileHandle(log, afilename)
        LoggerFactory._addConsoleHandle(log)
        return (log, afilename)

    @staticmethod
    def getLogFileName(oldLogFile):
        """
        function : Increase the time stamp and check the file size
        input : logFileName
        output : String
        """
        # get current time
        currentTime = time.strftime("%Y-%m-%d_%H%M%S")
        # Check log file correctness
        dirName = os.path.dirname(oldLogFile)
        originalFileName = os.path.basename(oldLogFile)
        resList = originalFileName.split(".")
        if (len(resList) > 2):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50235"] % oldLogFile)
        (prefix, suffix) = os.path.splitext(originalFileName)
        if (suffix != ".log"):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50212"]
                            % (oldLogFile, ".log"))
        # The log file have time stamped in -L mode
        if (len(originalFileName) > 21):
            timeStamp = originalFileName[-21:-4]
            if (LoggerFactory.is_valid_date(timeStamp)):
                return oldLogFile

        # Defaults log file
        newLogFile = dirName + "/" + prefix + "-" + currentTime + suffix
        if (os.path.isdir(dirName)):
            # Check old log file list
            cmd = "ls %s | grep '^%s-' | grep '%s$'" % (
                dirName, prefix, suffix)
            (status, output) = subprocess.getstatusoutput(cmd)
            if (status == 0):
                filenameList = []
                for echoLine in output.split("\n"):
                    filename = echoLine.strip()
                    existedResList = filename.split(".")
                    if (len(existedResList) > 2):
                        continue
                    existedSuffix = os.path.splitext(filename)[1]
                    if (existedSuffix != ".log"):
                        continue
                    if (len(originalFileName) + 18 != len(filename)):
                        continue
                    timeStamp = filename[-21:-4]
                    # check log file name
                    if (LoggerFactory.is_valid_date(timeStamp)):
                        pass
                    else:
                        continue
                    # Add the valid log file
                    filenameList.append(filename)

                if (len(filenameList)):
                    fileName = max(filenameList)
                    logFile = dirName + "/" + fileName.strip()
                    # check if need switch to an new log file
                    size = os.path.getsize(logFile)
                    if (size <= MAXLOGFILESIZE):
                        newLogFile = logFile
        return newLogFile

    @staticmethod
    def is_valid_date(datastr):
        '''
        Judge if date valid
        '''
        try:
            time.strptime(datastr, "%Y-%m-%d_%H%M%S")
            return True
        except Exception:
            return False

    @staticmethod
    def _addFileHandle(log, fileName):
        # create log file
        if not os.path.exists(os.path.dirname(fileName)):
            dir_permission = 0o700
            os.makedirs(os.path.dirname(fileName), mode=dir_permission)
        else:
            if oct(os.stat(fileName).st_mode)[-3:] != '600':
                os.chmod(fileName, ConstantsBase.KEY_FILE_PERMISSION)

        fmt = logging.Formatter(
            '[%(asctime)s][%(filename)s][line:%(lineno)d][%(levelname)s] '
            '%(message)s',
            '%Y-%m-%d %H:%M:%S')
        # output the log to a file
        # 16M takes precedence over 20M, Here cut the file does not trigger
        rthandler = logging.handlers.RotatingFileHandler(
            fileName,
            maxBytes=20 * 1024 * 1024,
            backupCount=2)
        rthandler.setFormatter(fmt)
        rthandler.setLevel(logging.DEBUG)
        log.handlers = []
        log.addHandler(rthandler)

    @staticmethod
    def _addConsoleHandle(log):
        fmt = logging.Formatter('%(message)s')
        # output the log to screen the same time
        console = logging.StreamHandler()
        console.setFormatter(fmt)
        console.setLevel(logging.INFO)
        log.addHandler(console)
        log.setLevel(logging.DEBUG)
