from typing import TypeVar
from enum import IntEnum
from .link_status_common import DpLinkEncoding


class DPLinkPattern(IntEnum):
    """
    Class `DPLinkPattern` contains all possible variants of DP link patterns.
    Names TrainingPattern1, TrainingPattern2, TrainingPattern3, TrainingPattern4 will be deleted in RC 3.7
    """
    ActiveVideo = 0
    IdlePattern = 1
    TrainingPattern1 = 2
    TrainingPattern2 = 3
    TrainingPattern3 = 4
    TrainingPattern4 = 5
    PRBS7 = 6
    HBR2 = 7
    SER = 8
    ForceVideo = 10
    ForceIdle = 11
    PRBS9 = 12
    PRBS11 = 13
    PRBS15 = 14
    PRBS23 = 15
    PRBS31 = 16
    LinkSquarePattern = 17
    Undefined = 18
    TPS1 = TrainingPattern1
    TSP2 = TrainingPattern2
    TSP3 = TrainingPattern3
    TSP4 = TrainingPattern4


class DP128b132bLinkPattern(IntEnum):
    """
    Class `DP128b132bLinkPattern` contains all possible output patterns in DP2.0 force link mode.
    """
    ActiveVideo = 0
    IdlePattern = 1
    TPS1 = 2
    TPS2 = 3
    PRBS9 = 4
    PRBS11 = 5
    PRBS15 = 6
    PRBS23 = 7
    PRBS31 = 8
    Custom80bit = 9
    LinkSquarePattern = 10
    PRBS7 = 11


class DPOutLinkMode(IntEnum):
    """
    Class `DPOutLinkMode` contains all possible out link modes.
    """
    Normal = 0
    Force8b10b = 1
    Force128b132b = 2


class SSCConfig:
    """
    Class `SSCConfig` contains information about SSC configuration parameters.
    - Set and get amplitude `amplitude`.
    - Set and get frequency `frequency`.
    - Enable flag.
    """
    def __init__(self):
        self.enabled = False
        self.amplitude = 0.5
        self.frequency = 30000

    def __eq__(self, other) -> bool:
        return self.enabled == other.enabled and \
               self.amplitude == other.amplitude and \
               self.frequency == other.frequency

    def __str__(self) -> str:
        return f"Enabled - {self.enabled}\n" \
               f"Amplitude - {self.amplitude}\n" \
               f"Frequency - {self.frequency}\n"


class LinkConfig:
    """
    Main class contains variants of link configuration:
    - DP 1.4 config `DP8b10b`.
    - DP 2.1 config `DP128b132b`.
    """
    class DP8b10b:
        """
        Class `DP8b10b` contains information of possible DP 1.4 configuration. Contains following field:
        - lane count
        - link bit rate
        - MST
        - MST stream count
        - set enhanced framing mode
        - Auto seed
        - SSC
        - FEC
        - Force EDID timings after link training
        - Adaptive-Sync auto enable
        - Split SDP (if supported)
        """
        def __init__(self):
            self.lane_count = None
            self.bit_rate = None
            self.mst = None
            self.mst_stream_count = None
            self.enhanced_framing_mode = None
            self.auto_seed = None
            self.ssc = None
            self.fec = None
            self.force_edid_timings_after_lt = None
            self.adaptive_sync_auto_enable = None
            self.split_sdp = None

        def __eq__(self, other) -> bool:
            return self.lane_count == other.lane_count and \
                   self.bit_rate == other.bit_rate and \
                   self.mst == other.mst and \
                   self.mst_stream_count == other.mst_stream_count and \
                   self.enhanced_framing_mode == other.enhanced_framing_mode and \
                   self.auto_seed == other.auto_seed and \
                   self.ssc == other.ssc and \
                   self.fec == other.fec and \
                   self.force_edid_timings_after_lt == other.force_edid_timings_after_lt and \
                   self.adaptive_sync_auto_enable == other.adaptive_sync_auto_enable and \
                   self.split_sdp == other.split_sdp

        def __str__(self) -> str:
            return f"Lane Count - {self.lane_count}\n" \
                   f"Bit rate - {self.bit_rate:.3}\nMST enabled - {self.mst}\n" \
                   f"MST stream count - {self.mst_stream_count}\n" \
                   f"Enhanced framing mode - {bool(self.enhanced_framing_mode)}\n" \
                   f"Auto Seed - {bool(self.auto_seed)}\nSSC info:\n{self.ssc.__str__()}\nFEC: {self.fec}\n" \
                   f"Force EDID Timings after LT: {self.force_edid_timings_after_lt}\n" \
                   f"Adaptive Sync auto enable: {self.adaptive_sync_auto_enable}\n" \
                   f"Split SDP: {self.split_sdp}\n"

    class DP128b132b:
        """
        Class `DP128b132b` contains information of possible DP 2.1 configuration. Contains following field:
        - lane count
        - link bit rate
        - Force DP 128/132
        - Maximum link bandwidth supported
        - Set enhanced framing mode
        - Auto seed
        - SSC
        - LLTPR
        - Try (enable/disable) DP 128/132
        - Old DP2 link training
        - Force EDID timings after link training
        - Adaptive-Sync auto enable
        - Split SDP (if supported)
        - Force eDP rates
        """
        def __init__(self):
            self.lane_count = None
            self.bit_rate = None
            self.force_dp_128_132 = None
            self.enhanced_framing_mode = None
            self.max_link_bandwidth_supported = None
            self.old_dp2_lt = None
            self.lttpr = None
            self.try_dp_128_132 = None
            self.auto_seed = None
            self.ssc = None
            self.force_edid_timings_after_lt = None
            self.adaptive_sync_auto_enable = None
            self.mst = None
            self.mst_stream_count = None
            self.crc_16 = None

        def __eq__(self, other) -> bool:
            return self.lane_count == other.lane_count and \
                   self.bit_rate == other.bit_rate and \
                   self.force_dp_128_132 == other.force_dp_128_132 and \
                   self.max_link_bandwidth_supported == other.max_link_bandwidth_supported and \
                   self.old_dp2_lt == other.old_dp2_lt and \
                   self.lttpr == other.lttpr and \
                   self.try_dp_128_132 == other.try_dp_128_132 and \
                   self.enhanced_framing_mode == other.enhanced_framing_mode and \
                   self.auto_seed == other.auto_seed and \
                   self.ssc == other.ssc and \
                   self.force_edid_timings_after_lt == other.force_edid_timings_after_lt and \
                   self.adaptive_sync_auto_enable == other.adaptive_sync_auto_enable and \
                   self.mst == other.mst and \
                   self.mst_stream_count == other.mst_stream_count and \
                   self.crc_16 == other.crc_16

        def __str__(self) -> str:
            return f"Lane Count - {self.lane_count}\n" \
                   f"Bit rate - {self.bit_rate:.3}\nMST enabled - {self.mst}\n" \
                   f"MST stream count - {self.mst_stream_count}\n" \
                   f"Force DP 128b/132b enabled - {self.force_dp_128_132}\n" \
                   f"Max link bandwidth supported - {self.max_link_bandwidth_supported}\n" \
                   f"Enhanced framing mode - {self.enhanced_framing_mode}\n" \
                   f"Try DP 128b/132b enabled - {self.try_dp_128_132}\n"\
                   f"Old DP 2.1 Link training enabled - {self.old_dp2_lt}\n" \
                   f"LTTPR enabled - {self.lttpr}\n" \
                   f"Auto Seed - {self.auto_seed}\nSSC info - {self.ssc.__str__()}\n" \
                   f"Force EDID Timings after LT: {self.force_edid_timings_after_lt}\n" \
                   f"Adaptive Sync auto enable: {self.adaptive_sync_auto_enable}\n" \
                   f"Split SDP: {self.crc_16}\n"

    class Force8b10b:
        """

        """
        def __init__(self):
            self.lane_count = None
            self.bit_rate = None
            self.pattern = None

        def __str__(self) -> str:
            return f"Lane Count - {self.lane_count}\n" \
                   f"Bit rate - {self.bit_rate:.3}\n" \
                   f"Link Pattern - {self.pattern.name}"

    class Force128b132b:
        """

        """
        def __init__(self):
            self.lane_count = None
            self.bit_rate = None
            self.pattern = None

        def __str__(self) -> str:
            return f"Lane Count - {self.lane_count}\n" \
                   f"Bit rate - {self.bit_rate:.3}\n" \
                   f"Link Pattern - {self.pattern.name}"

    class eDP:
        """

        """
        def __init__(self):
            self.lane_count = None
            self.force_edp = None
            self.eDp_cur_rate = None
            self.eDp_supported_rates = None
            self.eDp_aux_preamble = None

        def __str__(self) -> str:
            return f"Lane Count - {self.lane_count}\n" \
                   f"Force eDP: {bool(self.force_edp)}\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}"

        def __eq__(self, other) -> bool:
            return self.lane_count == other.lane_count and \
                self.force_edp == other.force_edp and \
                self.eDp_cur_rate == other.eDp_cur_rate and \
                self.eDp_aux_preamble == other.eDp_aux_preamble


class LinkStatus:
    """
    Main class describes current link status. Contains following field:
    - Lane count
    - BIt rate
    - State of enhanced framing
    - State of MST mode
    - State of DSC mode
    - LTTPR
    - Link encoding `DpLinkEncoding`
    - State of scrambling
    - State of SSC
    - State of FEC
    - State of eDP
    """
    def __init__(self):
        self.lane_count = 0
        self.bit_rate = 0
        self.enhanced_framing = False
        self.mst_enabled = False
        self.dsc_enabled = False
        self.lttpr = False
        self.link_encoding = DpLinkEncoding.LE_NONE
        self.scrambling_enabled = False
        self.ssc_enabled = False
        self.fec_enabled = False
        self.force_edp_enabled = False

    def __eq__(self, other) -> bool:
        return self.lane_count == other.lane_count and \
               self.bit_rate == other.bit_rate and \
               self.enhanced_framing == other.enhanced_framing and \
               self.mst_enabled == other.mst_enabled and \
               self.dsc_enabled == other.dsc_enabled and \
               self.lttpr == other.lttpr and \
               self.link_encoding == other.link_encoding and \
               self.scrambling_enabled == other.scrambling_enabled and \
               self.ssc_enabled == other.ssc_enabled and \
               self.fec_enabled == other.fec_enabled and \
               self.force_edp_enabled == other.force_edp_enabled

    def __str__(self) -> str:
        return f"Lane Count - {self.lane_count}\n" \
               f"Bit rate - {self.bit_rate:.3}\n" \
               f"Enhanced framing - {self.enhanced_framing}\n" \
               f"MST enabled - {self.mst_enabled}\n" \
               f"DSC enabled - {self.dsc_enabled}\n" \
               f"LTTPR - {self.lttpr}\n" \
               f"Link Encoding - {self.link_encoding.name}\n" \
               f"Scrambling enabled - {self.link_encoding.name}\n" \
               f"SSC enabled - {self.ssc_enabled}\n" \
               f"FEC enabled - {self.fec_enabled}\n"  \
               f"Force eDP enabled: {self.force_edp_enabled}"

    # class LinkOverrides:
    #
    #     def __init__(self):
    #         self.override_voltage = 0
    #         self.override_pre_emp = 0
    #         self.override_ffe_presets = [0] * 4


DisplayPortLinkConfig = TypeVar("DisplayPortLinkConfig",
                                LinkConfig.DP8b10b,
                                LinkConfig.DP128b132b,
                                LinkConfig.eDP,
                                LinkConfig.Force8b10b,
                                LinkConfig.Force128b132b)
