# -*-coding:utf-8-*-
from utils.common.error.fcd_error_code import get_code_msg
from platforms.project.ProjectUtils import get_project_condition_boolean
from plugins.DistributedStorage.params.install_params_checkutils import PoolCheck
from plugins.DistributedStorage.params.install_params_checkutils import ManageStorageParamsCheckUtils


class ManageStorFBParamCheckHook(object):
    def __init__(self):
        self.manage_cache_type = ['ssd_card', 'ssd_disk', 'none']

    def check(self, project_id, input_params):
        if not input_params:
            return True, ''
        error_msg_dict = {}
        err_msg_dict = self.check_manage_storage_param(project_id, input_params)
        error_msg_dict.update(err_msg_dict)
        if error_msg_dict:
            return False, error_msg_dict
        return True, ''

    def check_manage_storage_param(self, project_id, input_params):
        # 管理融合部署场景设备信息sheet页相关参数校验
        err_msg_dict = {}
        if get_project_condition_boolean(project_id, 'ManageStorFB80&!RegionConHA'):
            # 管理融合部署且不启用管理面跨AZ高可用场景相关参数校验
            err_msg_dict = self.check_manage_and_not_ha_param(input_params)
        elif get_project_condition_boolean(project_id, 'ManageStorFB80&RegionConHA'):
            err_msg_dict = self.check_manage_and_ha_param(project_id, input_params)
        return err_msg_dict

    def check_manage_and_not_ha_param(self, input_params):
        err_msg_dict = {}
        zk_slot = ""
        primary_capacity = 0
        cache_type = None
        cache_capacity = None
        for param_item in input_params:
            # 管理融合，检查首节点、控制节点和提供存储能力的云服务节点
            if not ("first_node" in param_item["bmc_role"] or "controller" in param_item["bmc_role"] or
                    ("cloud_service" in param_item["bmc_role"] and "osd" in param_item["ref_component"])):
                continue

            if "first_node" in param_item["bmc_role"] or "controller" in param_item["bmc_role"]:
                # 控制节点的指定部署组件必须包含osd组件
                if "osd" not in param_item["ref_component"]:
                    err_msg_dict["managestorfb_ref_component"] = get_code_msg('626241')
                # 非CSHA场景，控制节点必须为元数据节点
                if param_item.get("is_metadata_node") != "1":
                    err_msg_dict["managestorfb_is_metadata_node"] = get_code_msg('626226')

                # zk槽位值检测
                zk_slot, msg_dict = ManageStorageParamsCheckUtils.zk_slot_check(param_item, zk_slot, err_msg_dict)
                err_msg_dict.update(msg_dict)

            # 主存盘容量的检测
            primary_capacity, msg_dict = ManageStorageParamsCheckUtils.not_ha_primary_capacity_check(
                param_item, primary_capacity, err_msg_dict)
            err_msg_dict.update(msg_dict)

            # 主存槽位的检测
            msg_dict = ManageStorageParamsCheckUtils.not_ha_primary_slot_check(param_item, err_msg_dict)
            err_msg_dict.update(msg_dict)

            # 元数据槽位与主存槽位冲突检查
            msg_dict = ManageStorageParamsCheckUtils.zk_slot_and_primary_slot_conflict_check(param_item, err_msg_dict)
            err_msg_dict.update(msg_dict)

            # 缓存类型和容量检查
            cache_type, cache_capacity, msg_dict = ManageStorageParamsCheckUtils.not_ha_cache_check(
                param_item, self.manage_cache_type, cache_type, cache_capacity, err_msg_dict)
            err_msg_dict.update(msg_dict)
        # 如果存在格式错误先返回，避免检测磁盘个数时脚本异常
        if err_msg_dict:
            return err_msg_dict

        # 检查存储池中服务器上盘的数量是否满足要求
        check_result = self.check_converge_pool_disk_num('ManageStorage', input_params)
        err_msg_dict.update(check_result)

        return err_msg_dict

    @staticmethod
    def check_converge_pool_disk_num(pool, server_list):
        pool_check = PoolCheck()
        for server in server_list:
            if not ("first_node" in server["bmc_role"] or "controller" in server["bmc_role"] or
                    ("cloud_service" in server["bmc_role"] and "osd" in server["ref_component"])):
                continue
            disk_slot = server["primary_slot"]
            if disk_slot:
                disk_num = int(disk_slot.split('-')[1]) - int(disk_slot.split('-')[0]) + 1
                pool_check.record_disk_num(disk_num)
        return pool_check.check_disk_num(pool)

    def check_manage_and_ha_param(self, project_id, input_params):
        extra_params_dict = {
            "dc001": {"zk_node_num": 0,
                      "zk_slot": "",
                      "primary_capacity": 0,
                      "cache_capacity": 0,
                      "cache_type": None},
            "dc002": {"zk_node_num": 0,
                      "zk_slot": "",
                      "primary_capacity": 0,
                      "cache_capacity": 0,
                      "cache_type": None}
        }
        err_msg_dict = {}
        dc_site_list = ["dc001", "dc002"]
        not_expansion_cloud_flag = True
        if get_project_condition_boolean(
                project_id, r'((ExpansionPOD_KVM|ExpansionPOD_BMS)&ExpansionPOD_CloudService)|'
                            r'ExpansionScale_CloudServiceNode|ExpansionMgmtRes_ServiceNode'):
            not_expansion_cloud_flag = False
        for param_item in input_params:
            if not ("first_node" in param_item["bmc_role"] or "controller" in param_item["bmc_role"] or
                    ("cloud_service" in param_item["bmc_role"] and "osd" in param_item["ref_component"])):
                continue
            site_id = param_item.get("site")
            if site_id in dc_site_list:
                extra_params = extra_params_dict.get(site_id)
                extra_params["not_expansion_cloud_flag"] = not_expansion_cloud_flag
                msg_dict = self.check_manage_and_ha_param_for_storage(site_id, param_item, extra_params)
                err_msg_dict.update(msg_dict)
            if not ("first_node" in param_item["bmc_role"] or "controller" in param_item["bmc_role"]):
                continue
            # 控制节点的指定部署组件必须包含osd组件
            if "osd" not in param_item["ref_component"]:
                err_msg_dict["managestorfb_ref_component"] = get_code_msg('626242')

            if site_id in dc_site_list and param_item.get("is_metadata_node") != "1":
                # 控制节点必须作为元数据节点
                err_msg_dict[f"managestorfb_{site_id}_is_metadata_node"] = get_code_msg('626237') % site_id

        self.check_zk_num_compliant(not_expansion_cloud_flag, extra_params_dict, err_msg_dict)
        self.check_disk_num_compliant(dc_site_list, input_params, err_msg_dict)

        return err_msg_dict

    @staticmethod
    def check_zk_num_compliant(not_expansion_cloud_flag, extra_params_dict, err_msg_dict):
        """
        元数据节点个数做检测
        :param not_expansion_cloud_flag: 非扩容云服务标记
        :param extra_params_dict: 需要校验的参数字典
        :param err_msg_dict: 错误信息字典
        :return:
        """
        if not_expansion_cloud_flag:
            for site_id, extra_params in extra_params_dict.items():
                zk_node_num = extra_params.get("zk_node_num")
                if zk_node_num not in [3, 5, 7] and f"managestorfb_{site_id}_is_metadata_node" not in err_msg_dict:
                    err_msg_dict[f"managestorfb_{site_id}_is_metadata_node"] = \
                        get_code_msg('626250') % (site_id, zk_node_num)

    @staticmethod
    def check_disk_num_compliant(dc_site_list, input_params, err_msg_dict):
        """
        检查site1、site2存储池中服务器上盘的数量是否满足要求
        :param dc_site_list: ["dc001", "dc002"]
        :param input_params:
        :param err_msg_dict:
        :return:
        """
        for site in dc_site_list:
            check_result = ManageStorageParamsCheckUtils.\
                check_region_ha_pool_disk_num(site, site, input_params)
            err_msg_dict.update(check_result)

    def check_manage_and_ha_param_for_storage(self, dc_site, param_item, extra_params):
        err_msg_dict = {}
        not_expansion_cloud_flag = extra_params.get("not_expansion_cloud_flag")
        zk_slot = extra_params.get("zk_slot")
        primary_capacity = extra_params.get("primary_capacity")
        cache_type = extra_params.get("cache_type")
        cache_capacity = extra_params.get("cache_capacity")
        if not_expansion_cloud_flag and param_item.get("is_metadata_node") == "1":
            extra_params["zk_node_num"] += 1
            # zk槽位检测
            extra_params["zk_slot"], msg_dict = self.check_zk_slot(
                param_item, err_msg_dict, dc_site, f"managestorfb_{dc_site}_zk_slot", zk_slot)
            err_msg_dict.update(msg_dict)
        # 主存槽位的检测
        msg_dict = ManageStorageParamsCheckUtils.dc_check_primary_slot(
            param_item, err_msg_dict, dc_site, f"managestorfb_{dc_site}_primary_slot")
        err_msg_dict.update(msg_dict)
        # 主存盘容量的检测
        extra_params["primary_capacity"], msg_dict = ManageStorageParamsCheckUtils.dc_check_primary_capacity(
            param_item, err_msg_dict, dc_site, f"managestorfb_{dc_site}_primary_capacity", primary_capacity)
        err_msg_dict.update(msg_dict)
        # 缓存类型检查
        extra_params["cache_type"], msg_dict = ManageStorageParamsCheckUtils.dc_check_cache_type(
            param_item, self.manage_cache_type, cache_type, dc_site, err_msg_dict,
            f"managestorfb_{dc_site}_cache_type")
        err_msg_dict.update(msg_dict)
        # 缓存容量检查
        extra_params["cache_capacity"], msg_dict = ManageStorageParamsCheckUtils.dc_check_cache_capacity(
            param_item, err_msg_dict, dc_site, cache_capacity,
            f"managestorfb_{dc_site}_cache_capacity", f"managestorfb_{dc_site}_cache_type")
        err_msg_dict.update(msg_dict)

        # 元数据槽位与主存槽位冲突检查
        msg_dict = self.zk_slot_and_primary_slot_conflict_check(
            param_item, dc_site, f"managestorfb_{dc_site}_primary_slot",
            f"managestorfb_{dc_site}_zk_slot", err_msg_dict)
        err_msg_dict.update(msg_dict)
        return err_msg_dict

    @staticmethod
    def check_zk_slot(param_item, err_msg_dict, site_name, key_name, zk_slot):
        msg_dict = {}
        # zk槽位空值检测
        if param_item["zk_slot"]:
            if not str(param_item["zk_slot"]).isdigit() and key_name not in err_msg_dict:
                # zk节点zk槽位格式检测
                msg_dict[key_name] = get_code_msg('626239') % site_name
            elif not zk_slot:
                zk_slot = param_item["zk_slot"]
            elif zk_slot != param_item["zk_slot"] and key_name not in err_msg_dict:
                # zk节点zk槽位一致性检测
                msg_dict[key_name] = get_code_msg('626240') % site_name
        return zk_slot, msg_dict

    @staticmethod
    def zk_slot_and_primary_slot_conflict_check(param_item, site, primary_key, zk_key, error_dict):
        msg_dict = {}
        if primary_key in error_dict or zk_key in error_dict:
            return error_dict
        zk_slot = param_item.get("zk_slot")
        if not zk_slot:
            return msg_dict
        primary_slot = param_item.get("primary_slot")
        primary_slot_start, primary_slot_end = primary_slot.split('-')
        if int(primary_slot_start) <= int(zk_slot) <= int(primary_slot_end):
            msg_dict["managestorfb_conflict_slot"] = get_code_msg("626239") % site
        return msg_dict
