# -*- coding: UTF-8 -*-
import re
import traceback
from cbb.frame.rest.restUtil import Tlv2Rest
from cbb.frame.rest import restData
from cbb.frame.adapter.restService import RestAdapter
from cbb.frame.cli import cliUtil
from cbb.frame.context import contextUtil
from com.huawei.ism.tool.obase.exception import ToolException
from service.func_utils import execute_tlv


class DevFreeMemory:
    """
    空闲内存检查-空闲内存必须满足热补丁安装要求才允许升级
    """

    def __init__(self, data_dict):
        """
        初始化
        :param data_dict: 上下文
        """
        self.data_dict = data_dict
        self.log = contextUtil.getLogger(data_dict)
        self.lang = data_dict.get("lang")
        self.is_support_rest = True

    def check_free_memory(self, normal_memory):
        error_msg_list = []

        cmd = "upd sysresourcecheck"
        recs = ''
        # 如果重试，先用看是否支持rest，如果不支持rest，则使用tlv
        if not self.is_support_rest:
            recs = self.free_memory_check_by_tlv(
                cmd, error_msg_list, normal_memory
            )
            cli_ret = "{}\n{}".format(cmd, str(recs))
            return len(error_msg_list) == 0, "\n".join(error_msg_list), cli_ret

        try:
            recs = self.free_memory_check(
                cmd, error_msg_list, normal_memory
            )
        except (ToolException, Exception) as e:
            self.log.error(
                "upd sys.. by rest except:{}. use tlv".format(
                    traceback.format_exc()
                )
            )
            # 命令层名兼容rest和tlv。当老版本不支持rest时，使用tlv。
            if e.args and "-1" in str(e.args[0]):
                self.is_support_rest = False
                recs = self.free_memory_check_by_tlv(
                    cmd, error_msg_list, normal_memory
                )
        cli_ret = "{}\n{}".format(cmd, str(recs))
        return len(error_msg_list) == 0, "\n".join(error_msg_list), cli_ret

    def free_memory_check(self, cmd, error_msg_list, normal_memory):
        """
        通过tlv执行命令查询。老版本不支持rest查询
        :param cmd:
        :param error_msg_list:
        :param normal_memory:
        :return:
        """
        recs = RestAdapter(self.data_dict).excuteDiagnoseCmd(cmd, 2)
        if not recs:
            self.log.error("[free_memory_check]records is none")
            msg = cliUtil.getMsg(self.lang, "free.memory.check.error")
            error_msg_list.append(msg)
            return recs
        for rec in recs:
            node_id = Tlv2Rest.getRecordValue(
                rec, restData.Upgrade.RecordParam.RECORD_NODE_ID
            )
            result = Tlv2Rest.getRecordValue(
                rec, restData.Upgrade.RecordParam.RECORD_RESULT
            )
            self.check_free_mem_one_node(
                error_msg_list, normal_memory, node_id, result
            )
        return recs

    def free_memory_check_by_tlv(self, cmd, error_msg_list, normal_memory):
        """
        通过tlv执行命令查询。老版本不支持rest查询
        :param cmd:
        :param error_msg_list:
        :param normal_memory:
        :return:
        """
        recs = execute_tlv(self.data_dict, cmd, 2)
        if not recs:
            self.log.error("[free_memory_check]records is none")
            msg = cliUtil.getMsg(self.lang, "free.memory.check.error")
            error_msg_list.append(msg)
            return recs
        for rec in recs:
            node_id = rec.getParamStrValue(0)
            result = rec.getParamStrValue(1)
            self.check_free_mem_one_node(
                error_msg_list, normal_memory, node_id, result
            )
        return recs

    def check_free_mem_one_node(
            self, error_msg_list, normal_memory, node_id, result
    ):
        """
        检查一控的空闲内存
        :param error_msg_list: 错误消息列表
        :param normal_memory: 内存阈值
        :param node_id: 节点ID
        :param result: 内存
        :return:
        """
        pattern = re.compile("^[0-9]+,([0-9]+)$")
        if result == "TimeOut":
            error_msg_list.append(
                cliUtil.getMsg(self.lang, "free.memory.check.timeout", node_id)
            )
            return False
        memory_remain = pattern.findall(result)
        if not memory_remain:
            self.log.error("record is not normal")
            error_msg_list.append(
                cliUtil.getMsg(self.lang, "free.memory.check.error", node_id)
            )
            return False
        memory_remain = int(memory_remain[0])
        self.log.info(
            "memory is:{}, memory_remain:{}".format(
                normal_memory, memory_remain
            )
        )
        if memory_remain < normal_memory:
            error_msg_list.append(
                cliUtil.getMsg(
                    self.lang,
                    "free.memory.check.notpass",
                    (node_id, memory_remain, normal_memory),
                )
            )
