# -*- coding: utf-8 -*-
import time
import utils.common.log as logger
from utils.common.exception import FCDException as FCUException
from plugins.DistributedStorage.scripts.logic.UpgradeOperate import UpgradeOperate
from utils.common.fic_base import TestCase
import traceback


class UpgradeConfirm(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None,
                 metadata=None, **kwargs):
        super(UpgradeConfirm, 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.get("user_name", "admin")
        self.password = fs_args["dm_update_pwd"]
        self.upgrade_type = fs_args["upgrade_type"]
        if self.upgrade_type == "upgrade":
            self.post_check_success_status = "postcheck_success"
        elif self.upgrade_type == "rollback":
            self.post_check_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 %s commit.' % self.upgrade_type)
        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)
            rsp_result, rsp_data = self.opr.get_product()
            if rsp_result.get("code") != 0:
                err_msg = "Failed to get product, Detail:[result:%s]%s" % (rsp_result, rsp_data)
                logger.error(err_msg)
                raise FCUException(626313, err_msg)
            version = rsp_data.get("version")
            if version != "8.0.1.SPC600":
                logger.error("version is %s, skip!" % rsp_data)
                return

            if 0 == self._check_upgrade_task():
                logger.info("upgrade task finished.")
                return
            self._do_upgrade_confirm()

            logger.info('get upgrade status.')
            ret_result = None
            ret_data = None
            check_timeout = 300
            while check_timeout > 0:
                ret_result, ret_data = self.opr.get_upgrade_status()
                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 0 == self._check_confirm_result(ret_result, ret_data):
                    break
                time.sleep(5)
                check_timeout -= 5
            if check_timeout <= 0:
                err_msg = "get upgrade status timeout, status:{status}. result:{ret_result}, data: {ret_data}".format(
                    status=ret_data["currentPhase"], ret_result=ret_result, ret_data=ret_data)
                logger.error(err_msg)
                raise FCUException(626300, err_msg)
        except FCUException as e:
            logger.error(traceback.format_exc())
            raise e
        except Exception as e:
            logger.error(traceback.format_exc())
            raise FCUException(626317, str(e))
        finally:
            logger.info('procedure end.')

    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.info("upgrade task finished.")
            return 0
        elif ret_data["taskType"] != self.upgrade_type \
                or ret_data["status"] != "success":
            err_msg = "current upgrade status is not success, Detail:[" \
                      "result:%s, data:%s]" % (ret_result, ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        return 1

    @staticmethod
    def _check_confirm_result(ret_result, ret_data):
        if ret_data["currentPhase"] == "confirm_failure":
            err_msg = "upgrade confirm failed!"
            logger.error(err_msg)
            raise Exception(err_msg)
        elif ret_data["currentPhase"] == "":
            logger.info("confirm success!")
            return 0
        elif ret_data["currentPhase"] == "confirming":
            logger.info("is confirming.")
        else:
            logger.error(
                "upgrade status {status}. result: {ret_result}, "
                "data: {ret_data}".format(
                    status=ret_data["currentPhase"], ret_result=ret_result,
                    ret_data=ret_data))
        return 1

    def _do_upgrade_confirm(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)
        if ret_data["currentPhase"] == "confirming":
            err_msg = "current phase is confirming"
            logger.info(err_msg)
        elif ret_data["currentPhase"] != self.post_check_success_status:
            err_msg = "Perform the post-upgrade check first, current " \
                      "Detail:[result:%s, data:%s]" % (ret_result,
                                                       ret_data)
            logger.error(err_msg)
            raise Exception(err_msg)
        else:
            logger.info('confirm upgrade.')
            ret_result, ret_data = self.opr.upgrade_confirm()
            if ret_result["code"] != '0':
                err_msg = "pre upgrade check failed, Detail:[result:%s, " \
                          "data:%s]" % (ret_result, ret_data)
                logger.error(err_msg)
                raise Exception(err_msg)
