# coding=utf-8
# Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
import IPy

from utils.common.exception import HCCIException
from utils.common.message import Message
from utils.common.fic_base import StepBaseInterface
from utils.DBAdapter.DBConnector import BaseOps
from utils.business.project_condition_utils import get_project_condition_boolean
import utils.common.log as logger
from utils.business.vm_util import can_vm_pinged_to
from plugins.DistributedStorage.utils.common.general_query import GeneralQuery
from plugins.DistributedStorage.Deploy.scripts.PreCheck.sub_job_check_separate_exp_ip_conflict import ExpIpConflictCheck


class CheckIPOccupy(StepBaseInterface):
    def __init__(self, project_id, pod_id):
        super(CheckIPOccupy, self).__init__(project_id, pod_id)
        self.project_id = project_id
        self.pod_id = pod_id
        self.db = BaseOps()
        self.get_param = self.db.get_user_input_cloud_param_by_key

    def pre_check(self, project_id, pod_id):
        """
        插件内部接口：执行安装前的资源预检查，该接口由execute接口调用，工具框架不会直接调用此接口。
        :param project_id:
        :param pod_id:
        :return:Message类对象
        """
        return Message(200)

    def execute(self, project_id, pod_id):
        try:
            self.procedure(project_id)
            return Message(200)
        except HCCIException as e1:
            return Message(500, e1)
        except Exception as err:
            return Message(500, err)

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

    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:Message类对象
        """
        return Message(200)

    def procedure(self, project_id):
        params = dict()
        if get_project_condition_boolean(
                project_id, 'TenantStorFB80&(ExpansionAZ_KVM|ExpansionPOD_KVM|ExpansionAZ_BMS|ExpansionPOD_BMS)'):
            expansion_new_fsm_float_ip = self.db.get_user_input_cloud_param_by_key(
                project_id, "expansion_new_fsm_float_ip")
            params['expansion_new_fsm_float_ip'] = expansion_new_fsm_float_ip
        elif get_project_condition_boolean(project_id, 'TenantStorFB80&ExpansionServiceStorage'):
            expansion_fusionstorage_float_ip = self.db.get_user_input_cloud_param_by_key(
                project_id, "expansion_fusionstorage_float_ip")
            params['expansion_fusionstorage_float_ip'] = expansion_fusionstorage_float_ip

        for key, value in params.items():
            logger.info("Start to ping %s[%s]" % (key, value))
            if can_vm_pinged_to(value):
                raise HCCIException(626307, "{}:{}".format(key, value))
            self.check_float_ip_range(value)
            self.check_ip_conflict(value)

    def check_float_ip_range(self, float_ip):
        """
        浮动IP必须在external_om平面内，但不能在external_om_info.get("subnet")内，且不为网关、广播地址、网络号等。
        :param float_ip:
        :return:
        """
        external_om_info_list = GeneralQuery.get_external_om_info(self.db, self.pod_id, self.project_id)
        logger.info("external_om_info_list:{}".format(external_om_info_list))
        for external_om_info in external_om_info_list:
            external_om_gw = external_om_info.get("gateway")
            ipy_obj = IPy.IP(external_om_info.get("subnet"))
            pool_start, pool_end = external_om_info.get("poolstart"), external_om_info.get("poolend")

            if (float_ip not in ipy_obj) \
                    or (IPy.IP(pool_start).int() <= IPy.IP(float_ip).int() <= IPy.IP(pool_end).int()) \
                    or float_ip == external_om_gw \
                    or float_ip == str(ipy_obj.net()) \
                    or float_ip == str(ipy_obj.broadcast()):
                logger.error("The floating IP address is not in the available network segment.")
                raise HCCIException(626398,
                                    float_ip,
                                    external_om_info.get("subnet"), "{}-{}".format(pool_start, pool_end),
                                    external_om_gw,
                                    str(ipy_obj.broadcast()),
                                    str(ipy_obj.net())
                                    )

    def check_ip_conflict(self, float_ip):
        if not get_project_condition_boolean(self.project_id, "!TenantStorFB_Heterogeneous"):
            return

        def check_conflict_(ip_addr, gateway, ip_range):
            if ip_addr == gateway:
                raise HCCIException(626399, ip_addr, gateway)
            start_ip, end_ip = ip_range.split("-")
            if IPy.IP(start_ip).int() <= IPy.IP(ip_addr).int() <= IPy.IP(end_ip).int():
                raise HCCIException(626399, ip_addr, ip_range)

        logger.info('Get network plane parameters from LLD')
        fusionstorage_manage_gateway = self.get_param(self.project_id, "fusionstorage_manage_gateway")
        fusionstorage_manage_range = self.get_param(self.project_id, "fusionstorage_manage_range")
        check_conflict_(float_ip, fusionstorage_manage_gateway, fusionstorage_manage_range)

        fusionstorage_service_gateway = self.get_param(self.project_id, "fusionstorage_service_gateway")
        fusionstorage_service_range = self.get_param(self.project_id, "fusionstorage_service_range")
        check_conflict_(float_ip, fusionstorage_service_gateway, fusionstorage_service_range)
        if get_project_condition_boolean(self.project_id, "DRStorage_TFB_Sep&(CSDRStorage_TFB|CSHAStorage_TFB)"):
            fusionstorage_rep_range1 = self.get_param(self.project_id, "fusionstorage_rep_range1")
            fusionstorage_rep_gateway1 = self.get_param(self.project_id, "fusionstorage_rep_gateway1")
            check_conflict_(float_ip, fusionstorage_rep_gateway1, fusionstorage_rep_range1)

            fusionstorage_rep_range2 = self.get_param(self.project_id, "fusionstorage_rep_range2")
            fusionstorage_rep_gateway2 = self.get_param(self.project_id, "fusionstorage_rep_gateway2")
            check_conflict_(float_ip, fusionstorage_rep_gateway2, fusionstorage_rep_range2)

            if get_project_condition_boolean(self.project_id, "CSHAStorage_TFB"):
                fusionstorage_arb_range = self.get_param(self.project_id, "fusionstorage_arb_range")
                fusionstorage_arb_gateway = self.get_param(self.project_id, "fusionstorage_arb_gateway")
                check_conflict_(float_ip, fusionstorage_arb_gateway, fusionstorage_arb_range)

        if get_project_condition_boolean(self.project_id, "TenantStorBackendNetSep"):
            fusionstorage_inner_range = self.get_param(self.project_id, "fusionstorage_inner_range")
            fusionstorage_inner_gateway = self.get_param(self.project_id, "fusionstorage_inner_gateway")
            check_conflict_(float_ip, fusionstorage_inner_gateway, fusionstorage_inner_range)
