# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import collections

import utils.common.log as logger
from utils.common.fic_base import TestCase
from utils.Driver.CloudDC.OpenStack.config_cascading_kvm import ConfinCascadingKvm
from utils.client.FSPAuthClient import FSPAuthClient
from utils.Driver.CloudDC.OpenStack.get_host_info import GetHostInfo
from utils.business.project_util import ProjectApi
from utils.constant.constant import BMCROLE
from utils.common.exception import FCDException
from platforms.project.ProjectUtils import get_project_condition_boolean
from plugins.DistributedStorage.scripts.utils.common.DeployConstant import DeployConstant
from plugins.DistributedStorage.scripts.logic.DeployOperate import DeployOperate
from plugins.DistributedStorage.scripts.logic.InstallOperate import InstallOperate


class ConfigKVMResourcePool(TestCase):
    def __init__(self, project_id, pod_id, fs_args, **kwargs):
        super(ConfigKVMResourcePool, self).__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.float_ip = self.fs_args.get('float_ip')
        self.vbs_list = self.fs_args.get('vbs_list')
        self.backend_name = self.fs_args.get('backend_name')
        self.az_id = DeployConstant.AVAILABILITY_ZONE
        self.ha_az_id = DeployConstant.HA_AVAILABILITY_ZONE
        self.ha_backend_name = self.fs_args.get('ha_backend_name')
        self.more_args = kwargs
        self.update_pwd = self.fs_args.get('dm_update_pwd')
        self.install_opr = InstallOperate(self.project_id, self.pod_id, fs_args)
        self.exp_pool = get_project_condition_boolean(self.project_id, 'ManageStorNewPool')

    @staticmethod
    def get_pool_id_list(fs_args):
        operate = DeployOperate(fs_args)
        operate.login(DeployConstant.DM_LOGIN_USER, fs_args.get('dm_update_pwd'))
        logger.info("Query storage pool data.")
        res_pool = operate.query_storage_pool()
        pool_info = res_pool.get_query_data()
        if len(pool_info.get('storagePools')) == 0:
            err_msg = "Failed to query storage pool information"
            logger.error(err_msg)
            operate.login_out(DeployConstant.DM_LOGIN_USER, fs_args.get('dm_update_pwd'))
            raise FCDException(626078, err_msg)
        pool_id_list = [str(pool.get('poolId')) for pool in pool_info.get('storagePools')]
        return pool_id_list

    @staticmethod
    def _get_cinder_kvm(availability_zone, cluster_list, enabled_backend):
        cinder_kvm = None
        for cluster in cluster_list:
            cinder_drivers = cluster["params"]["cinder_drivers"]
            if not cinder_drivers:
                continue
            backend_store, cur_az = cinder_drivers[0]["backend_store"], cinder_drivers[0]["cfg"]["availability_zone"]
            if backend_store != 'fusionstorage' or cur_az != availability_zone:
                continue
            section_list = cinder_drivers[0]["cfg"]['section_list']
            for section in section_list:
                if section['volume_backend_name'] == enabled_backend:
                    cinder_kvm = cluster["params"]["host"]
                    logger.info('availability zone:{}, exist cinder-kvm:{}'.format(availability_zone, cinder_kvm))
        return cinder_kvm

    def procedure(self):
        webui_client = FSPAuthClient.get_cps_web_client(self.db, self.project_id, self.pod_id)
        project_ha_dr_status_dict = ProjectApi().get_project_ha_dr_status(self.project_id)
        ha_status = project_ha_dr_status_dict['RegionConHA'] == 1 or project_ha_dr_status_dict['CSHA'] == 1
        obj = ConfinCascadingKvm(webui_client)
        resource_pool_data = obj.get_kvm_resource_pool()
        logger.info('Query pool id')
        pool_id_list = self.get_pool_id_list(self.fs_args)
        logger.info('Get control node ip and id')
        control_id_list, control_ip_list = self.get_control_node_info(obj, ha_status, webui_client)
        fs_agent = ",".join(control_ip_list)
        logger.info('Get the over_ratio')
        over_ratio = self.get_over_ratio(obj, self.az_id, self.backend_name)
        logger.info("Upload cert and get private key")
        private_key_psw = self.install_opr.upload_cert_and_get_private_key(webui_client)
        logger.info("Config cinder connect with DistributedStorage")
        cluster_name = self.query_cinder_kvm_name_by_az_id_and_backend_name(
            resource_pool_data, self.az_id, self.backend_name)
        if self.exp_pool:
            logger.info('Update multiple backend')
            section_list = [{"volume_backend_name": self.backend_name,
                             "pool_id_list": ','.join(pool_id_list),
                             "over_ratio": over_ratio}]
            obj.update_resource_kvm_multiple_backend(
                self.backend_name, self.float_ip, fs_agent, section_list, control_id_list, self.az_id,
                private_key_psw, cluster_name)
        else:
            if cluster_name:
                logger.info("The resource %s is exist, delete it first" % cluster_name)
                obj.delete_resource(cluster_name)
            obj.config_cascading_kvm(self.backend_name, self.float_ip, fs_agent, pool_id_list, over_ratio,
                                     control_id_list, private_key_psw)
        if not ha_status:
            logger.info("The connection is configured successfully")
            return
        args = collections.namedtuple("args",
                                      ["ha_status", "obj", "private_key_psw", "resource_pool_data", "webui_client"])

        self.ha_config_kvm_pool_procedure(args(ha_status, obj, private_key_psw, resource_pool_data, webui_client))

        logger.info("The connection is configured successfully")

    def ha_config_kvm_pool_procedure(self, args: collections.namedtuple):
        logger.info('[HA] Query pool id')
        ha_float_ip = self.get_ha_float_ip()
        ha_pool_id_list = self.get_pool_id_list({'float_ip': ha_float_ip, 'dm_update_pwd': self.update_pwd})
        logger.info('[HA] Get control node ip and id')
        ha_control_id_list, ha_control_ip_list = self.get_control_node_info(
            args.obj, args.ha_status, args.webui_client, 'dc002')
        ha_fs_agent = ",".join(ha_control_ip_list)
        logger.info('[HA] Get the over_ratio')
        ha_over_ratio = self.get_over_ratio(args.obj, self.ha_az_id, self.ha_backend_name, "manage_ha_thin_alloc_rate")
        logger.info("[HA] Config cinder connect with DistributedStorage")
        ha_cluster_name = self.query_cinder_kvm_name_by_az_id_and_backend_name(
            args.resource_pool_data, self.ha_az_id, self.ha_backend_name)
        if self.exp_pool:
            logger.info('[HA] Update multiple backend')
            ha_section_list = [{"volume_backend_name": self.ha_backend_name,
                                "pool_id_list": ','.join(ha_pool_id_list),
                                "over_ratio": ha_over_ratio}]
            args.obj.update_resource_kvm_multiple_backend(
                self.ha_backend_name, ha_float_ip, ha_fs_agent, ha_section_list, ha_control_id_list, self.ha_az_id,
                args.private_key_psw, ha_cluster_name)
        else:
            if ha_cluster_name:
                logger.info("[HA] The resource %s is exist, delete it first" % ha_cluster_name)
                args.obj.delete_resource(ha_cluster_name)
            args.obj.config_cascaded_kvm(self.ha_backend_name, ha_float_ip, ha_fs_agent, ha_pool_id_list, ha_over_ratio,
                                         ha_control_id_list, self.ha_az_id, args.private_key_psw)

    def query_cinder_kvm_name_by_az_id_and_backend_name(self, cluster_data, availability_zone, enabled_backend):
        no_value = None
        cluster_list = cluster_data.get('cluster_list')
        if not cluster_list:
            logger.info('The cinder kvm service does not exist')
            return no_value
        cinder_kvm = self._get_cinder_kvm(availability_zone, cluster_list, enabled_backend)
        if not cinder_kvm:
            logger.info('The cinder kvm service does not exist, az id:{}'.format(availability_zone))
            return no_value
        else:
            return cinder_kvm

    def get_ha_float_ip(self):
        ha_fs_float_ip = self.db.get_value_from_cloudparam(self.pod_id, "DistributedStorageManage", "HAFSMOMFloatingIP")
        if not ha_fs_float_ip:
            ha_fs_float_ip = self.db.get_user_input_cloud_param_by_key(self.project_id, "dc002_expansion_fsm_float_ip")
        return ha_fs_float_ip

    def get_over_ratio(self, obj, az_id, backend_name, key="manage_thin_alloc_rate"):
        if self.exp_pool:
            old_backend = obj.get_kvm_backend_data(az_id, backend_name)
            if not old_backend:
                err_msg = 'Error: Failed to query the existing cinder-kvm00X info from th cps-web'
                logger.error(err_msg)
                raise FCDException(626006, err_msg)
            old_section_list = old_backend.get('section_list')
            over_ratio = old_section_list[0].get('over_ratio')
        else:
            over_ratio = self.db.get_value_from_cloudparam(self.pod_id, "DistributedStorageManage", key)
        logger.info('The over_ratio is : %s' % over_ratio)
        return over_ratio

    def get_control_node_info(self, obj, ha_status, webui_client, site="dc001"):
        control_ip_list, control_id_list, _, _ = obj.get_hosts_info_u()
        if ha_status:
            ret_params_list = self.db.get_bmc_info_by_site_and_bmc_role(site, pod_id=self.pod_id)
            bmc_ip_list = []
            for ret_param in ret_params_list:
                if ret_param["bmc_role"] == BMCROLE.CONTROLLER_NODE or ret_param["bmc_role"] == \
                        BMCROLE.CLOUD_SERVICE_NODE or ret_param["bmc_role"] == BMCROLE.FIRST_NODE:
                    bmc_ip_list.append(ret_param['bmc_ip'])
            if len(bmc_ip_list) > 3:
                bmc_ip_list = bmc_ip_list[:3]
            get_host_info = GetHostInfo(webui_client)
            control_id_list, control_ip_list = get_host_info.get_host_info(bmc_ip_list)
        return control_id_list, control_ip_list
