# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import traceback
import utils.common.log as logger
from utils.common.fic_base import TestCase
from utils.common.message import Message
from utils.common.exception import HCCIException
from utils.client.FSPAuthClient import FSPAuthClient
from utils.constant.FCDConstant import BMC_ROLE_INFO
from utils.Driver.CloudDC.OpenStack.get_host_info import GetHostInfo
from plugins.DistributedStorage.logic.deploy_operate import DeployOperate
from plugins.DistributedStorage.utils.common.deploy_constant import DeployConstant


class CreateCluster(TestCase):
    def __init__(self, project_id, pod_id, fs_args, **kwargs):
        super(CreateCluster, self).__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.opr = DeployOperate(self.fs_args)
        self.first_metadata_node = None
        self.first_metadata_type = None
        self.first_metadata_size = None
        self.all_flash = False
        self.more_args = kwargs
        self.get_host_info = None

    def procedure(self):
        logger.info("Start to create cluster.")
        try:
            self.opr.login(DeployConstant.DM_LOGIN_USER, self.fs_args['dm_update_pwd'])
        except HCCIException as e:
            logger.error(traceback.format_exc())
            return Message(500, e)
        except Exception as e:
            return Message(500, HCCIException(626002, str(e)))

        logger.info("Check fs conf paramters.")
        try:
            cluster_ip_list, zk_slot = self.get_cluster_list()
        except HCCIException as e:
            logger.error(traceback.format_exc())
            return Message(500, e)
        except Exception as e:
            return Message(500, HCCIException(626002, str(e)))

        logger.info('Creating cluster')
        try:
            self.creating_cluster(cluster_ip_list, zk_slot)
        except HCCIException as e:
            logger.error(traceback.format_exc())
            return Message(500, e)
        except Exception as e:
            return Message(500, HCCIException(626002, str(e)))

        logger.info('Create cluster successful')
        self.opr.login_out(DeployConstant.DM_LOGIN_USER, self.fs_args['dm_update_pwd'])
        return Message()

    def creating_cluster(self, cluster_ip_list, zk_slot):
        cluster_name = 'cluster01'
        server_list = list()
        res = self.opr.scan_server_media(cluster_ip_list)
        for ip in cluster_ip_list:
            media_data = res.get_media_by_node_slot(ip, zk_slot, self.all_flash)
            if not media_data:
                err_msg = "Failed to get media by slot[%s] on node[%s]. Media detail:%s" % (zk_slot, ip, media_data)
                logger.error(err_msg)
                raise HCCIException(626351, ip, "ZK", media_data)

            if not self.first_metadata_node:
                self.first_metadata_node = ip
            media_type = media_data.get('mediaType')
            self.compare_with_first_value(media_type, self.first_metadata_type, 'type', ip)
            media_size = media_data.get('mediaSize')
            self.compare_with_first_value(media_size, self.first_metadata_size, 'size', ip)
            media_status = media_data.get('mediaRole')
            if media_status != 'no_use':
                err_msg = "Failed to get media by slot[%s] on node[%s]. " \
                          "The disk of slot is not exist" % (zk_slot, ip)
                logger.error(err_msg)
                raise Exception(err_msg)

            if media_type == 'ssd_card':
                zk_disk_esn = media_data.get('phyDevEsn')
                server = {'nodeMgrIp': ip, 'zkType': media_type, 'zkDiskSlot': zk_slot, 'zkDiskEsn': zk_disk_esn}
            else:
                server = {'nodeMgrIp': ip, 'zkType': media_type, 'zkDiskSlot': zk_slot}
            server_list.append(server)
        res = self.opr.create_cluster(cluster_name, server_list)
        result, res_detail = res.get_query_detail()
        if result != 0:
            err_msg = "Failed to Create Cluster, Result:%s, Detail:%s" % (result, res_detail)
            logger.error(err_msg)
            raise Exception(err_msg)

    def get_cluster_list(self):
        nodes = self.db.get_bmc_info_by_pod_id(pod_id=self.pod_id)
        webui_client = FSPAuthClient.get_cps_web_client(
            self.db, self.project_id, self.pod_id)
        self.get_host_info = GetHostInfo(webui_client)
        # 获取元数据节点bmcip
        cluster_bmc_ip_list = [unit['bmc_ip'].split('/')[0] for unit in nodes if self.is_metadata_node_kvm(unit)]
        # 获取元数据节点主存槽位
        primary_slot_list = [unit['primary_slot'].split('/')[0] for unit in nodes if self.is_metadata_node_kvm(unit)]
        # 获取元数据槽位
        zk_slot_list = [unit['zk_slot'].split('/')[0] for unit in nodes if self.is_metadata_node_kvm(unit)]
        cache_type_list = [unit['cache_type'].split('/')[0] for unit in nodes if unit["is_metadata_node"] == '1']
        # 获取元数据节点管理ip
        cluster_id_list, cluster_ip_list = self.get_host_info.get_host_info(cluster_bmc_ip_list)
        # 元数据节点个数检查
        if len(cluster_ip_list) not in [3, 5, 7]:
            logger.error("the num of cluster:%s is wrong" % len(cluster_ip_list))
            raise Exception("the num of cluster:%s is wrong" % len(cluster_ip_list))
        # 元数据节点主存槽位检查
        if len(primary_slot_list) == 0 or not primary_slot_list[0]:
            raise Exception("The primary slot of metadata node in LLD is empty")
        # zk槽位检查
        zk_slot = zk_slot_list[0]
        # zk槽位一致性检查
        for slot in zk_slot_list:
            if zk_slot != slot:
                raise Exception("The slot of zk must be same")
        # zk槽位为空取默认值
        if not zk_slot:
            zk_slot = '2'
        logger.info("all cache type list:%s" % cache_type_list)
        if 'none' in cache_type_list:
            self.all_flash = True
        return cluster_ip_list, zk_slot

    def is_metadata_node_kvm(self, unit):
        return unit["is_metadata_node"] == "1" and (BMC_ROLE_INFO.KVM in unit["bmc_role"].split(',')
                                                    or BMC_ROLE_INFO.KVM_DPDK in unit["bmc_role"].split(','))

    def compare_with_first_value(self, src_value, cmp_value, value_type, node_ip):
        if not cmp_value:
            if value_type == 'type':
                self.first_metadata_type = src_value
            else:
                self.first_metadata_size = src_value
            return
        if src_value != cmp_value:
            err_msg = "The %s of metadata disk on the node[%s] is inconsistent with the first node[%s]." \
                      "Detail: current node:%s,first node:%s" % (value_type, node_ip, self.first_metadata_node,
                                                                 cmp_value, src_value)
            logger.error(err_msg)
            raise Exception(err_msg)
        return
