from typing import TypeVar
from enum import IntEnum


class LinkCapabilities:
    """
    Class `LinkCapabilities` describes capabilities of DP link.
    """
    def __init__(self):
        self.max_lane = None
        self.bit_rate = None
        self.dp_128_132_bitrates = None
        self.override_10g = None
        self.old_dp_2_0_lt = None
        self.force_cable_status_to_plugged = None
        self.mst = None
        self.ss_sbm = None
        self.fec = None
        self.tps4 = None
        self.tps3 = None
        self.dsc = None
        self.mst_sink_count = None

    def __str__(self) -> str:
        return f"Max Lanes - {self.max_lane}\n" \
               f"Max Bitrate - {self.bit_rate}\n" \
               f"DP (128b/132b) Supported Bitrates - {self.dp_128_132_bitrates}\n" \
               f"Instead of 10 Gbps, use - {self.override_10g}\n" \
               f"Old DP 2.0 LT - {self.old_dp_2_0_lt}\n" \
               f"Force Cable Status to Plugged - {self.force_cable_status_to_plugged}\n" \
               f"MST - {self.mst} (Sink Count - {self.mst_sink_count})\n" \
               f"SS SBM - {self.ss_sbm}\n" \
               f"FEC - {self.fec}\n" \
               f"TPS4 - {self.tps4}\n" \
               f"TPS3 - {self.tps3}\n" \
               f"DSC - {self.dsc}\n"


class LinkEDPCapabilities:
    """
    Class `LinkEDPCapabilities` describes capabilities of eDP link.
    """

    def __init__(self):
        self.max_lane = None
        self.eDp_cur_rate = None
        self.eDp_supported_rates = None
        self.eDp_aux_preamble = None
        self.eDp_support = None

    def __str__(self) -> str:
        return f"Max Lanes - {self.max_lane}\n" \
               f"eDP rate - {self.eDp_cur_rate}\n" \
               f"eDP supported rates - {self.eDp_supported_rates}\n" \
               f"eDP AUX preamble - {self.eDp_aux_preamble}\n" \
               f"eDp Support - {self.eDp_support}"


DisplayPortLinkCaps = TypeVar("DisplayPortLinkCaps",
                              LinkEDPCapabilities,
                              LinkCapabilities)


class CableCapabilitiesEnum(IntEnum):
    Unknown = 0,
    DP40 = 1
    DP54 = 2
    DP80 = 3

    def __str__(self) -> str:
        return self.name


class RoutedLTConfig:
    """
    Class `RoutedLTConfig` describes configuration fields for Routed LinkTraining.
    """
    def __init__(self):
        self.__is128b132b = False
        self.__is_old_dp20_lt = False
        self.__vs = 0
        self.__pe = 0
        self.__ffe = 0
        self.__link_bw = 0
        self.__lane_count = 0

    @property
    def is128b132b(self) -> bool:
        return self.__is128b132b

    @is128b132b.setter
    def is128b132b(self, value: bool = False):
        self.__is128b132b = value

    @property
    def is_old_dp20_lt(self) -> bool:
        return self.__is_old_dp20_lt

    @is_old_dp20_lt.setter
    def is_old_dp20_lt(self, value: bool = False):
        self.__is_old_dp20_lt = value

    @property
    def vs(self) -> int:
        return self.__vs

    @vs.setter
    def vs(self, value: int):
        if not (0 <= value < 3):
            raise ValueError(f"VS cannot be less than 0 and more than 3")
        self.__vs = value

    @property
    def pe(self) -> int:
        return self.__pe

    @pe.setter
    def pe(self, value: int):
        if not (0 <= value <= 0x3):
            raise ValueError(f"PE cannot be less than 0 and more than 0x3")
        self.__pe = value

    @property
    def ffe(self) -> int:
        return self.__ffe

    @ffe.setter
    def ffe(self, value: int):
        if not (0 <= value <= 0xF):
            raise ValueError(f"FFE cannot be less than 0 and more than 0xF")
        self.__ffe = value

    @property
    def link_bw(self) -> int:
        return self.__link_bw

    @link_bw.setter
    def link_bw(self, value: int):
        if not (0 <= value <= 0xFF):
            raise ValueError(f"link_bw cannot be less than 0 and more than 0xFF")
        self.__link_bw = value

    @property
    def lane_count(self) -> int:
        return self.__lane_count

    @lane_count.setter
    def lane_count(self, value: int):
        if not (0 <= value <= 0xFF):
            raise ValueError(f"lane_count cannot be less than 0 and more than 0xFF")
        self.__lane_count = value

    def int_value(self) -> int:
        val = (self.ffe << 8) if self.is128b132b else ((self.vs << 8) | (self.pe << 10))
        return self.is128b132b | (self.__is_old_dp20_lt << 1) | val | (self.link_bw << 16) | (self.lane_count << 24)


class RoutedLTStatus:

    __StateToStr = {0: "Not started", 1: "In progress", 2: "Finished", 3: "Incorrect"}

    def __init__(self, enabled: bool, dp20_old_lt: bool, state: int, success: bool, step: int):
        self.enabled = enabled
        self.dp20_old_lt = dp20_old_lt
        self.state = state
        self.success = success
        self.step = step

    def __str__(self) -> str:

        return (f"Is Enabled: {'yes' if self.enabled else 'no'}\n"
                f"Is DP 20 old LT: {'yes' if self.dp20_old_lt else 'no'}\n"
                f"State: {self.__StateToStr.get(self.state)}\n"
                f"Result: {'Successful' if self.success else 'Unsuccessful'}\n"
                f"Steps: {self.step}")


