# -*- 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 UpgradePkg(TestCase):
    def __init__(self, project_id, pod_id, fs_args, **kwargs):
        super(UpgradePkg, self).__init__(project_id, pod_id)
        self.more_args = kwargs
        self.opr = UpgradeOperate(fs_args)
        self.rest_opr = RestPublicMethod(project_id, pod_id, fs_args)
        self.user_name = fs_args["user_name"]
        self.password = fs_args["password"]
        self.upgrade_type = fs_args["upgrade_type"]
        if self.upgrade_type == "upgrade":
            self.postcheck_success_status = "postcheck_success"
        elif self.upgrade_type == "rollback":
            self.postcheck_success_status = "rollback_postcheck_success"
        else:
            err_msg = "upgrade type is wrong, type: %s" % self.upgrade_type
            logger.error(err_msg)
            raise Exception(err_msg)

    def procedure(self):
        logger.info('Start upgrade task.')
        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, Detail:[status:%s,code:%s]%s" % (status_code, error_code, error_des)
            logger.error(err_msg)
            raise Exception(err_msg)

        self._check_upgrade_status()
        osd_nodes_list, vbs_nodes_list = self.rest_opr.get_server_list()

        self._do_upgrade_task()

        logger.info('get upgrade task info.')
        check_timeout = 90*60 + 300*len(osd_nodes_list) + 300*(len(
            vbs_nodes_list)/20 + 1)
        self._wait_upgrade_result(check_timeout)

    def retry(self):
        logger.info('Start retry upgrade task.')
        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, Detail:[status:{},code:{}]{}".format(status_code, error_code, error_des)
            logger.error(err_msg)
            raise Exception(err_msg)

        self._check_upgrade_status()
        osd_nodes_list, vbs_nodes_list = self.rest_opr.get_server_list()

        logger.info("get upgrade task result")
        ret_result, ret_data = self.opr.get_upgrade_task()
        if ret_result["code"] != '0':
            err_msg = "get upgrade task failed, " \
                      "Detail:[result:%s, data:%s]" \
                      % (ret_result, ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        elif ret_data["status"] == "failed" \
                and ret_data["taskType"] == "upgrade":
            logger.info('retry upgrade task.')
            ret_result, ret_data = self.opr.retry_upgrade_task()
            if ret_result["code"] != '0':
                err_msg = "retry upgrade task failed, " \
                          "Detail:[result:%s, data:%s]" \
                          % (ret_result, ret_data)
                logger.error(err_msg)
                raise Exception(err_msg)

        logger.info('get retry upgrade task info')
        check_timeout = 90*60 + 300*len(osd_nodes_list) + 300 * (len(vbs_nodes_list)/20 + 1)
        self._wait_upgrade_result(check_timeout)

    def _wait_upgrade_result(self, check_timeout):
        max_retry_times = 30
        failed_nums = 0
        ret_result = None
        ret_data = None
        while check_timeout > 0:
            try:
                ret_result, ret_data = self.opr.get_upgrade_task()
            except Exception as ex:
                err_msg = "get upgrade task failed, " \
                          "Exception: %s" % (str(ex))
                logger.error(err_msg)
                failed_nums += 1
                if failed_nums > max_retry_times:
                    raise
            else:
                failed_nums = 0
                if 0 == self._check_upgrade_result(ret_result, ret_data):
                    break
            time.sleep(10)
            check_timeout -= 10
        if check_timeout <= 0:
            err_msg = "upgrade timeout, progress:{progress}. " \
                      "result:{ret_result}, data: {ret_data}" \
                .format(progress=ret_data["percent"],
                        ret_result=ret_result, ret_data=ret_data)
            logger.error(err_msg)
            raise HCCIException(621000, err_msg)

    def _check_upgrade_status(self):
        logger.info("check upgrade status.")
        ret_result, ret_data = self.opr.get_upgrade_status()
        if ret_result["code"] != '0':
            err_msg = "get upgrade status failed, " \
                      "Detail:[result:%s, data:%s]" \
                      % (ret_result, ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        elif ret_data["currentPhase"] == "upgrading":
            logger.info("current is upgrading")

    def _check_upgrade_result(self, ret_result, ret_data):
        if ret_result["code"] != '0':
            err_msg = "get upgrade task failed, " \
                      "Detail:[result:%s, data:%s]" \
                      % (ret_result, ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        if ret_data["status"] == "failed":
            failed_map = RestPublicMethod.get_failed_component(ret_data["result"])
            err_msg = "upgrade {} failed".format(failed_map)
            logger.error(err_msg)
            raise Exception(err_msg)
        elif ret_data["status"] == "success":
            logger.info("upgrade success!")
            return 0
        elif ret_data["status"] == "running":
            logger.info("upgrade is running. Progress is {}%"
                        .format(ret_data["percent"]))
        else:
            logger.error("get upgrade task status wrong. "
                         "result: {ret_result}, data: {ret_data}"
                         .format(ret_result=ret_result,
                                 ret_data=ret_data))
        return 1

    def _do_upgrade_task(self):
        logger.info('start upgrade task.')
        ret_result, ret_data = self.opr.upgrade_task()
        if ret_result["code"] == '1073884696':
            err_msg = "node is upgrade status, " \
                      "Detail:[result:%s, data:%s]" \
                      % (ret_result, ret_data)
            logger.error(err_msg)
        elif ret_result["code"] != '0':
            err_msg = "upgrade task failed, " \
                      "Detail:[result:%s, data:%s]" \
                      % (ret_result, ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
