from enum import IntEnum
from typing import List


class PRCommand(IntEnum):
    """
    Class `PRCommand` contains all possible variants of Panel Replay Command.
    """

    No = 0
    EnablingInactive = 1
    EnablingActive = 2
    RFB = 3

    def __str__(self):
        if self.value == self.No:
            return "No command under execution."
        if self.value == self.EnablingInactive:
            return "Enabling inactive mode is in progress."
        if self.value == self.EnablingActive:
            return "Enabling active mode is in progress."
        if self.value == self.RFB:
            return "RFB selective update is in progress."


class PRStatus(IntEnum):
    """
    Class `PRStatus` contains all possible variants of Panel Replay Status.
    """

    Disabled = 0
    EnabledInactive = 1
    EnabledActive = 2

    def __str__(self):
        if self.value == self.Disabled:
            return "Disabled."
        if self.value == self.EnabledInactive:
            return "Enabled in an inactive mode."
        if self.value == self.EnabledActive:
            return "Enabled in an active mode."


class PRError(IntEnum):
    """
    Class `PRError` contains all possible variants of Panel Replay Error type.
    """

    No = 0
    Internal = 1
    IncorrectCommandReceived = 2
    FailedAccess = 3
    LTFailed = 4
    SelUpdIncorrect = 5

    def __str__(self):
        if self.value == self.No:
            return "No errors."
        if self.value == self.Internal:
            return "Internal error."
        if self.value == self.IncorrectCommandReceived:
            return "Incorrect command received."
        if self.value == self.FailedAccess:
            return "Failed to access DPCD."
        if self.value == self.LTFailed:
            return "LinkTraining failed."
        if self.value == self.SelUpdIncorrect:
            return "Selective update config is incorrect."


class PRMode(IntEnum):
    """
    Class `PRMode` contains all possible variants of Panel Replay mode.
    """
    PR = 0
    PSR1 = 1
    PSR2 = 2
    Res = 3


class YGranularity(IntEnum):
    """
    Class `YGranularity` contains all possible variants of SU Y granularity.
    """
    Value_8 = 0
    Value_10 = 1
    Value_12 = 2
    Value_14 = 3 
    Value_15 = 4
    Value_16 = 5 
    Value_18 = 6 
    Value_20 = 7 
    Value_24 = 8 
    Value_30 = 9
    Value_32 = 10
    Value_36 = 11 
    Value_40 = 12 
    Value_48 = 13 
    Value_54 = 14
    Value_64 = 15


class Region:
    """
    Class `Region` contains information about each PR Region (Frame).
    - Set and get X coordinate 'x'.
    - Set and get Y coordinate 'y'.
    - Set and get Width 'width'.
    - Set and get Height `height`
    """

    def __init__(self, x: int = 0, y: int = 0, width: int = 0, height: int = 0):
        self.__x = x
        self.__y = y
        self.__width = width
        self.__height = height

    @property
    def x(self) -> int:
        """
        Returns current X coordinate value.

        Returns:
            object of `int` type
        """
        return self.__x

    @x.setter
    def x(self, value: int):
        self.__x = value

    @property
    def y(self) -> int:
        """
        Returns current Y coordinate value.

        Returns:
            object of `int` type
        """
        return self.__y

    @y.setter
    def y(self, value: int):
        self.__y = value

    @property
    def width(self) -> int:
        """
        Returns current Width value.

        Returns:
            object of `int` type
        """
        return self.__width

    @width.setter
    def width(self, value: int):
        self.__width = value

    @property
    def height(self) -> int:
        """
        Returns current Height value.

        Returns:
            object of `int` type
        """
        return self.__height

    @height.setter
    def height(self, value: int):
        self.__height = value


class Flags:
    """
    Class `Flags` contains information about Panel Replay flags capabilities.
    - Set and get `early_transport` Early transport during selective update is supported.
    - Set and get `crc_in_vsc_sdp`. CRC for selective update region/full active frame in VSC SDP is supported.
    - Set and get `mode`. PanelReplay mode.
    - Set and get `hpd_irq`. Generate HPD_IRQ with Adaptive-Sync SDP missing (PR).
    - Set and get `hpd_irq_vsc_sdp`. IRQ_HPD with VSC SDP uncorrectable error (PR).
    - Set and get `hpd_irq_rfb`. IRQ_HPD with RFB storage error (PR).
    - Set and get `hpd_irq_crc`. IRQ_HPD with active frame CRC error.
    - Set and get `refresh_rate_unlock`. Sink refresh rate unlock granted.
    - Set and get `ext_y_gran`. Use SU extended Y granularity (PSR2 and PR).
    - Set and get `main_link_remain_on`. Main-link remains ON during PSR1/PSR2 active states.
    - Set and get `y_granularity`. SU Y granularity extended value selection.
    """

    def __init__(self, early_transport: bool = False, crc_in_vsc_sdp: bool = False, pr_mode: PRMode = PRMode.PR,
                 hpd_irq: bool = False, hpd_irq_vsc_sdp: bool = False, hpd_irq_rfb: bool = False,
                 hpd_irq_crc: bool = False, refresh_rate_unlock: bool = False, ext_y_gran: bool = False,
                 main_link_remain_on: bool = False, y_granularity: YGranularity = YGranularity.Value_8):
        self.__early_transport = early_transport
        self.__crc_in_vsc_sdp = crc_in_vsc_sdp
        self.__mode = pr_mode
        self.__hpd_irq = hpd_irq
        self.__hpd_irq_vsc_sdp = hpd_irq_vsc_sdp
        self.__hpd_irq_rfb = hpd_irq_rfb
        self.__hpd_irq_crc = hpd_irq_crc
        self.__refresh_rate_unlock = refresh_rate_unlock
        self.__ext_y_gran = ext_y_gran
        self.__main_link_remain_on = main_link_remain_on
        self.__y_granularity = y_granularity

    @property
    def early_transport(self) -> bool:
        """
        Returns current early transport value.

        Returns:
            object of `bool` type
        """
        return self.__early_transport

    @early_transport.setter
    def early_transport(self, value: bool):
        self.__early_transport = value

    @property
    def crc_in_vsc_sdp(self) -> bool:
        """
        Returns current crc in vsc sdp value.

        Returns:
            object of `bool` type
        """
        return self.__crc_in_vsc_sdp

    @crc_in_vsc_sdp.setter
    def crc_in_vsc_sdp(self, value: bool):
        self.__crc_in_vsc_sdp = value

    @property
    def mode(self) -> PRMode:
        """
        Returns current PR mode.

        Returns:
            object of `PRMode` type
        """
        return self.__mode

    @mode.setter
    def mode(self, value: PRMode):
        self.__mode = value

    @property
    def hpd_irq(self) -> bool:
        """
        Returns current state of HPD_IRQ with Adaptive-Sync SDP missing (PR).

        Returns:
            object of `bool` type
        """
        return self.__hpd_irq

    @hpd_irq.setter
    def hpd_irq(self, value: bool):
        self.__hpd_irq = value

    @property
    def hpd_irq_vsc_sdp(self) -> bool:
        """
        Returns current state of IRQ_HPD with VSC SDP uncorrectable error (PR).

        Returns:
            object of `bool` type
        """
        return self.__hpd_irq_vsc_sdp

    @hpd_irq_vsc_sdp.setter
    def hpd_irq_vsc_sdp(self, value: bool):
        self.__hpd_irq_vsc_sdp = value

    @property
    def hpd_irq_rfb(self) -> bool:
        """
        Returns current state of IRQ_HPD with RFB storage error (PR).

        Returns:
            object of `bool` type
        """
        return self.__hpd_irq_rfb

    @hpd_irq_rfb.setter
    def hpd_irq_rfb(self, value: bool):
        self.__hpd_irq_rfb = value

    @property
    def hpd_irq_crc(self) -> bool:
        """
        Returns current state of IRQ_HPD with active frame CRC error.

        Returns:
            object of `bool` type
        """
        return self.__hpd_irq_crc

    @hpd_irq_crc.setter
    def hpd_irq_crc(self, value: bool):
        self.__hpd_irq_crc = value

    @property
    def refresh_rate_unlock(self) -> bool:
        """
        Returns current state of Sink refresh rate unlock granted.

        Returns:
            object of `bool` type
        """
        return self.__refresh_rate_unlock

    @refresh_rate_unlock.setter
    def refresh_rate_unlock(self, value: bool):
        self.__refresh_rate_unlock = value

    @property
    def ext_y_gran(self) -> bool:
        """
        Returns current state of SU extended Y granularity (PSR2 and PR).

        Returns:
            object of `bool` type
        """
        return self.__ext_y_gran

    @ext_y_gran.setter
    def ext_y_gran(self, value: bool):
        self.__ext_y_gran = value

    @property
    def main_link_remain_on(self) -> bool:
        """
        Returns current state of Main-link remains ON during PSR1/PSR2 active states.

        Returns:
            object of `bool` type
        """
        return self.__main_link_remain_on

    @main_link_remain_on.setter
    def main_link_remain_on(self, value: bool):
        self.__main_link_remain_on = value

    @property
    def y_granularity(self) -> YGranularity:
        """
        Returns current value of SU Y granularity.

        Returns:
            object of `YGranularity` type
        """
        return self.__y_granularity

    @y_granularity.setter
    def y_granularity(self, y_granularity: YGranularity):
        self.__y_granularity = y_granularity


class PrSettings:
    """
    Class `PrSettings` contains information about Panel Replay capabilities.
    - Set and get `flags` Flags capabilities.
    - Set and get `regions`. Regions capabilities.
    """

    def __init__(self):
        self.__regions: [Region] = []
        self.__flags: Flags = Flags()

    @property
    def flags(self) -> Flags:
        """
        Returns current Flags caps.

        Returns:
            object of `Flags` type
        """
        return self.__flags

    @flags.setter
    def flags(self, value: Flags):
        self.__flags = value

    @property
    def regions(self) -> List[Region]:
        """
        Returns current Regions caps.

        Returns:
            object of `Region` list type
        """
        return self.__regions

    @regions.setter
    def regions(self, value: List[Region]):
        self.__regions = value
