# coding:utf-8
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import time
from tenacity import retry, stop_after_attempt, wait_fixed
import utils.common.log as logger
from utils.client.FSPAuthClient import FSPAuthClient
from plugins.DistributedStorage.scripts.utils.common.fsp_constant import FspConstant


class CPSWebRest(object):
    def __init__(self, project_id, pod_id, db):
        self.project_id = project_id
        self.pod_id = pod_id
        # 获取数据库客户端
        self.db = db
        self.cps_rest_client = FSPAuthClient.get_cps_rest_client(self.db, self.project_id, self.pod_id)
        self.cps_web = FSPAuthClient.get_cps_web_client(self.db, self.project_id, self.pod_id)

    def fusionstorage_block_clone(self):
        """
        :return:role_name
        """
        method = 'POST'
        url = FspConstant.ROLE_CLONE
        data = {"original_role": "fusionstorage-block"}
        resp = self._cps_web_request(method, url, data)
        return resp

    def fusionstorage_block_resource(self, resource_data):
        """
        :param resource: 该角色组的资源隔离定义，cpu、mem和disk可选，至少有一个，
                          mem单位为M， 格式如下：
                          {“cpu”:{“core”:5},
                           “mem”:{“size”:3072},
                            “disk”:{“readbps”:60,”writebps”:30}
                           }

        :param wildcard:是否支持该角色组模糊匹配，1支持模糊匹配，0精确匹配，默认值0
        :return:
        """
        method = 'PUT'
        url = FspConstant.ROLE_RESOURCE
        resp = self._cps_web_request(method, url, resource_data)
        return resp

    def deploy_hosts_roles(self, host_id_list, role):
        """往host_id节点部署role_list

        :param host_id_list:
        :param role:
        :return:
        """
        method = "PATCH"
        rest_url = "api/v1/roles/hosts"
        data = {"original": [],
                "current": []}

        for host_id in host_id_list:
            host_roles_old = self.get_host_roles(host_id)
            host_roles_new = list(set(host_roles_old + [role]))
            logger.info("deploy roles:%s to hostid:%s,host old roles :%s host new role:%s "
                        % (role, host_id, host_roles_old, host_roles_new))
            if set(host_roles_new) == set(host_roles_old):
                continue
            org_host_data = {"host_name": host_id,
                             "roles": host_roles_old}
            curr_host_data = {"host_name": host_id,
                              "roles": host_roles_new}
            data.get('original').append(org_host_data)
            data.get('current').append(curr_host_data)

        resp = self._cps_web_request(method, rest_url, data)
        logger.info("Finish to deploy roles[%s] to hosts[%s], Detail:%s" % (role, host_id_list, resp))
        return resp

    def check_hosts_role_deploy(self, host_id_list, role, timeout=300):
        hosts_list = host_id_list
        wait_time = 0
        sleep_time = 30
        while wait_time <= timeout:
            deployed_host_list = list()
            for host_id in hosts_list:
                role_list = self.get_host_roles(host_id)
                if role in role_list:
                    logger.info('The role[%s] is deployed on host[%s]' % (role, host_id))
                    deployed_host_list.append(host_id)
            hosts_list = list(set(hosts_list).difference(set(deployed_host_list)))
            if len(hosts_list) == 0:
                break
            try:
                check_times = wait_time/sleep_time
            except ZeroDivisionError as e:
                err_msg = 'ZeroDivisionError, Detail:%s' % str(e)
                logger.error(err_msg)
                raise e
            logger.info('The role[%s] is not deployed on hosts[%s], '
                        'check %sth times after %ss' % (role, hosts_list, check_times, sleep_time))
            time.sleep(sleep_time)
            wait_time += sleep_time

        if len(hosts_list) == 0:
            logger.info('The role[%s] is deployed on all hosts[%s]' % (role, host_id_list))
            return True
        if len(hosts_list) == len(host_id_list):
            logger.error("Role is not installed on all hosts:[%s]. Delete the role:[%s]" % (host_id_list, role))
            self.cps_rest_client.do_role_delete(role)
            self.cps_rest_client.do_commit()
        err_msg = 'The role[%s] is not deployed on hosts[%s]' % (role, hosts_list)
        logger.error(err_msg)
        raise Exception(err_msg)

    @retry(stop=stop_after_attempt(2), wait=wait_fixed(2), reraise=True)
    def get_host_roles(self, host_id):
        method = "GET"
        rest_url = "api/v1/roles/hosts/%s" % host_id
        resp = self._cps_web_request(method, rest_url)
        role_list = list()
        role_list.extend(list(resp.keys()))
        return role_list

    @retry(stop=stop_after_attempt(2), wait=wait_fixed(2), reraise=True)
    def _cps_web_request(self, method, url, data=None):
        cmd = {"method": method, "uri": url, "body": data}
        resp = self.cps_web.exec_cmd(cmd)
        if not resp or resp[0] != 200:
            raise Exception('Send cps web request failed: url=%s, body=%s, detail:%s' % (url, data, resp))
        return resp[2]
