from UniTAP.libs.lib_tsi.tsi_io import PortIO
from enum import IntEnum
from UniTAP.libs.lib_tsi.tsi_types import TSI_ARC_CONTROL_W, TSI_HDRX_ARC_STATUS_R
from ctypes import c_uint32


class ArcLoopbackAudioSource(IntEnum):
    """
    Class `ArcLoopbackAudioSource` contains all possible variants of ARC loopback audio source type.
    """
    Unknown = -1
    TPG = 0
    HDMI = 1
    DVI = 2
    DP = 3
    SPDIF = 4


class ArcRx:
    """
    Class `ArcRx` contains information about caps and states of Audio return channel.
    - Support ARC `supported`.
    - Loopback support TGP `loopback_supported_tpg`.
    - Loopback support HDMI `loopback_supported_hdmi`.
    - Loopback support DVI `loopback_supported_dvi`.
    - Loopback support DP `loopback_supported_dp`.
    - Loopback support SPDIF `loopback_supported_spdif`.
    - Current state (enabled/disabled) - `enabled`.
    - Control of ARC Source `arc_source`.
    - Control of single mode `single_mode`.

    """
    def __init__(self, port_io: PortIO):
        self.__io = port_io
        self.__supported = False
        self.__loopback_supported_tpg = False
        self.__loopback_supported_hdmi = False
        self.__loopback_supported_dvi = False
        self.__loopback_supported_dp = False
        self.__loopback_supported_spdif = False
        self.__enabled = False
        self.__arc_source = ArcLoopbackAudioSource.HDMI
        self.__arc_source_value = 2
        self.__single_mode = True

    def __read_arc_status(self) -> int:
        return self.__io.get(TSI_HDRX_ARC_STATUS_R, c_uint32)[1]

    def __write_arc(self, value: int):
        self.__io.set(TSI_ARC_CONTROL_W, value, c_uint32)

    @property
    def supported(self) -> bool:
        self.__supported = (self.__read_arc_status() & 0x1) != 0
        return self.__supported

    @property
    def loopback_supported_tpg(self) -> bool:
        self.__loopback_supported_tpg = ((self.__read_arc_status() >> 1) & 0x1) != 0
        return self.__loopback_supported_tpg

    @property
    def loopback_supported_hdmi(self) -> bool:
        self.__loopback_supported_hdmi = ((self.__read_arc_status() >> 2) & 0x1) != 0
        return self.__loopback_supported_hdmi

    @property
    def loopback_supported_dvi(self) -> bool:
        self.__loopback_supported_dvi = ((self.__read_arc_status() >> 8) & 0x1) != 0
        return self.__loopback_supported_dvi

    @property
    def loopback_supported_dp(self) -> bool:
        self.__loopback_supported_dp = ((self.__read_arc_status() >> 9) & 0x1) != 0
        return self.__loopback_supported_dp

    @property
    def loopback_supported_spdif(self) -> bool:
        self.__loopback_supported_spdif = ((self.__read_arc_status() >> 10) & 0x1) != 0
        return self.__loopback_supported_spdif

    @property
    def enabled(self) -> bool:
        self.__enabled = ((self.__read_arc_status() >> 31) & 0x1) != 0
        return self.__enabled

    @property
    def arc_source(self) -> ArcLoopbackAudioSource:
        return self.__arc_source

    @property
    def single_mode(self) -> bool:
        return self.__single_mode

    @single_mode.setter
    def single_mode(self, single_mode: bool):
        value = self.__arc_source_value | ((1 << 16) if single_mode else 0)
        self.__write_arc(value)
        self.__single_mode = single_mode

    @arc_source.setter
    def arc_source(self, arc_source: ArcLoopbackAudioSource):

        self.__arc_source_value = 0

        if arc_source == ArcLoopbackAudioSource.HDMI:
            self.__arc_source_value |= 2
            self.__arc_source_value |= (0 << 8)
        elif arc_source == ArcLoopbackAudioSource.TPG:
            self.__arc_source_value |= 1
        elif arc_source == ArcLoopbackAudioSource.DVI:
            self.__arc_source_value |= 2
            self.__arc_source_value |= (1 << 8)
        elif arc_source == ArcLoopbackAudioSource.DP:
            self.__arc_source_value |= 2
            self.__arc_source_value |= (2 << 8)
        elif arc_source == ArcLoopbackAudioSource.SPDIF:
            self.__arc_source_value |= 2
            self.__arc_source_value |= (3 << 8)

        value = self.__arc_source_value | ((1 << 16) if self.__single_mode else 0)
        self.__write_arc(value)
        self.__arc_source = arc_source

    def __str__(self):
        return f"Audio return channel supported: {self.supported}\n" \
               f"Loopback supported TPG: {self.loopback_supported_tpg}\n" \
               f"Loopback supported HDMI: {self.loopback_supported_hdmi}\n" \
               f"Loopback supported DVI: {self.loopback_supported_dvi}\n" \
               f"Loopback supported DP: {self.loopback_supported_dp}\n" \
               f"Loopback supported SPDIF: {self.loopback_supported_spdif}\n" \
               f"Enabled: {self.enabled}\n" \
               f"ARC Source: {self.arc_source.name}\n" \
               f"Single mode: {self.single_mode}\n"
