# -*- coding: UTF-8 -*-

import java.lang.Exception as JException
from com.huawei.ism.tool.obase.exception import PwdCLIOverrunException

from common.constant import PATCH_TYPE, PATCH_EVALU
from common import resourceParse
from common.baseFactory import log
from common import checkUtils
from common.checkUtils import CheckItemObserver
from checkitems import ad_domain_connectivity_check
from checkitems import DaemonProcessCheck
from cbb.business.collect import products_adapter
from cbb.frame.base import baseUtil
from cbb.business.checkitems.UpdateInnerCheckVersion import VersionUpdate
from checkitems import check_ras_cnt_before_upgrade
from checkitems import check_1822_exception_hotpatch
from checkitems import check_power_upgrade_state
from checkitems import check_admin_to_power_upgrade
from checkitems import check_systemdisk_risk
from cbb.business.checkitems.SystemInnerCheck import UpgradeCheck
from cbb.business.checkitems.IgnoreCheck4Patch import ignore_precheck

# 补丁评估检查项参数
HOT_PATCH_EVALUATE = "HotpatchEvaluate"
# 热补丁安装前检查参数
HOT_PATCH_PRECHECK = "HotpatchPrecheck"
# 创建SSH连接失败信息
SSH_CONNECT_ERROR_MSG = "'NoneType' object has no attribute 'getCli'"


@ignore_precheck
def execute(dataDict):
    context = dataDict.get("context")
    lang = dataDict.get('lang')
    resource = resourceParse.execute(lang)
    dataDict["resource"] = resource
    deviceSN = str(dataDict.get('dev').getDeviceSerialNumber())
    patchType = context.get("patchType_%s" % deviceSN)
    log.info(dataDict, "patchType:===============" + patchType)

    patch_evalu = False
    dev = dataDict.get('dev')
    if dev.getMatchType() == PATCH_EVALU:
        patchType = PATCH_TYPE.HOT_PATCH
        patch_evalu = True

    try:
        checkObserver = CheckItemObserver(dataDict, "precheck")
        if patchType == PATCH_TYPE.HOT_PATCH:
            checkType = get_check_type(dataDict, patch_evalu)
            log.info(dataDict, "[PreCheck]user setted checkType is :" + checkType)
            flowchoiceNum = dataDict.get('flowchoice')
            dataDict.update(checkType=checkType, flowchoice=flowchoiceNum, observer=checkObserver)

            preCheck = UpgradeCheck(dataDict)
            checkResult = preCheck.execute()
            if not checkResult[0]:
                return False, checkResult[1], ""
            err_msg_list = []
            if not patch_evalu:
                # 如果是补丁评估工具，不能执行自己实现的检查项，补丁评估在配置文件中配置有检查项；
                check_item_local(dataDict, err_msg_list)
            check_inner_item(checkObserver, patch_evalu, err_msg_list)
            if err_msg_list:
                return False, '\n'.join(err_msg_list), ''
            return True, '', None
        elif patchType == PATCH_TYPE.ASL_PATCH:
            return True, '', None
        else:
            log.error(dataDict, u'Failed to obtain the patch package type.   PATCH_TYPE:{}'.format(patchType))
            return False, resource.get('upload.pkgTypeAbnormality'), None
    except PwdCLIOverrunException as pwd_cli_over_exception:
        log.error(dataDict,
                  u'Remaining memory is less than 130 MB, or the CLI reaches limit：{}'.format(pwd_cli_over_exception))
        return False, resource.get('upgrade.error.cli.over.run'), None
    except (JException, Exception) as e:
        log.error(dataDict, u'An exception occurs during the pre-patch check.：{}'.format(e))
        if SSH_CONNECT_ERROR_MSG in str(e):
            return False, resource.get("upgrade.error.cli.connect.failed"), None
        return False, resource.get('upgrade.precheck.notpassed'), None


def get_check_type(data_dict, patch_evalu):
    """
    功能描述：补丁评估中6.1.3版本下发类型 改成HotpatchEvaluate
    :param data_dict:上下文
    :param patch_evalu:是否补丁评估
    :return: check_type
    """
    product_version = data_dict.get("dev").getProductVersion()
    dev_type = str(data_dict.get("dev").getDeviceType())
    log.info(data_dict, "[PreCheck]product_version is :{}, dev_type:{}".format(product_version, dev_type))
    if is_hot_patch_evaluate_scene(data_dict, patch_evalu, dev_type, product_version):
        return HOT_PATCH_EVALUATE
    return HOT_PATCH_PRECHECK


def is_hot_patch_evaluate_scene(data_dict, patch_evalu, dev_type, product_version):
    """
    是否为补丁评估且支持HotpatchEvaluate的设备，
    @param patch_evalu: 是否为补丁评估
    @param dev_type: 设备型号
    @param product_version: 版本
    @return: True 为 HOT_PATCH_EVALUATE False为 HOT_PATCH_PRECHECK
    """
    return all([patch_evalu, is_hot_patch_eval_config_device(data_dict, dev_type, product_version)])


def is_hot_patch_eval_config_device(data_dict, dev_type, product_version):
    """
    是否为支持HotpatchEvaluate的设备。新融合，微存储支持配置。
    @param dev_type: 设备型号
    @param product_version: 版本
    @return: 结果
    """
    return any([_is_dorado_hot_patch_evaluate_scene(dev_type),
                is_ocean_protect_patch_eval(dev_type, product_version),
                baseUtil.is_new_oceanstor(dev_type),
                baseUtil.is_computing_dev(dev_type),
                _is_kunpeng_hot_patch_evaluate_scene(data_dict, product_version),
                baseUtil.is_micro_dev(dev_type)])


def _is_kunpeng_hot_patch_evaluate_scene(data_dict, product_version):
    return "Kunpeng" in product_version and VersionUpdate(data_dict).need_update_inner_check()


def is_ocean_protect_patch_eval(dev_type, product_version):
    """
    二级存储设备，版本1.1.RC1之后的支持HotpatchEvaluate配置
    @param dev_type: 设备型号
    @param product_version: 版本
    @return: 结果
    """

    return baseUtil.is_ocean_protect(dev_type) and products_adapter.compare_version(product_version, "1.1.RC1") >= 0


def _is_dorado_hot_patch_evaluate_scene(dev_type):
    """
    Dorado V6，版本6.1.3RC1之后的支持HotpatchEvaluate配置
    @param dev_type: 设备型号
    @param product_version: 版本
    @return: 结果
    """
    return baseUtil.isDoradoV6Dev(dev_type)


def check_inner_item(check_observer, patch_evalu, err_msg_list):
    """
    检查阵列内部检查项结果
    :param check_observer:
    :param patch_evalu:
    :param err_msg_list:
    :return:
    """
    if not check_observer.isAllSystemInnerItemsPassed():
        errMsg = checkUtils.getNotPassedItemsMsg(
            check_observer.getAllCheckItems())
        errMsg = "" if patch_evalu else errMsg
        result_flag = True if patch_evalu else False
        if not result_flag:
            err_msg_list.append(errMsg)


def check_item_local(dataDict, err_msg_list):
    """
    需要放在本地的检查项
    :param dataDict:
    :return:
    """
    check_item_list = [
        ad_domain_connectivity_check,
        DaemonProcessCheck,
        check_ras_cnt_before_upgrade,
        check_1822_exception_hotpatch,
        check_power_upgrade_state,
        check_admin_to_power_upgrade,
        check_systemdisk_risk
    ]
    for item in check_item_list:
        flag, msg, ret = item.execute(dataDict)
        if not flag:
            err_msg_list.append(msg)
