from UniTAP.dev.modules.dut_tests.test_group_params_types import Param
from UniTAP.dev.modules.dut_tests.test_utils import update_default_value


class VrrCaps(Param):
    """
    Class `VrrCaps` describes DUT VRR capabilities flags and allows settings values.
    - VRR enable/disable `vrr_enable`.
    - Defines M_CONST `m_const`.
    """
    def __init__(self, json_obj):
        super().__init__(json_obj)

    @property
    def vrr_enable(self):
        """
        Set and get VRR enable/disable flag.

        Returns:
            object bool
        """
        return self._get_by_bitmask(0, bool)

    @vrr_enable.setter
    def vrr_enable(self, vrr_enable: bool):
        self._set_by_bitmask(vrr_enable, 0)

    @property
    def m_const(self):
        """
        Set and get m const enable/disable flag.

        Returns:
            object bool
        """
        return self._get_by_bitmask(1, bool)

    @m_const.setter
    def m_const(self, m_const: bool):
        self._set_by_bitmask(m_const, 1)


class BaseFront(Param):
    """
    Class `BaseFront` describes DUT BaseFront capabilities flags and allows settings values.
    - Base front value `vrr_enable`.
    - Reduced blanking enable/disable `m_const`.
    """
    def __init__(self, json_obj):
        super().__init__(json_obj)

    @property
    def base_front(self):
        """
        Set and get va;ue of base front.

        Returns:
            object int
        """
        return self._get_by_bitmask(0, int)

    @base_front.setter
    def base_front(self, base_front: int):
        if not (0 <= base_front <= 3):
            raise ValueError(f"Base front value cannot be less than 0 and more than 3")
        self._set_by_bitmask(base_front, 0)

    @property
    def reduced_blanking(self):
        """
        Set and get reduced blanking flag support.

        Returns:
            object bool
        """
        return self._get_by_bitmask(1, bool)

    @reduced_blanking.setter
    def reduced_blanking(self, reduced_blanking: bool):
        self._set_by_bitmask(reduced_blanking, 1)


class VrrTestParamBase:
    """
    Class `VrrTestParam` describes parameters for VRR Sink and Source tests.
    - Test timeout, in milliseconds `timeout`.
    - Defines VRR Max value `vrr_max`.
    - Defines VRR Min value `vrr_min`.
    - Defines VRR Static value `vrr_static`.
    - Defines step of changing frame rate `vrr_step`.
    - Defines timer to change frame rate `vrr_time_step`.
    - Defines VRR capabilities `vrr_enable_cups` type `VrrCaps`.
    - Defines VRR Base front `base_vfront` type `BaseFront`.
    - Defines Base Refresh Rate `base_rate`.
    """
    def __init__(self, timeout, vrr_max, vrr_min, vrr_static, vrr_step, vrr_time_step,
                 vrr_enable_cups, base_vfront, base_rate):
        self.__timeout = timeout
        self.__vrr_max = vrr_max
        self.__vrr_min = vrr_min
        self.__vrr_static = vrr_static
        self.__vrr_step = vrr_step
        self.__vrr_time_step = vrr_time_step
        self.__vrr_enable_cups = vrr_enable_cups
        self.__base_vfront = base_vfront
        self.__base_rate = base_rate

    @property
    def timeout(self) -> int:
        """
        Set and get test timeout, in milliseconds.

        Returns:
            object of int type
        """
        return self.__timeout.default_value

    @timeout.setter
    def timeout(self, timeout: int):
        if not(self.__timeout.min_value < timeout < self.__timeout.max_value):
            raise ValueError(f"Timeout cannot be less than {self.__timeout.min_value} and more than "
                             f"{self.__timeout.max_value}.")
        self.__timeout.default_value = timeout

    @property
    def vrr_max(self) -> int:
        """
        Set and get VRR max.

        Returns:
            object of int type
        """
        return self.__vrr_max.default_value

    @vrr_max.setter
    def vrr_max(self, vrr_max: int):
        if not(self.__vrr_max.min_value < vrr_max < self.__vrr_max.max_value):
            raise ValueError(f"VRR max cannot be less than {self.__vrr_max.min_value} and more than "
                             f"{self.__vrr_max.max_value}.")
        self.__vrr_max.default_value = vrr_max

    @property
    def vrr_min(self) -> int:
        """
        Set and get VRR min.

        Returns:
            object of int type
        """
        return self.__vrr_min.default_value

    @vrr_min.setter
    def vrr_min(self, vrr_min: int):
        if not(self.__vrr_min.min_value < vrr_min < self.__vrr_min.max_value):
            raise ValueError(f"VRR min cannot be less than {self.__vrr_min.min_value} and more than "
                             f"{self.__vrr_min.max_value}.")
        self.__vrr_min.default_value = vrr_min

    @property
    def vrr_static(self) -> int:
        """
        Set and get VRR static.

        Returns:
            object of int type
        """
        return self.__vrr_static.default_value

    @vrr_static.setter
    def vrr_static(self, vrr_static: int):
        if not(self.__vrr_static.min_value < vrr_static < self.__vrr_static.max_value):
            raise ValueError(f"VRR stasic cannot be less than {self.__vrr_static.min_value} and more than "
                             f"{self.__vrr_static.max_value}.")
        self.__vrr_static.default_value = vrr_static

    @property
    def vrr_step(self) -> int:
        """
        Set and get VRR step.

        Returns:
            object of int type
        """
        return self.__vrr_step.default_value

    @vrr_step.setter
    def vrr_step(self, vrr_step: int):
        if not(self.__vrr_step.min_value < vrr_step < self.__vrr_step.max_value):
            raise ValueError(f"VRR step cannot be less than {self.__vrr_step.min_value} and more than "
                             f"{self.__vrr_step.max_value}.")
        self.__vrr_step.default_value = vrr_step

    @property
    def vrr_time_step(self) -> int:
        """
        Set and get VRR time step.

        Returns:
            object of int type
        """
        return self.__vrr_time_step.default_value

    @vrr_time_step.setter
    def vrr_time_step(self, vrr_time_step: int):
        if not(self.__vrr_time_step.min_value < vrr_time_step < self.__vrr_time_step.max_value):
            raise ValueError(f"VRR time step cannot be less than {self.__vrr_time_step.min_value} and more than "
                             f"{self.__vrr_time_step.max_value}.")
        self.__vrr_time_step.default_value = vrr_time_step

    @property
    def vrr_enable_cups(self):
        """
        Set and get VRR caps.

        Returns:
            object of `VrrCaps` type
        """
        return self.__vrr_enable_cups

    @vrr_enable_cups.setter
    def vrr_enable_cups(self, vrr_enable_cups: VrrCaps):
        self.__vrr_enable_cups = vrr_enable_cups

    @property
    def base_vfront(self):
        """
        Set and get base vfront value.

        Returns:
            object of BaseFront type
        """
        return self.__base_vfront

    @base_vfront.setter
    def base_vfront(self, base_vfront: BaseFront):
        self.__base_vfront = base_vfront

    @property
    def base_rate(self) -> int:
        """
        Set and get base rate.

        Returns:
            object of int type
        """
        return self.__base_rate.default_value

    @base_rate.setter
    def base_rate(self, base_rate: int):
        if not(self.__base_rate.min_value < base_rate < self.__base_rate.max_value):
            raise ValueError(f"VRR time step cannot be less than {self.__vrr_time_step.min_value} and more than "
                             f"{self.__base_rate.max_value}.")
        self.__base_rate.default_value = base_rate


class VrrSinkDUTTestParam(VrrTestParamBase):
    """
    Class `VrrSinkDUTTestParam` describes parameters for VRR Sink and Source tests.
    - Test timeout, in milliseconds `timeout`.
    - Defines VRR Max value `vrr_max`.
    - Defines VRR Min value `vrr_min`.
    - Defines VRR Static value `vrr_static`.
    - Defines step of changing frame rate `vrr_step`.
    - Defines timer to change frame rate `vrr_time_step`.
    - Defines VRR capabilities `vrr_enable_cups` type `VrrCaps`.
    - Defines VRR Base front `base_vfront` type `BaseFront`.
    - Defines Base Refresh Rate `base_rate`.
    """
    def __init__(self, json_obj):
        super().__init__(Param(json_obj["TSI_VRR_SINK_DUT_TIMEOUT"]),
                         Param(json_obj["TSI_VRR_SINK_DUT_VRR_MAX"]),
                         Param(json_obj["TSI_VRR_SINK_DUT_VRR_MIN"]),
                         Param(json_obj["TSI_VRR_SINK_DUT_VRR_STATIC"]),
                         Param(json_obj["TSI_VRR_SINK_DUT_VRR_STEP"]),
                         Param(json_obj["TSI_VRR_SINK_DUT_VRR_TIME_STEP"]),
                         VrrCaps(json_obj["TSI_VRR_SINK_DUT_VRR_ENABLE"]),
                         BaseFront(json_obj["TSI_VRR_SINK_DUT_BASE_VFRONT"]),
                         Param(json_obj["TSI_VRR_SINK_DUT_BASE_RATE"]))


class VrrSourceDUTTestParam(VrrTestParamBase):
    """
    Class `VrrSourceDUTTestParam` describes parameters for VRR Sink and Source tests.
    - Test timeout, in milliseconds `timeout`.
    - Defines VRR Max value `vrr_max`.
    - Defines VRR Min value `vrr_min`.
    - Defines VRR Static value `vrr_static`.
    - Defines step of changing frame rate `vrr_step`.
    - Defines timer to change frame rate `vrr_time_step`.
    - Defines VRR capabilities `vrr_enable_cups` type `VrrCaps`.
    - Defines VRR Base front `base_vfront` type `BaseFront`.
    - Defines Base Refresh Rate `base_rate`.
    """
    def __init__(self, json_obj):
        super().__init__(Param(json_obj["TSI_VRR_SRC_DUT_TIMEOUT"]),
                         Param(json_obj["TSI_VRR_SRC_DUT_VRR_MAX"]),
                         Param(json_obj["TSI_VRR_SRC_DUT_VRR_MIN"]),
                         Param(json_obj["TSI_VRR_SRC_DUT_VRR_STATIC"]),
                         Param(json_obj["TSI_VRR_SRC_DUT_VRR_STEP"]),
                         Param(json_obj["TSI_VRR_SRC_DUT_VRR_TIME_STEP"]),
                         VrrCaps(json_obj["TSI_VRR_SRC_DUT_VRR_ENABLE"]),
                         BaseFront(json_obj["TSI_VRR_SRC_DUT_BASE_VFRONT"]),
                         Param(json_obj["TSI_VRR_SRC_DUT_BASE_RATE"]))
