from enum import IntEnum
from UniTAP.dev.modules.dut_tests.test_group_params_types import Param


class LinkRate(IntEnum):
    """
    Class `LinkRate` describes available supported link rates.
    """
    Rate_1_62_Gbps = 6
    Rate_2_7_Gbps = 10
    Rate_5_4_Gbps = 20
    Rate_8_1_Gbpc = 30


class LinkConfigTestParam:
    """
    Class `LinkConfigTestParam` describes parameters for Link configuration test.
    - Test timeout, in milliseconds `timeout`.
    - Defines the maximum number of lanes to be tested `max_lane_count`. Possible variants: 1, 2, 4.
    - Defines the maximum link rate to be tested `max_rate` type `LinkRate`.
    - Defines the length of the HPD pulse used to start each  test iteration, in milliseconds `hpd_pulse_duration`.
    - Defines how long the test waits for LT start after issuing HPD pulse, in milliseconds `lt_start_timeout`.
    - Defines the additional delay inserted in between test iterations, in milliseconds `test_loop_delay`.
    """
    def __init__(self, json_obj):
        self.__timeout = Param(json_obj["TSI_DP_LTT_TIMEOUT"])
        self.__max_lane_count = Param(json_obj["TSI_DP_LTT_MAX_LANE_COUNT"])
        self.__max_rate = Param(json_obj["TSI_DP_LTT_MAX_RATE"])
        self.__hpd_pulse_duration = Param(json_obj["TSI_DP_LTT_HPD_PULSE_DURATION"])
        self.__lt_start_timeout = Param(json_obj["TSI_DP_LTT_LT_START_TIMEOUT"])
        self.__test_loop_delay = Param(json_obj["TSI_DP_LTT_TEST_LOOP_DELAY"])

    @property
    def timeout(self):
        """
        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 max_lane_count(self) -> int:
        """
        Set and get maximum number of lanes.

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

    @max_lane_count.setter
    def max_lane_count(self, max_lane_count: int):
        if not max_lane_count in [1, 2, 4]:
            raise ValueError("Max lane count must be in range: 1, 2, or 4.")
        self.__max_lane_count.default_value = max_lane_count

    @property
    def max_rate(self):
        """
        Set and get maximum link rate.

        Returns:
            object `LinkRate`
        """
        return self.__max_rate.default_value

    @max_rate.setter
    def max_rate(self, max_rate: LinkRate):
        self.__max_rate.default_value = max_rate.value

    @property
    def hpd_pulse_duration(self) -> int:
        """
        Set and get length of the HPD pulse.

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

    @hpd_pulse_duration.setter
    def hpd_pulse_duration(self, hpd_pulse_duration: int):
        if not(self.__hpd_pulse_duration.min_value < hpd_pulse_duration < self.__hpd_pulse_duration.max_value):
            raise ValueError(f"HPD pulse duration must be less than {self.__hpd_pulse_duration.min_value} and more than"
                             f" {self.__hpd_pulse_duration.max_value}.")
        self.__hpd_pulse_duration.default_value = hpd_pulse_duration

    @property
    def lt_start_timeout(self) -> int:
        """
        Set and get link training start timeout.

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

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

    @property
    def test_loop_delay(self) -> int:
        """
        Set and get test loop delay.

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

    @test_loop_delay.setter
    def test_loop_delay(self, test_loop_delay: int):
        if not(self.__test_loop_delay.min_value < test_loop_delay < self.__test_loop_delay.max_value):
            raise ValueError(f"Test loop delay cannot be less than {self.__test_loop_delay.min_value} "
                             f"and more than {self.__test_loop_delay.max_value}.")
        self.__test_loop_delay.default_value = test_loop_delay
