# -*-coding:utf-8-*-
import utils.common.log as logger
from utils.common.exception import HCCIException
from utils.business.project_condition_utils import get_project_condition_boolean
from utils.common.OpenStackNodeManager import OpenStackNodeManager
from utils.DBAdapter.DBConnector import BaseOps
from plugins.DistributedStorage.utils.config.DeviceCheck import DeviceResource
from plugins.DistributedStorage.Deploy.scripts.BusinessConverge.implement.TC_Install_Role \
    import InstallRole as businessConvergeRole
from plugins.DistributedStorage.Deploy.scripts.PreCheck.common.dataUnits import HostData
import utils.constant.constant as constant


def resource_calc(project_id, pod_id):
    """扩容资源预检接口函数
    type:取值为vm或host。vm代表需要占用资源的为vm；host代表直接在主机上占用资源，比如对主机进行资源隔离。必选参数。
    host_id：主机id。可选参数，默认值为None。如需指定主机，请传该值。
    cpu：本次需新增的vcpu数量。整数类型。必选参数。
    Mem：本次需新增的内存数量，单位为GB，可以为小数。必选参数。
    Sys_disk：本次需新增的系统盘数量，单位为GB，整数类型。必选参数。
    sys_disk_type：取值为local或remote。Local代表本地盘，remote代表远端卷。可选参数。默认值为remote。
    Data_disk_total：本次需新增的数据盘总量（需要多个数据盘时，取总和），单位为GB。可选参数。整数类型。默认值为0.
    data_disk_type：取值为local或remote。Local代表本地盘，remote代表远端卷。可选参数。默认值为remote。
    [{type:vm, host_id:None, cpu:1, mem:2, sys_disk:20,sys_disk_type:local, data_disk_total:40,data_disk_type:remote},
    {type:host, host_id:192.168.0.1, cpu:1, mem:2, sys_disk:0, sys_disk_type:local, data_disk_total: 0,
    data_disk_type:remote }]
    """
    resource_list = list()
    try:
        if get_project_condition_boolean(project_id, "ManageStorFB80&ExpansionMgmtRes_ServiceNode"):
            get_vm_resource_when_exp_cloud_node(pod_id, project_id, resource_list)

        if get_project_condition_boolean(project_id, "TenantStorFB80&(ExpansionAZ_KVM|ExpansionServiceStorage|"
                                                     "ExpansionComputeRes_KVMNode|ExpansionNetworkRes_NetworkNode)"):
            get_vm_resource_when_exp_sep_business(pod_id, project_id, resource_list)

        if get_project_condition_boolean(project_id, "TenantStorFBHCI80&!businessARM&(ExpansionComputeRes_KVMNode|"
                                                     "ExpansionNetworkRes_NetworkNode)"):
            get_vm_resource_when_business_converge(pod_id, project_id, resource_list)

    except HCCIException as e:
        logger.error("calc DMK resource error")
        raise e
    except Exception as e:
        logger.error(str(e))
        raise HCCIException('256203', str(e))
    return resource_list


def get_vm_resource_when_business_converge(pod_id, project_id, resource_list):
    business_converge_fb = ResourceExpNodes(project_id, pod_id)
    osd_bmc_list = business_converge_fb.get_business_converge_osd_bmc_list()
    vbs_bmc_list = business_converge_fb.get_business_converge_vbs_bmc_list()
    logger.info("business converge storage osd bmc list:%s" % osd_bmc_list)
    logger.info("business converge storage vbs bmc list:%s" % vbs_bmc_list)
    osd_num = len(osd_bmc_list)
    vbs_num = len(vbs_bmc_list)
    nodes = business_converge_fb.db.get_bmc_info_by_pod_id(business_converge_fb.pod_id)
    osd_memory = businessConvergeRole.get_memory_value(project_id, nodes)
    logger.info("node memory:%s" % osd_memory)
    # 混合场景
    osd_cpu = 6
    # 全闪场景取cpu12
    if businessConvergeRole.get_cache_type(nodes) == 'none':
        osd_cpu = 12
    if osd_num > 0:
        res_request = {'type': 'host', 'cpu': osd_cpu * osd_num, 'mem': osd_memory * osd_num}
        resource_list.append(res_request)
    if vbs_num > 0:
        res_request = {'type': 'host', 'cpu': 4 * vbs_num, 'mem': 7 * vbs_num}
        resource_list.append(res_request)


def get_vm_resource_when_exp_sep_business(pod_id, project_id, resource_list):
    compute_node = HostData(project_id, pod_id)
    vbs_list = compute_node.get_separate_compute_node_list()
    logger.info("business separate storage osd bmc list:%s" % vbs_list)
    vbs_num = len(vbs_list)
    if vbs_num > 0:
        res_request = {'type': 'host', 'cpu': 4 * vbs_num, 'mem': 7 * vbs_num}
        resource_list.append(res_request)


def get_vm_resource_when_exp_cloud_node(pod_id, project_id, resource_list):
    cloud_service = ResourceExpNodes(project_id, pod_id)
    osd_bmc_list, osd_memory = cloud_service.get_cloudservice_osd_memory()
    logger.info("osd bmc list:%s" % osd_bmc_list)
    logger.info("osd memory:%s" % osd_memory)
    osd_num = len(osd_bmc_list)
    if get_project_condition_boolean(pod_id, 'manageARM'):
        osd_cpu = 8
    else:
        osd_cpu = 6
    if osd_num > 0:
        res_request = {'type': 'host', 'cpu': osd_cpu * osd_num, 'mem': osd_memory * osd_num}
        resource_list.append(res_request)
    vbs_list = cloud_service.get_cloudservice_vbs_nodes()
    vbs_num = len(vbs_list)
    if vbs_num > 0:
        res_request = {'type': 'host', 'cpu': 4 * vbs_num, 'mem': 5 * osd_num}
        resource_list.append(res_request)


class ResourceExpNodes(object):
    def __init__(self, project_id, pod_id):
        self.project_id = project_id
        self.pod_id = pod_id
        self.db = BaseOps()

    def get_cloudservice_osd_memory(self):
        all_nodes = self.db.get_bmc_info_by_pod_id(pod_id=self.pod_id)
        osd_bmcip_list, not_osd_bmcip_list, memory = self.get_memory_value(all_nodes)
        return osd_bmcip_list, memory

    def get_cloudservice_vbs_nodes(self):
        nodes_list = list()
        all_nodes = self.db.get_bmc_info_by_pod_id(pod_id=self.pod_id)
        for unit in all_nodes:
            if unit["bmc_role"] == constant.BMCROLE.CLOUD_SERVICE_NODE and 'vbs' in unit["ref_component"]:
                nodes_list.append(unit)
        return nodes_list

    def get_business_converge_osd_bmc_list(self):
        return OpenStackNodeManager.get_osd_ip_list(self.db, self.pod_id, is_typeii=False, is_business=True)

    def get_business_converge_vbs_bmc_list(self):
        vbs_bmc_list = OpenStackNodeManager.get_vbs_ip_list(self.db, self.pod_id, is_typeii=False, is_business=True)
        osd_bmc_list = OpenStackNodeManager.get_osd_ip_list(self.db, self.pod_id, is_typeii=False, is_business=True)
        vbs_bmc_list = list(set(vbs_bmc_list).difference(set(osd_bmc_list)))
        return vbs_bmc_list

    def get_memory_value(self, all_nodes, scene=None, mode=None):
        osd_role = 'osd'
        osd_bmcip_list = []
        not_osd_bmcip_list = []
        cache_capacity = 0
        primary_capacity = 0
        storage_slot_list = []
        for unit in all_nodes:
            if unit["bmc_role"] == constant.BMCROLE.CLOUD_SERVICE_NODE and osd_role in unit["ref_component"]:
                # 获取部署了osd组件的云服务节点
                osd_bmcip_list.append(unit["bmc_ip"])
                # 获取主存槽位
                storage_slot_list.append(unit["primary_slot"])

                # 获取缓存容量以及缓存容量一致性检查
                cache_capacity = self.get_cache_capacity(cache_capacity, unit)

                # 获取主存容量以及主存容量一致性检查
                primary_capacity = self.get_primary_capacity(primary_capacity, unit)
            elif unit["bmc_role"] == constant.BMCROLE.CLOUD_SERVICE_NODE and osd_role not in unit["ref_component"]:
                # 获取没有部署了osd组件的云服务节点
                not_osd_bmcip_list.append(unit["bmc_ip"])
        memory = 0
        if len(osd_bmcip_list) > 0:
            check = DeviceResource()
            storage_slot = check.get_storage_pool_slot(storage_slot_list)
            memory = check.get_fsa_memory_800(storage_slot, cache_capacity, primary_capacity, condition='manageFB')
        return osd_bmcip_list, not_osd_bmcip_list, memory

    @staticmethod
    def get_primary_capacity(primary_capacity, unit):
        if primary_capacity == 0:
            if not unit["primary_capacity"] or unit["primary_capacity"] == 0:
                # 缓存容量为空时抛异常
                err_msg = "The primary capacity of cloud service node with OSD component cannot be empty"
                logger.error(err_msg)
                raise Exception(err_msg)
            primary_capacity = unit["primary_capacity"]
        else:
            if primary_capacity != unit["primary_capacity"]:
                # 控制节点的缓存容量不一致时抛异常
                err_msg = "The primary capacity of cloud service node with OSD component must be same"
                logger.error(err_msg)
                raise Exception(err_msg)
        return primary_capacity

    @staticmethod
    def get_cache_capacity(cache_capacity, unit):
        if cache_capacity == 0:
            if not unit["cache_capacity"] or unit["cache_capacity"] == 0:
                # 缓存容量为空时抛异常
                err_msg = "The cache capacity of cloud service node with OSD component cannot be empty"
                logger.error(err_msg)
                raise Exception(err_msg)
            cache_capacity = unit["cache_capacity"]
        else:
            if cache_capacity != unit["cache_capacity"]:
                # 控制节点的缓存容量不一致时抛异常
                err_msg = "The cache capacity of cloud service node with OSD component must be same"
                logger.error(err_msg)
                raise Exception(err_msg)
        return cache_capacity
