import logging
from abc import ABC, abstractmethod
from typing import Optional


from olc.alg.admission.admission_alg import AdmissionAbstractAlgorithm
from olc.alg.alg_context import AlgContextBuilder
from olc.alg.alg_manager import OlcAlgManager
from olc.bean.match_wrapper import MatchWrapper
from olc.bean.olc_config_rule import AdmissionPolicy, AlgInstance
from olc.collector.collector_manager import OlcCollectorManager
from olc.exception.olc_dynamic_exception import OLCDynamicException

log = logging.getLogger(__name__)


class AbsAdmissionController(ABC):
    def __init__(self):
        super().__init__()

    @abstractmethod
    def refresh_status(self):
        pass

    """
    判断是否可以通过
    return 返回是否可以通过  true 拒绝 false 通过
    """
    @abstractmethod
    def get_result(self) -> bool:
        pass


class AllowController(AbsAdmissionController):
    def refresh_status(self):
        pass

    def get_result(self) -> bool:
        return False


class DenyController(AbsAdmissionController):
    def refresh_status(self):
        pass

    def get_result(self) -> bool:
        return True


class DynamicController(AbsAdmissionController):

    def __init__(self, matchWrapper: MatchWrapper[AdmissionPolicy]):
        super().__init__()
        self._tag_group = matchWrapper.tag_group
        self._policy = matchWrapper.policy
        alg = matchWrapper.policy.calculate_alg
        self._cal_ins: AlgInstance = alg
        self._cal_alg: Optional[AdmissionAbstractAlgorithm] = (
            OlcAlgManager.get_instance().get_admission_alg(alg.alg_name)
        )
        self._pre_status: bool = False
        self._status: bool = False

    def run_alg(self):
        try:
            if self._cal_alg is None:
                log.warning(f"not found admission alg {self._cal_ins.alg_name}")
                return False
            instance_paras = self._cal_ins.alg_param.copy()
            for key, value in instance_paras.items():
                alg_param = self._cal_alg.para_names.get(key)
                if alg_param is not None:
                    if alg_param.dynamic:
                        true_value = OlcCollectorManager.get_instance().get_dyn_key_true_value(value)
                        if true_value is None:
                            log.warning(f"get dynamic value err, dynamic key {alg_param} value is null")
                            raise OLCDynamicException(f"Dynamic parameter conversion error")
                        instance_paras[key] = true_value
            builder = AlgContextBuilder[bool]().new_builder()
            builder.set_group(self._tag_group)
            builder.set_policy(self._policy)
            builder.set_parameter(instance_paras)
            builder.set_previous(self._pre_status)
            builder.set_init_result(self._status)
            return self._cal_alg.make_decision(builder.build())
        except Exception as e:
            log.warning(f"admission dynamic algorithm executed error. err :{repr(e)}")
            return False

    def refresh_status(self):
        if self._cal_alg is None:
            return
        if not self._cal_alg.every_request:
            alg = self.run_alg()
            self.update_controller(alg)  # 只有在需要时才更新

    def get_result(self) -> bool:
        if self._cal_alg.every_request:
            return self.run_alg()
        else:
            return self._status


    def update_controller(self, status: bool):
        self._pre_status = self._status
        self._status = status

    def __repr__(self):
        return f"DynamicController(tag_group = {self._tag_group}, policy = {self._policy})"