#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import functools
from utils.client.FSPAuthClient import FSPAuthClient, OpenstackAuthClient
from utils.Driver.CloudDC.OpenStack.compute.resource_tracker import ResourceTracker
from utils.common.PublicServiceOperate import ParameterQuery
from utils.common import log as logger
from utils.common.exception import FCDException


class GeneralQuery:
    def __init__(self):
        pass

    @staticmethod
    def get_host_resource_info_list(db, project_id, pod_id):
        webui_host_and_tool = FSPAuthClient.get_cps_web_client(db=db, project_id=project_id, pod_id=pod_id)
        method = "GET"
        rest_url = "api/v1/cloud_service/fusion_storage/info"
        send_data = {}
        cmd = {"method": method, "uri": rest_url, "body": send_data}
        resp = webui_host_and_tool.exec_cmd(cmd)
        host_rsource_info = {}
        if resp[0] == 200:
            hosts = resp[2]["avail_hosts"]
            for host in hosts:
                host_rsource_info[host["omip"]] = [host["hypervisor"]["vcpus"] - host["hypervisor"]["vcpus_used"],
                                                   host["hypervisor"]["free_disk_gb"],
                                                   host["hypervisor"]["free_ram_mb"]]
        else:
            raise Exception("Failed to get host resource info")

        return host_rsource_info

    @staticmethod
    def select_host_of_fsm(db, project_id, pod_id, availability_zone="manage-az"):
        # 获取主机资源
        host_resource_info = GeneralQuery.get_host_resource_info_list(db, project_id, pod_id)
        # 获取对应的availability_zone内的节点
        ip_list = GeneralQuery.get_available_bmcip_list(db, project_id, pod_id, availability_zone)
        # 获取资源满足的节点的管理ip
        available_ip_list = GeneralQuery.check_host_resource_and_get_ip(host_resource_info, ip_list, project_id,
                                                                        pod_id, availability_zone)
        return available_ip_list

    @staticmethod
    def get_available_bmcip_list(db, project_id, pod_id, availability_zone):
        # 获取对应的availability_zone内的节点
        webui_client = FSPAuthClient.get_cps_web_client(db, project_id, pod_id)
        nova_client = OpenstackAuthClient.get_compute_client(db, project_id, pod_id)
        resource_tracker = ResourceTracker(pod_id, webui_client, nova_client)
        host_id_list = resource_tracker.get_az_hosts_id(availability_zone)
        method = "GET"
        rest_url = "api/v1/hosts"
        send_data = {}
        cmd = {"method": method, "uri": rest_url, "body": send_data}
        resp = webui_client.exec_cmd(cmd)
        bmcip_list = []
        if resp[0] == 200:
            hosts = resp[2]["hosts"]
            for host in hosts:
                if host['id'] in host_id_list:
                    ip_list = list()
                    ip_list.append(host["metadata"]["ipmiip"])
                    ip_list.append(host["omip"])
                    bmcip_list.append(ip_list)
        return bmcip_list

    @staticmethod
    def check_host_resource_and_get_ip(host_resource_info, ip_list, project_id, pod_id, availability_zone="manage-az"):
        args_dict = {
            "project_id": project_id,
            "pod_id": pod_id,
        }
        fsm_query = ParameterQuery("DistributedStorageBusiness", args_dict)
        flavor = fsm_query.get_value_from_cloudparam("business_fsm_scale")
        if not flavor:
            flavor = "3~64"
        check_resource = dict()
        check_resource["3~64"] = [4, 100, 8192]
        check_resource["65~128"] = [8, 100, 8192]
        check_resource["129~256"] = [16, 160, 16384]
        check_resource["257~4096"] = [16, 300, 32768]
        check_value = check_resource.get(flavor)
        meet_resource_list = []
        get_check_ip = []
        for ip in ip_list:
            if host_resource_info.get(ip[1]) is None:
                continue
            host_info = host_resource_info.get(ip[1])
            if float(host_info[0]) < float(check_value[0]) or float(host_info[1]) < float(check_value[1]) \
                    or float(host_info[2]) < float(check_value[2]):
                continue
            else:
                ip_info = list()
                ip_info.append(ip[0])
                ip_info.extend(host_info)
                meet_resource_list.append(ip_info)
        # 按照vCPU、disk、memory从大到小排序
        meet_resource_list.sort(key=functools.cmp_to_key(GeneralQuery.compare_res), reverse=True)

        for info in meet_resource_list:
            get_check_ip.append(info[0])

        if len(get_check_ip) < 2:
            err_msg = "The number of nodes with a resource that meets the requirements is less than 2, " \
                      "please check the host resource"
            logger.error(err_msg)
            meet_cirteria = "vCPUs:%s, Disk Size(GB):%s, Memory Size(MB):%s"\
                            % (check_value[0], check_value[1], check_value[2])
            raise FCDException(626263, availability_zone, meet_cirteria)
        return get_check_ip

    @staticmethod
    def compare_res(res_x, res_y):
        cpu_x = res_x[1]
        mem_x = res_x[2]
        disk_x = res_x[3]
        cpu_y = res_y[1]
        mem_y = res_y[2]
        disk_y = res_y[3]
        if cpu_x > cpu_y:
            return 1
        elif cpu_x == cpu_y:
            if mem_x > mem_y:
                return 1
            elif mem_x == mem_y:
                if disk_x >= disk_y:
                    return 1
                else:
                    return -1
            else:
                return -1
        else:
            return -1
