# -*- coding: utf-8 -*-
import time
import utils.common.log as logger
from utils.common.exception import HCCIException
from plugins.DistributedStorage.common.UpgradeOperate import UpgradeOperate
import plugins.DistributedStorage.common.constants as PostCheckConstant
from plugins.DistributedStorage.common.base import TestCase
import traceback


class PostUpgradeCheck(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None,
                 metadata=None, **kwargs):
        super(PostUpgradeCheck, self).__init__(project_id, pod_id)
        self.condition = condition
        self.metadata = metadata
        self.more_args = kwargs
        self.opr = UpgradeOperate(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.post_check_success_status = "postcheck_success"
            self.post_check_status = "postcheck"
        elif self.upgrade_type == "rollback":
            self.post_check_success_status = "rollback_postcheck_success"
            self.post_check_status = "rollback_postcheck"
        else:
            err_msg = "upgrade type is wrong, type: %s" % self.upgrade_type
            logger.error(err_msg)
            raise Exception(err_msg)
        self.confirming_status = "confirming"

    def procedure(self):
        logger.info('post upgrade check.')
        try:
            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)

            if 0 == self._check_upgrade_task():
                return
            if 0 == self._check_upgrade_status():
                return

            logger.info('get post upgrade check result.')
            ret_result = None
            ret_data = None
            check_timeout = 300
            while check_timeout > 0:
                ret_result, ret_data = self.opr.get_post_check_result()
                if ret_result["code"] != '0':
                    err_msg = "get rollback upgrade task failed, " \
                              "Detail:[result:%s, data:%s]" \
                              % (ret_result, ret_data)
                    logger.error(err_msg)
                    raise Exception(err_msg)
                if 0 == self._check_post_check_result(ret_result, ret_data):
                    break
                time.sleep(10)
                check_timeout -= 10
            if check_timeout <= 0:
                err_msg = "get post check timeout, status:{status}. " \
                          "result:{ret_result}, data: {ret_data}" \
                    .format(status=ret_data["status"], ret_result=ret_result,
                            ret_data=ret_data)
                logger.error(err_msg)
                raise HCCIException(621000, err_msg)
        except HCCIException as e:
            logger.error('Post upgrade check failed, details: {}'.format(e))
            logger.error(traceback.format_exc())
            raise e
        except Exception as e:
            logger.error('Post upgrade check failed, details: {}'.format(e))
            logger.error(traceback.format_exc())
            raise HCCIException(621002, str(e))

    def _check_upgrade_task(self):
        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"] == "" and ret_data["percent"] == 100:
            logger.warn("upgrade task finished.")
            return 0
        elif ret_data["status"] != "success":
            err_msg = "current upgrade task status is failed, " \
                      "Detail:[result:%s, data:%s]" \
                      % (ret_result, ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        return 1

    def _check_upgrade_status(self):
        logger.info("get 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"] == self.post_check_success_status:
            logger.warn("post check has successful")
            return 0
        elif ret_data["currentPhase"] == self.confirming_status:
            logger.warn("currentPhase is %s has successful."
                        % ret_data["currentPhase"])
            return 0
        elif ret_data["currentPhase"] != self.post_check_status:
            logger.info('post upgrade check.')
            ret_result, ret_data = self.opr.post_check()
            if ret_result["code"] != '0':
                err_msg = "post upgrade check failed, " \
                          "Detail:[result:%s, data:%s]" \
                          % (ret_result, ret_data)
                logger.error(err_msg)
                raise Exception(err_msg)
        return 1

    def _check_post_check_result(self, ret_result, ret_data):
        if ret_data["status"] == \
                PostCheckConstant.PostCheckStatus.FAILERED:
            failed_list, success_list, running_list = \
                self.get_failed_component(ret_data["result"])
            err_msg = "component {failed} failed, component " \
                      "{running} is not check, component {success} " \
                      "check ok!" \
                .format(failed=failed_list, running=running_list,
                        success=success_list)
            logger.error(err_msg)
            raise Exception(err_msg)
        elif ret_data["status"] == \
                PostCheckConstant.PostCheckStatus.SUCCESSED:
            logger.info("post check success!")
            return 0
        elif ret_data["status"] == \
                PostCheckConstant.PostCheckStatus.CHECKING:
            logger.info("post checking is running. Progress is {}%"
                        .format(ret_data["progress"]))
        else:
            logger.error("get post check result {status}. "
                         "result: {ret_result}, data: {ret_data}"
                         .format(status=ret_data["status"],
                                 ret_result=ret_result,
                                 ret_data=ret_data))
        return 1

    @staticmethod
    def get_failed_component(data_result):
        failed_list = []
        success_list = []
        running_list = []
        for micro_service in data_result:
            component_list = micro_service["upgradeList"]
            for component in component_list:
                if component["status"] == 0:
                    running_list.append(component["name"])
                elif component["status"] == 1:
                    success_list.append(component["name"])
                elif component["status"] == 2:
                    failed_list.append(component["name"])
                else:
                    logger.error("post check status {status} wrong!"
                                 .format(status=component["status"]))
        return failed_list, success_list, running_list
