# -*-coding:utf-8-*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import utils.common.log as logger
from utils.common.exception import HCCIException
from utils.DBAdapter.DBConnector import BaseOps
from utils.business.project_util import ProjectApi
from utils.common.OpenStackNodeManager import OpenStackNodeManager
from utils.constant.FCDConstant import REGION_CONTROL_HA_SITE as region_site
from utils.business.project_condition_utils import get_project_condition_boolean
from plugins.DistributedStorage.Deploy.scripts.PreCheck.common.data_units import HostData
from plugins.DistributedStorage.Deploy.scripts.ManageConverge.implement.tc_install_role import InstallRole as manageRole
from plugins.DistributedStorage.Deploy.scripts.BusinessConverge.implement.tc_install_role import \
    InstallRole as businessConvergeRole


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:
        get_resource_list(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)) from e
    return resource_list


def get_resource_list(pod_id, project_id, resource_list):
    resource_list.extend(get_manage_storage_resource_calc(project_id, pod_id))
    resource_list.extend(get_converge_storage_resource_calc(project_id, pod_id))
    resource_list.extend(get_seperate_storage_resource_calc(project_id, pod_id))


def get_manage_storage_resource_calc(project_id, pod_id):
    resource_list = list()
    if get_project_condition_boolean(project_id, "ProjectDeploy&ManageStorFB80"):
        manage_fb = ResourceStorFB(project_id, pod_id)
        osd_bmc_list = manage_fb.get_manage_storage_osd_bmc_list()
        vbs_bmc_list = manage_fb.get_manage_storage_vbs_bmc_list()
        logger.info("manage storage osd bmc list:%s" % osd_bmc_list)
        logger.info("manage storage vbs bmc list:%s" % vbs_bmc_list)
        curr_condition = ProjectApi().get_project_ha_dr_status(manage_fb.project_id)
        if curr_condition['RegionConHA']:
            # 高可用场景未单独计算vbs的内存，按站点内所有节点作为osd节点内存计算
            dc001_nodes = manage_fb.db.get_bmc_info_by_site_and_bmc_role(region_site.DC001, pod_id=manage_fb.pod_id)
            dc001_nodes_bmc_list = [node['bmc_ip'] for node in dc001_nodes]
            dc001_osd_bmc_list = list(set(osd_bmc_list).intersection(set(dc001_nodes_bmc_list)))
            dc001_vbs_bmc_list = list(set(vbs_bmc_list).intersection(set(dc001_nodes_bmc_list)))
            dc002_nodes = manage_fb.db.get_bmc_info_by_site_and_bmc_role(region_site.DC002, pod_id=manage_fb.pod_id)
            dc002_nodes_bmc_list = [node['bmc_ip'] for node in dc002_nodes]
            dc002_osd_bmc_list = list(set(osd_bmc_list).intersection(set(dc002_nodes_bmc_list)))
            dc002_vbs_bmc_list = list(set(vbs_bmc_list).intersection(set(dc002_nodes_bmc_list)))
            dc001_memory = manageRole.get_memory_value(dc001_nodes)
            logger.info("dc001 memory:%s" % dc001_memory)
            dc002_memory = manageRole.get_memory_value(dc002_nodes)
            logger.info("dc002:%s" % dc002_memory)
            dc001_memory_sum = dc001_memory * len(dc001_osd_bmc_list + dc001_vbs_bmc_list)
            dc002_memory_sum = dc002_memory * len(dc002_osd_bmc_list + dc002_vbs_bmc_list)
            memory_sum = dc001_memory_sum + dc002_memory_sum
        else:
            all_nodes = manage_fb.db.get_bmc_info_by_pod_id(manage_fb.pod_id)
            node_memory = manageRole.get_memory_value(all_nodes)
            logger.info("node memory:%s" % node_memory)
            memory_sum = node_memory * len(osd_bmc_list + vbs_bmc_list)
        if get_project_condition_boolean(project_id, 'manageARM'):
            osd_cpu = 8
        else:
            osd_cpu = 6
        node_sum = len(osd_bmc_list + vbs_bmc_list)
        if node_sum > 0:
            res_request = {'type': 'host', 'cpu': osd_cpu * len(osd_bmc_list + vbs_bmc_list), 'mem': memory_sum}
            resource_list.append(res_request)
    return resource_list


def get_converge_storage_resource_calc(project_id, pod_id):
    resource_list = list()
    if get_project_condition_boolean(project_id, "ProjectDeploy&TenantStorFBHCI80&!businessARM"):
        business_converge_fb = ResourceStorFB(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
        # 超融合容灾场景，预留复制所需cpu
        if get_project_condition_boolean(
                project_id, "TenantStorFBHCI80&(CSHAStorage_TFB|CSDRStorage_TFB)&!DRStorage_TFB_Sep"):
            osd_cpu += 4
        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)
    return resource_list


def get_seperate_storage_resource_calc(project_id, pod_id):
    resource_list = list()
    if get_project_condition_boolean(project_id, "ProjectDeploy&TenantStorFB80"):
        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)
    return resource_list


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

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

    def get_manage_storage_vbs_bmc_list(self):
        vbs_bmc_list = OpenStackNodeManager.get_vbs_ip_list(self.db, self.pod_id, is_typeii=True, is_business=False)
        osd_bmc_list = OpenStackNodeManager.get_osd_ip_list(self.db, self.pod_id, is_typeii=True, is_business=False)
        vbs_bmc_list = list(set(vbs_bmc_list).difference(set(osd_bmc_list)))
        return vbs_bmc_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
