# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import traceback
import pathlib

import utils.common.log as logger
from utils.common.ssh_util import Ssh
from utils.common.message import Message
from utils.common.exception import HCCIException
from utils.common.fic_base import StepBaseInterface
from utils.common.software_package_util import find_software_package
from plugins.DistributedStorage.common.base import TestCase
from plugins.DistributedStorage.common.parameter_gain import ParamsGain
from plugins.DistributedStorage.logic.install_operate import InstallOperate
from plugins.DistributedStorage.utils.common.deploy_constant import DeployConstant


class UploadDistributePkgInf(StepBaseInterface):
    def __init__(self, project_id, pod_id, regionid_list=None, suit_id=None):
        super(UploadDistributePkgInf, self).__init__(project_id, pod_id, regionid_list)
        self.project_id = project_id
        self.pod_id = pod_id
        self.regionid_list = regionid_list
        self.suit_id = suit_id
        self.fs_args = ParamsGain(project_id, pod_id, regionid_list).get_args(suit_id)
        self.upload_pkg = UploadDistributePkgImp(self.project_id, self.pod_id, self.fs_args)
        self.error_code = 620006

    def execute(self, project_id, pod_id, regionid_list=None, suit_id=None):
        logger.info('Start upload distribute package')
        try:
            self.upload_pkg.procedure()
        except HCCIException as err:
            logger.error("upload distribute package error:{}".format(traceback.format_exc()))
            return Message(500, str(err))
        except Exception as err:
            logger.error("upload distribute package error:{}".format(traceback.format_exc()))
            return Message(500, HCCIException(self.error_code, str(err)))
        return Message()

    def rollback(self, project_id, pod_id, regionid_list=None, suit_id=None):
        """
        标准调用接口：执行回滚
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        logger.info('Start rollback distribute package')
        try:
            self.upload_pkg.rollback_procedure()
        except HCCIException as err:
            logger.error("Rollback distribute package error:{}".format(traceback.format_exc()))
            return Message(500, str(err))
        except Exception as err:
            logger.error("Rollback distribute package error:{}".format(traceback.format_exc()))
            return Message(500, HCCIException(self.error_code, str(err)))
        return Message()

    def retry(self, project_id, pod_id, regionid_list=None, suit_id=None):
        """
        标准调用接口：重试
        :return: Message类对象
        """
        return self.execute(self.project_id, self.pod_id, self.regionid_list, self.suit_id)


class UploadDistributePkgImp(TestCase):
    def __init__(self, project_id, pod_id, fs_args, condition=None, metadata=None, **kwargs):
        super(UploadDistributePkgImp, self).__init__(project_id, pod_id)
        self.condition = condition
        self.metadata = metadata
        self.fs_args = fs_args
        self.more_args = kwargs
        self.admin_pwd = fs_args.get("password")
        self.master_ip = self.fs_args.get("master_ip")
        self.master_username = self.fs_args.get("master_username")
        self.master_password = self.fs_args.get("master_password")
        self.master_root_pwd = self.fs_args.get("master_root_pwd")
        self.slaver_ip = self.fs_args.get("slaver_ip")
        self.slaver_username = self.fs_args.get("slaver_username")
        self.slaver_password = self.fs_args.get("slaver_password")
        self.slaver_root_pwd = self.fs_args.get("slaver_root_pwd")
        self.master_client, self.slaver_client = None, None
        self.standby_node, self.standby_client = None, None
        self.error_code = 621024
        self.all_upload_pkg_list = []
        self.client_list = []

    @classmethod
    def _clear_old_pkg(cls, client, pkg_name):
        if not pkg_name:
            logger.warn("The package name is empty:{}".format(pkg_name))
            return
        cmd = "rm -rf /root/{}".format(pkg_name)
        Ssh.ssh_send_command(client, cmd, "#", 20, 3)

    def procedure(self):
        self.get_all_pkg_name_and_path()
        try:
            logger.info("step1. Log in to the management nodes")
            self.ssh_mgmt_nodes()
            logger.info("step2. Checking the HA Status")
            self.check_ha_status()
            logger.info("step3. Delete the old package")
            self.clear_old_package()
            logger.info("step4. Querying the Standby Node")
            self.get_ha_standby_node()
            logger.info("step5. Uploading the Storage Software Packages:{}".format(self.all_upload_pkg_list))
            self.upload_package()
            logger.info("Succeeded in uploading the packages")
        finally:
            for client in self.client_list:
                Ssh.ssh_close(client)

    def rollback_procedure(self):
        self.get_all_pkg_name_and_path()
        try:
            logger.info("Start clearing the software package")
            self.ssh_mgmt_nodes()
            self.clear_old_package()
            logger.info("The software package is cleared successfully")
        finally:
            for client in self.client_list:
                Ssh.ssh_close(client)

    def ssh_mgmt_nodes(self):
        logger.info("Log in to node {}".format(self.master_ip))
        self.master_client = InstallOperate.create_ssh_root_client(
            self.master_ip, self.master_username, self.master_password, self.master_root_pwd)
        self.client_list.append(self.master_client)
        logger.info("Log in to node {}".format(self.slaver_client))
        self.slaver_client = InstallOperate.create_ssh_root_client(
            self.slaver_ip, self.slaver_username, self.slaver_password, self.slaver_root_pwd)
        self.client_list.append(self.slaver_client)

    def check_ha_status(self):
        ha_status_cmd = "/opt/dfv/oam/oam-u/ha/ha/module/hacom/tools/ha_client_tool --gethastatus " \
                        "| grep '^ha' | awk '{print $4}'"
        ret = Ssh.ssh_exec_command_return(self.slaver_client, ha_status_cmd)
        logger.info("cmd result:{}".format(ret))
        if str(ret).__contains__("Abnormal"):
            err_msg = "HA status abnormal, {}".format(ret)
            logger.error(err_msg)
            raise HCCIException(self.error_code, err_msg)

    def clear_old_package(self):
        for pkg_name, _ in self.all_upload_pkg_list:
            logger.info("Delete the {} package on node {}".format(pkg_name, self.master_ip))
            self._clear_old_pkg(self.master_client, pkg_name)
            logger.info("Delete the {} package on node {}".format(pkg_name, self.slaver_ip))
            self._clear_old_pkg(self.slaver_client, pkg_name)

    def get_ha_standby_node(self):
        ha_info_cmd = "/opt/dfv/oam/oam-u/ha/tools/getHAStatus.sh | grep LOCAL_ROLE | " \
                      "awk -F : '{print $2}'|awk '$1=$1'"
        ret = Ssh.ssh_exec_command_return(self.slaver_client, ha_info_cmd)
        logger.info("ha_info_cmd result:{}".format(ret))
        if str(ret).__contains__("standby"):
            logger.info("Current node [{}] is standby".format(self.slaver_ip))
            self.standby_node = [self.slaver_ip, self.slaver_username, self.slaver_password, self.slaver_root_pwd]
            self.standby_client = self.slaver_client
        else:
            logger.info("The node [{}] is standby".format(self.master_ip))
            self.standby_node = [self.master_ip, self.master_username, self.master_password, self.master_root_pwd]
            self.standby_client = self.master_client

    def upload_package(self):
        dst = "/home/{}".format(self.standby_node[1])
        for pkg_name, pkg_dir in self.all_upload_pkg_list:
            pkg_path = pathlib.Path(pkg_dir) / pkg_name
            logger.info("Upload the {} package to node {}".format(pkg_path, self.standby_node[0]))
            Ssh.put_file(*self.standby_node[:3], str(pkg_path), dst)
            logger.info("Move the {}/{} package to the /root directory".format(dst, pkg_name))
            standby_client = InstallOperate.create_ssh_root_client(*self.standby_node)
            self.client_list.append(standby_client)
            mv_cmd = "mv {}/{} /root".format(dst, pkg_name)
            Ssh.ssh_send_command(standby_client, mv_cmd, "#", 30, 3)

    def get_all_pkg_name_and_path(self):
        for _, cur_pattern in DeployConstant.ONE_STEP_UPGRADE.items():
            pkg_dict, num = find_software_package(cur_pattern, self.project_id)
            if not pkg_dict:
                err_msg = "The {} does not exist in the /home/pkg directory,result:{}".format(cur_pattern, pkg_dict)
                logger.error(err_msg)
                raise HCCIException(self.error_code, err_msg)
            self.all_upload_pkg_list.append(list(pkg_dict.items())[0])
        logger.info("All pkg:{}".format(self.all_upload_pkg_list))
