# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import time
import utils.common.log as logger
from utils.common.exception import HCCIException
from plugins.DistributedStorage.common.upgrade_operate import UpgradeOperate
from plugins.DistributedStorage.common.base import TestCase
from plugins.DistributedStorage.common.public_handle_new import RestPublicMethod


class PrepareUpgrade(TestCase):
    def __init__(self, project_id, pod_id, fs_args):
        super(PrepareUpgrade, self).__init__(project_id, pod_id)
        self.fs_args = fs_args
        self.opr = UpgradeOperate(fs_args)
        self.rest_opr = RestPublicMethod(project_id, pod_id, fs_args)
        self.float_ip = fs_args.get("float_ip")
        self.user_name = fs_args.get("user_name")
        self.password = fs_args.get("password")

    def procedure(self):
        logger.info('Start prepare for upgrade task.')
        self.login_deploy_manager()
        # 根据当前存储版本判断是否执行本工步, 813之后版本自升级流程在本工步通过REST接口实现
        if self.rest_opr.storage_version_after_813():
            # 判断deploymanager是否需要自升级
            logger.info("Check whether to upgrade the upgrade service")
            if not self.need_self_upgrade():
                logger.info("the upgrade service not need to upgrade")
                return
            # 下发自升级任务
            self.deliver_self_upgrade_task()
            # 查询自升级任务状态
            self._wait_self_upgrade_result()
        else:
            # 813之前版本升级前准备已在“自升级”工步完成,跳过本工步
            logger.info("For current version, prepare for upgrade already finished in self upgrade step")
            return
        logger.info('procedure end!')

    def login_deploy_manager(self):
        status_code, error_code, error_des = self.opr.try_login(self.user_name, self.password)
        if status_code != 200 or error_code != 0:
            err_msg = "Failed to login deploy manager, Detail:[status:{},code:{}]{}".format(
                status_code, error_code, error_des)
            logger.error(err_msg)
            raise HCCIException(621001, err_msg)

    def need_self_upgrade(self):
        ret_result, ret_data = self.opr.get_upgrade_packages()
        if ret_result.get('code') != '0':
            err_msg = 'Failed to query information about the existing upgrade package,' \
                      ' Detail:[result:%s, data:%s]' % (ret_result, ret_data)
            logger.error(err_msg)
            raise HCCIException(621018, err_msg)
        need_self_upgrade = ret_data.get("needSelfUpgrade")
        return need_self_upgrade

    def deliver_self_upgrade_task(self):
        logger.info("Deliver upgrade service task")
        ret_result, ret_data = self.opr.do_self_upgrade()
        if ret_result.get('code') != 0:
            err_msg = 'Failed to deliver upgrade service task, Detail:[result:%s, data:%s]' % (ret_result, ret_data)
            logger.error(err_msg)
            raise HCCIException(621018, err_msg)
        failed_node_list = []
        for node in ret_data:
            if node.get('code') != '0':
                failed_node_list.append(node)
        if failed_node_list:
            err_msg = 'Failed to upgrade service node:%s' % failed_node_list
            logger.error(err_msg)
            raise HCCIException(621018, err_msg)

    def _wait_self_upgrade_result(self):
        check_timeout = 3600
        ret_result = None
        ret_data = None
        while check_timeout > 0:
            ret_result, ret_data = self.opr.query_task_progress('self_upgrade')
            if ret_result.get('code') != 0:
                err_msg = 'Failed to get upgrade service task, Detail:[result:%s, data:%s]' % (ret_result, ret_data)
                logger.error(err_msg)
                raise HCCIException(621018, err_msg)
            if 0 == self._check_self_upgrade_task_result(ret_data, ret_result):
                logger.info("upgrade service task success")
                break
            time.sleep(30)
            check_timeout -= 30
        if check_timeout <= 0:
            err_msg = "upgrade service timeout, Detail:[result:%s, data:%s]" % (ret_result, ret_data)
            logger.error(err_msg)
            raise HCCIException(621018, err_msg)

    def _check_self_upgrade_task_result(self, ret_data, ret_result):
        success_node_list = []
        failed_node_list = []
        for node in ret_data:
            ip = node.get('management_ip')
            status = node.get('status')
            if status == 'success':
                success_node_list.append(ip)
                logger.info('Node [%s] upgrade service success' % ip)
            elif status == 'running':
                progress = node.get('progress')
                logger.info('Node [%s] running upgrade service task, progress:%s' % (ip, progress))
            elif status == 'failed':
                failed_node_list.append(node)
                err_msg = 'Node [%s] upgrade service failed. Detail:[code:%s, description:%s, suggestion:%s]' \
                          % (ip, node.get('code'), node.get('description'), node.get('suggestion'))
                logger.error(err_msg)
            else:
                logger.info('get upgrade service task status wrong. '
                            'result:{ret_result}, data:{ret_data}'.format(ret_result=ret_result, ret_data=ret_data))
        if len(success_node_list) == len(ret_data):
            logger.info('All nodes [%s] upgrade service success' % success_node_list)
            return 0
        if len(failed_node_list) == len(ret_data):
            err_msg = "All nodes execute upgrade service failed, Detail:%s" % failed_node_list
            logger.error(err_msg)
            raise HCCIException(621018, err_msg)
        return 1
