from enum import IntEnum
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 RangeMinRate(IntEnum):
    """
    Describes available values for rate in Adaptive-Sync tests.
    """
    Rate_59_940Hz = 0
    Rate_47_952Hz = 1
    Rate_29_970Hz = 2
    Rate_23_976Hz = 3


class AdaptiveSyncDpCaps(Param):
    """
    Class `AdaptiveSyncDp14Caps` defines adaptive-sync capabilities and allows setting:
    - Support Adaptive-Sync `support_adaptive_sync`.
    - Support fixed average `support_fixed_average`.
    - Support duration increase and decrease `support_duration_increase_and_decrease`.
    """
    def __init__(self, json_obj):
        super().__init__(json_obj)

    @property
    def support_adaptive_sync(self):
        """
        Set and get adaptive-sync flag support.

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

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

    @property
    def support_fixed_average(self):
        """
        Set and get fixed average flag support.

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

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

    @property
    def support_duration_increase_and_decrease(self):
        """
        Set and get duration increase and decrease flag support.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(2, bool)

    @support_duration_increase_and_decrease.setter
    def support_duration_increase_and_decrease(self, support: bool):
        self._set_by_bitmask(support, 2)

    @property
    def enable_manually(self):
        """
        Set and get enable manually flag support.

        Returns:
            object of bool type
        """
        return self._get_by_bitmask(3, bool)

    @enable_manually.setter
    def enable_manually(self, enable: bool):
        self._set_by_bitmask(enable, 3)


class AdaptiveSyncDpConfigTabBase:
    def __init__(self, caps: AdaptiveSyncDpCaps, as_range_min_rate,
                 max_rate_1920x1080,
                 max_rate_2560x1080,
                 max_rate_2560x1440,
                 max_rate_3840x2160,
                 max_rate_4096x2160,
                 max_rate_5120x2160,
                 max_rate_7680x4320,
                 max_rate_10240x4320):
        self._caps = caps
        self._as_range_min_rate = as_range_min_rate
        self._max_rate_1920x1080 = max_rate_1920x1080
        self._max_rate_2560x1080 = max_rate_2560x1080
        self._max_rate_2560x1440 = max_rate_2560x1440
        self._max_rate_3840x2160 = max_rate_3840x2160
        self._max_rate_4096x2160 = max_rate_4096x2160
        self._max_rate_5120x2160 = max_rate_5120x2160
        self._max_rate_7680x4320 = max_rate_7680x4320
        self._max_rate_10240x4320 = max_rate_10240x4320

    @property
    def as_caps(self) -> AdaptiveSyncDpCaps:
        """
        Set and get adaptive-sync capabilities.

        Returns:
            object `AdaptiveSyncDp14Caps`
        """
        return self._caps

    @as_caps.setter
    def as_caps(self, caps: AdaptiveSyncDpCaps):
        self._caps = caps

    @property
    def as_range_min_rate(self) -> int:
        """
        Set and get adaptive-sync minimum rate.

        Returns:
            object `RangeMinRate`
        """
        return self._as_range_min_rate

    @as_range_min_rate.setter
    def as_range_min_rate(self, as_range_min_rate: RangeMinRate):
        self._as_range_min_rate.default_value = as_range_min_rate.value

    @property
    def max_rate_1920x1080(self) -> int:
        """
        Set and get maximum rate for resolution 1920x1080

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

    @max_rate_1920x1080.setter
    def max_rate_1920x1080(self, max_rate_1920x1080: int):
        if not (
                self._max_rate_1920x1080.min_value <= max_rate_1920x1080 < self._max_rate_1920x1080.max_value):
            raise ValueError(f"Max rate for 1920x1080 cannot be less than "
                             f"{self._max_rate_1920x1080.min_value} and more than "
                             f"{self._max_rate_1920x1080.max_value}.")
        self._max_rate_1920x1080.default_value = max_rate_1920x1080

    @property
    def max_rate_2560x1080(self) -> int:
        """
        Set and get maximum rate for resolution 2560x1080

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

    @max_rate_2560x1080.setter
    def max_rate_2560x1080(self, max_rate_2560x1080: int):
        if not (
                self._max_rate_2560x1080.min_value <= max_rate_2560x1080 < self._max_rate_2560x1080.max_value):
            raise ValueError(f"Max rate for 2560x1080 cannot be less than "
                             f"{self._max_rate_2560x1080.min_value} and more than "
                             f"{self._max_rate_2560x1080.max_value}.")
        self._max_rate_2560x1080.default_value = max_rate_2560x1080

    @property
    def max_rate_2560x1440(self) -> int:
        """
        Set and get maximum rate for resolution 2560x1440

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

    @max_rate_2560x1440.setter
    def max_rate_2560x1440(self, max_rate_2560x1440: int):
        if not (
                self._max_rate_2560x1440.min_value <= max_rate_2560x1440 < self._max_rate_2560x1440.max_value):
            raise ValueError(f"Max rate for 2560x1080 cannot be less than "
                             f"{self._max_rate_2560x1440.min_value} and more than "
                             f"{self._max_rate_2560x1440.max_value}.")
        self._max_rate_2560x1440.default_value = max_rate_2560x1440

    @property
    def max_rate_3840x2160(self) -> int:
        """
        Set and get maximum rate for resolution 3840x2160

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

    @max_rate_3840x2160.setter
    def max_rate_3840x2160(self, max_rate_3840x2160: int):
        if not (
                self._max_rate_3840x2160.min_value <= max_rate_3840x2160 < self._max_rate_3840x2160.max_value):
            raise ValueError(f"Max rate for 3840x2160 cannot be less than "
                             f"{self._max_rate_3840x2160.min_value} and more than "
                             f"{self._max_rate_3840x2160.max_value}.")
        self._max_rate_3840x2160.default_value = max_rate_3840x2160

    @property
    def max_rate_4096x2160(self) -> int:
        """
        Set and get maximum rate for resolution 4096x2160

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

    @max_rate_4096x2160.setter
    def max_rate_4096x2160(self, max_rate_4096x2160: int):
        if not (
                self._max_rate_4096x2160.min_value <= max_rate_4096x2160 < self._max_rate_4096x2160.max_value):
            raise ValueError(f"Max rate for 4096x2160 cannot be less than "
                             f"{self._max_rate_4096x2160.min_value} and more than "
                             f"{self._max_rate_4096x2160.max_value}.")
        self._max_rate_4096x2160.default_value = max_rate_4096x2160

    @property
    def max_rate_5120x2160(self) -> int:
        """
        Set and get maximum rate for resolution 5120x2160

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

    @max_rate_5120x2160.setter
    def max_rate_5120x2160(self, max_rate_5120x2160: int):
        if not (
                self._max_rate_5120x2160.min_value <= max_rate_5120x2160 < self._max_rate_5120x2160.max_value):
            raise ValueError(f"Max rate for 5120x2160 cannot be less than "
                             f"{self._max_rate_5120x2160.min_value} and more than "
                             f"{self._max_rate_5120x2160.max_value}.")
        self._max_rate_5120x2160.default_value = max_rate_5120x2160

    @property
    def max_rate_7680x4320(self) -> int:
        """
        Set and get maximum rate for resolution 7680x4320

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

    @max_rate_7680x4320.setter
    def max_rate_7680x4320(self, max_rate_7680x4320: int):
        if not (
                self._max_rate_7680x4320.min_value <= max_rate_7680x4320 < self._max_rate_7680x4320.max_value):
            raise ValueError(f"Max rate for 7680x4320 cannot be less than "
                             f"{self._max_rate_7680x4320.min_value} and more than "
                             f"{self._max_rate_7680x4320.max_value}.")
        self._max_rate_7680x4320.default_value = max_rate_7680x4320

    @property
    def max_rate_10240x4320(self) -> int:
        """
        Set and get maximum rate for resolution 10240x4320

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

    @max_rate_10240x4320.setter
    def max_rate_10240x4320(self, max_rate_10240x4320: int):
        if not (
                self._max_rate_10240x4320.min_value <= max_rate_10240x4320 < self._max_rate_10240x4320.max_value):
            raise ValueError(f"Max rate for 10240x4320 cannot be less than "
                             f"{self._max_rate_10240x4320.min_value} and more than "
                             f"{self._max_rate_10240x4320.max_value}.")
        self._max_rate_10240x4320.default_value = max_rate_10240x4320

    def clear_max_rates(self):
        """
        Clear rates settings.
        """
        self.max_rate_1920x1080 = 0
        self.max_rate_2560x1080 = 0
        self.max_rate_2560x1440 = 0
        self.max_rate_3840x2160 = 0
        self.max_rate_4096x2160 = 0
        self.max_rate_5120x2160 = 0
        self.max_rate_7680x4320 = 0
        self.max_rate_10240x4320 = 0


class AdaptiveSyncDp14ConfigTab(AdaptiveSyncDpConfigTabBase):
    """
    Class `AdaptiveSyncDp14ConfigTab` allows working with parameters for DP 1.4 Adaptive-Sync tests.
    - Set and get capabilities `as_caps` type `AdaptiveSyncDp14Caps`.
    - Set and get adaptive-sync range minimum rate `as_range_min_rate` type `RangeMinRate`.
    - Set and get maximum rate for resolution 1920x1080 `max_rate_1920x1080`.
    - Set and get maximum rate for resolution 2560x1080 `max_rate_2560x1080`.
    - Set and get maximum rate for resolution 2560x1440 `max_rate_2560x1440`.
    - Set and get maximum rate for resolution 3840x2160 `max_rate_3840x2160`.
    - Set and get maximum rate for resolution 4096x2160 `max_rate_4096x2160`.
    - Set and get maximum rate for resolution 5120x2160 `max_rate_5120x2160`.
    - Set and get maximum rate for resolution 7680x4320 `max_rate_7680x4320`.
    - Set and get maximum rate for resolution 10240x4320 `max_rate_10240x4320`.
    """
    def __init__(self, json_obj):
        super().__init__(AdaptiveSyncDpCaps(json_obj["TSI_DP14_SRCCTS_AS_DUT_CAPS"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MIN_RATE"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_0"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_1"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_2"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_3"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_4"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_5"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_6"]),
                         Param(json_obj["TSI_DP14_SRCCTS_AS_RANGE_MAX_RATE_7"])
                         )


class AdaptiveSyncDp21ConfigTab(AdaptiveSyncDpConfigTabBase):
    """
    Class `AdaptiveSyncDp21ConfigTab` inherited of class`AdaptiveSyncDp14ConfigTab` allows working with
    parameters for DP 2.1 Adaptive-Sync tests
    Class `AdaptiveSyncDp21ConfigTab` has all the `AdaptiveSyncDp14ConfigTab` functionality.
    """
    def __init__(self, json_obj):
        super().__init__(AdaptiveSyncDpCaps(json_obj["TSI_DP20_SRCCTS_AS_DUT_CAPS"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MIN_RATE"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_0"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_1"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_2"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_3"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_4"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_5"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_6"]),
                         Param(json_obj["TSI_DP20_SRCCTS_AS_RANGE_MAX_RATE_7"])
                         )
