#!/usr/bin/env python3
# -*- coding:utf-8 -*-


try:
    import sys
    import importlib

    importlib.reload(sys)
    import os
    import psutil
    from gspylib.inspection.common import SharedFuncs
    from gspylib.inspection.common.CheckItem import BaseItem
    from gspylib.hardware.gsdisk import g_disk
except ImportError as ie:
    raise Exception("[GAUSS-52200] : Unable to import module: %s." % str(ie))


class CheckSpaceUsage(BaseItem):
    def __init__(self):
        super(CheckSpaceUsage, self).__init__(self.__class__.__name__)
        self.diskVailPGHOST = None
        self.diskVailGPHOME = None
        self.diskVailGAUSSHOME = None
        self.diskVailGAUSSLOG = None
        self.diskVailOS_TMP = None
        self.diskVailDATA = None
        self.Threshold_NG = None
        self.Threshold_Warning = None

    def preCheck(self):
        # check current node contains cn instances if not raise  exception
        super(CheckSpaceUsage, self).preCheck()
        # check the threshold was set correctly
        if not self.threshold.__contains__('DiskVailPGHOST'):
            raise Exception("threshold  DiskVailPGHOST can not be empty")
        if not self.threshold.__contains__('DiskVailGPHOME'):
            raise Exception("threshold DiskVailGPHOME can not be empty")
        if not self.threshold.__contains__('DiskVailGAUSSHOME'):
            raise Exception("threshold DiskVailGAUSSHOME can not be empty")
        if not self.threshold.__contains__('DiskVailGAUSSLOG'):
            raise Exception("threshold DiskVailGAUSSLOG can not be empty")
        if not self.threshold.__contains__('DiskVailOS_TMP'):
            raise Exception("threshold DiskVailOS_TMP can not be empty")
        if not self.threshold.__contains__('DiskVailDATA'):
            raise Exception("threshold DiskVailDATA can not be empty")

        if not (self.threshold.__contains__('Threshold_NG') and self.threshold.__contains__('Threshold_Warning')):
            raise Exception("The threshold Threshold_NG and Threshold_Warning can not be empty.")
        if not self.threshold['Threshold_NG'].isdigit() or not self.threshold['Threshold_Warning'].isdigit():
            raise Exception("The threshold Threshold_NG and Threshold_Warning must be integer.")
        self.Threshold_NG = int(self.threshold['Threshold_NG'])
        self.Threshold_Warning = int(self.threshold['Threshold_Warning'])
        if self.Threshold_NG < self.Threshold_Warning:
            raise Exception("The threshold Threshold_NG must be greater than Threshold_Warning.")
        if self.Threshold_NG > 99 or self.Threshold_Warning < 1:
            raise Exception("The threshold Threshold_NG and Threshold_Warning must be integer from 1 to 99.")

        self.diskVailPGHOST = self.threshold['DiskVailPGHOST']
        self.diskVailGPHOME = self.threshold['DiskVailGPHOME']
        self.diskVailGAUSSHOME = self.threshold['DiskVailGAUSSHOME']
        self.diskVailGAUSSLOG = self.threshold['DiskVailGAUSSLOG']
        self.diskVailOS_TMP = self.threshold['DiskVailOS_TMP']
        self.diskVailDATA = self.threshold['DiskVailDATA']

    def obtainDataDir(self, nodeInfo):
        dataDirList = {os.getenv("PGHOST"): ["PGHOST", self.diskVailPGHOST],
                       os.getenv("GPHOME"): ["GPHOME", self.diskVailGPHOME],
                       os.getenv("GAUSSHOME"): ["GAUSSHOME", self.diskVailGAUSSHOME],
                       os.getenv("GAUSSLOG"): ["GAUSSLOG", self.diskVailGAUSSLOG],
                       "/tmp": ["OS_TMP", self.diskVailOS_TMP]}
        for inst in nodeInfo.datanodes:
            dataDirList[inst.datadir] = ["DN", self.diskVailDATA]
        for inst in nodeInfo.cmservers:
            dataDirList[inst.datadir] = ["CMS", 0]
        for inst in nodeInfo.coordinators:
            dataDirList[inst.datadir] = ["CN", 0]
        for inst in nodeInfo.gtms:
            dataDirList[inst.datadir] = ["GTM", 0]
        if hasattr(nodeInfo, 'etcds'):
            for inst in nodeInfo.etcds:
                dataDirList[inst.datadir] = ["ETCD", 0]

        return dataDirList

    def obtainDiskDir(self):
        cmd = "df -h -P | awk '{print $NF}'"
        output = SharedFuncs.runShellCmd(cmd)
        allDiskPath = output.split('\n')[1:]
        return allDiskPath

    def doCheck(self):
        flag = "Normal"
        resultStr = ""
        DiskList = []
        DiskInfoDict = {}
        pathDisk = {}
        if self.cluster:
            pathDisk = self.obtainDataDir(self.cluster.getDbNodeByName(self.host))
            pathList = list(pathDisk.keys())
        else:
            pathList = self.obtainDiskDir()
        for path in pathList:
            diskName = g_disk.getMountPathByDataDir(path)
            usageInfo = round(g_disk.getDiskSpaceUsage(path), 2)
            diskInfo = "%s %s%%" % (diskName, usageInfo)
            if diskName in DiskList:
                continue
            else:
                DiskList.append(diskName)
            DiskInfoDict[usageInfo] = diskInfo
            rateNum = usageInfo
            if rateNum > self.Threshold_NG:
                resultStr += "The usage of the device disk space[%s:%d%%] cannot be greater than %d%%.\n" % (
                    diskName, rateNum, self.Threshold_NG)
                flag = "Error"
            elif rateNum > self.Threshold_Warning:
                resultStr += "The usage of the device disk space[%s:%d%%] cannot be greater than %d%%.\n" % (
                    diskName, rateNum, self.Threshold_Warning)
                if flag == "Normal":
                    flag = "Warning"

            if pathDisk:
                if diskInfo:
                    AvailableSpace = psutil.disk_usage(path).free / 1024 / 1024 / 1024
                    minSpace_KB = float(pathDisk[path][1])
                    if AvailableSpace < minSpace_KB:
                        resultStr += "The %s path [%s] where the disk available space[%.1fGB] is less than %.1fGB.\n" \
                                     % (pathDisk[path][0], path, AvailableSpace, minSpace_KB)
                        flag = "Error"
                else:
                    raise Exception("Filed to analysis the disk information. Error:\n%s" % diskInfo)
        self.result.val = resultStr
        self.judge_status_by_flag(flag, "All disk space are sufficient.")

        keys = list(DiskInfoDict.keys())
        keys.sort()
        MaxDisk = list(map(DiskInfoDict.get, keys))[-1]
        MinDisk = list(map(DiskInfoDict.get, keys))[0]
        self.result.val += "\nDisk     Filesystem spaceUsage\nMax free %s\nMin free %s" % (MaxDisk, MinDisk)
        for diskInfo in map(DiskInfoDict.get, keys):
            self.result.raw = "%s\n%s" % (self.result.raw, diskInfo)
