# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import re
import traceback
import json
import utils.common.log as logger
from utils.common.fic_base import StepBaseInterface
from utils.common.message import Message
from utils.DBAdapter.DBConnector import BaseOps
from utils.business.project_util import ProjectApi
from plugins.ResourceCheck.common.libs.BMCCmd import BMCCmdExc
from plugins.DistributedStorage.utils.common.deploy_constant import PangeaConstant, DeployConstant
from plugins.DistributedStorage.Deploy.scripts.PreCheck.common.device_operate import PreCheckPublicOperate, \
    PreCheckOperate


class CheckNeedInstallDriverNodeInf(StepBaseInterface):
    def __init__(self, project_id, pod_id):
        super(CheckNeedInstallDriverNodeInf, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.check_install_driver = CheckNeedInstallDriverNodeImpl(project_id, pod_id)

    def pre_check(self, project_id, pod_id):
        """
        插件内部接口：
        :param project_id:
        :param pod_id:
        :return:
        """
        return Message()

    def execute(self, project_id, pod_id):
        """
        标准调用接口：
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        try:
            self.check_install_driver.procedure()
        except Exception as err:
            logger.error('Driver check Failed: {}'.format(traceback.format_exc()))
            return Message(500, err)
        return Message(200)

    def rollback(self, project_id, pod_id):
        """
        标准调用接口：执行回滚
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message()

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

    def check(self, project_id, pod_id):
        """
        标准调用接口：重试
        :param project_id:
        :param pod_id:
        :return:
        """
        return Message()


class CheckNeedInstallDriverNodeImpl:
    def __init__(self, project_id, pod_id):
        self.project_id = project_id
        self.pod_id = pod_id
        self.date_base = BaseOps()
        self.pre_check_opr = PreCheckPublicOperate(project_id, pod_id)
        self.osd_node_list = self.pre_check_opr.get_bmc_info(need_rep=True)
        self.project_conditions = self.pre_check_opr.get_condition()
        self.bmc_list = [node_info.get("bmc_ip") for node_info in self.osd_node_list]
        self.arm_bmc_ip_list = []
        self.fs_inspect_json_path = self.pre_check_opr.get_fs_inspect_json_path()
        self.third_inspect_json_path = self.pre_check_opr.get_third_inspect_json_path()

    @classmethod
    def _package_pattern_exist(cls, json_path, comp: re.compile):
        def pkg_pattern_exist(pkgs):
            ret = False
            for pkg in pkgs:
                for key in pkg.keys():
                    if comp.match(key):
                        ret = True
                        break
            return ret

        with open(json_path, 'r', encoding='utf-8') as json_data:
            json_dict = json.load(json_data)
        pkg_define_list = json_dict.get('pkg_define', [])
        logger.info("List of packages to be verified:{}".format(pkg_define_list))
        for pkg_info in pkg_define_list:
            if pkg_pattern_exist(pkg_info.get('pkgs', [])):
                logger.info("The package has been verified. Pass")
                return True
        return False

    def procedure(self):
        logger.info('Start checking whether the driver package needs to be verified')

        if self.pg_pkg_need_to_be_verified():
            pg_json_data = {
                "project_condition": self.project_conditions,
                "pkgs": [DeployConstant.STORAGE_PACKAGES_PATTERN[6]]
            }
            self.update_fs_inspect_json(pg_json_data)

        logger.info('Update completed!!!')

    def pg_pkg_need_to_be_verified(self):
        if self.pg_pkg_pattern_exists():
            logger.info("The Pangea package already exists. Pass")
            return False

        if not self.get_arm_nodes():
            logger.info("The ARM node does not exist. Pass")
            return False

        return True

    def pg_pkg_pattern_exists(self):
        comp = re.compile(r"^OceanStor-Pacific_.*_PANGEA-SmartPkg\.zip$")
        return self._package_pattern_exist(self.third_inspect_json_path, comp) or \
            self._package_pattern_exist(self.fs_inspect_json_path, comp)

    def get_arm_nodes(self):
        ret_all = PreCheckOperate.get_system_arch(self.bmc_list)
        logger.info("Architecture result: {}".format(ret_all))
        for bmc_ip, ret in ret_all.items():
            if ret.get("stdout") == "ARM":
                self.arm_bmc_ip_list.append(bmc_ip)
        logger.info("ARM node:{}".format(self.arm_bmc_ip_list))
        return self.arm_bmc_ip_list

    def install_sas_driver_nodes(self):
        cmd_exe = BMCCmdExc()
        result_all = cmd_exe.run(self.arm_bmc_ip_list, PangeaConstant.PRODUCT_TYPE_CMD)
        logger.info("Product type:{}".format(result_all))
        install_sas_driver_nodes = []
        for bmc_ip, ret in result_all.items():
            if ret.get("stdout").strip() in PangeaConstant.SAS_DRIVER_TAI_SHAN_200_WHITELIST:
                install_sas_driver_nodes.append(bmc_ip)
        logger.info("Installing the SAS Driver Node:{}".format(install_sas_driver_nodes))
        return install_sas_driver_nodes

    def update_fs_inspect_json(self, add_json_data: dict):
        logger.info("The Added package pattern:{}".format(add_json_data))
        with open(self.fs_inspect_json_path, 'r', encoding='utf-8') as json_data:
            json_dict = json.load(json_data)
        json_dict['pkg_define'].append(add_json_data)

        logger.info('Modify the file: {}'.format(self.fs_inspect_json_path))
        PreCheckOperate.update_json_file(self.fs_inspect_json_path, json_dict)

        logger.info('Add package information to db')
        ProjectApi.update_project_pkg_verify_status(self.project_id, False)
