import warnings

from UniTAP.libs.lib_tsi.tsi_io import PortIO
from .arc_rx import ArcRx
from .tmds_rx import TmdsRx
from .tmds_tx import TmdsTx
from .status_rx import StatusRx, HdmiModeRx
from .status_tx import StatusTx, HdmiModeTx
from .capabilities import HdmiCapabilities
from .frl_control_tx import FrlControlTx
from .frl_caps_rx import FrlControlRx
from UniTAP.libs.lib_tsi.tsi_types import TSI_HDTX_CAPABILITY_R, TSI_HDRX_CAPABILITY_R
from typing import Optional


class HdmiLinkTx:
    """
    Main class describes HDMI link on Source (TX - transmitter) side. Contains following objects for working with link:
    - TMDS `tmds`.
    - FRL `frl`.
    - Status `status`.
    """
    def __init__(self, port_io: PortIO):
        self.__io = port_io
        self.__tmds = TmdsTx(self.__io)
        self.__status = StatusTx(self.__io)
        self.__frl = FrlControlTx(self.__io)
        self.__caps = HdmiCapabilities(TSI_HDTX_CAPABILITY_R, self.__io)

    @property
    def tmds(self) -> Optional[TmdsTx]:
        """
        Returns object of class `TmdsTx` for working with TMDS.
        None if TMDS does not support on the device.

        Returns:
            object of `TmdsTx`|None type
        """
        if self.__status.hdmi_mode == HdmiModeTx.HDMI_2_1:
            warnings.warn("Current device mode is HDMI 2.1, please, use FRL controls or change HDMI mode.")
            return None
        if not self.__caps.support_tmds:
            warnings.warn("Current device does not support TMDS.")
            return None

        return self.__tmds

    @property
    def frl(self) -> Optional[FrlControlTx]:
        """
        Returns object of class `FrlControlTx` for working with FRL.
        None if FRL does not support on the device.

        Returns:
            object of `FrlControlTx`|None type
        """
        if self.__status.hdmi_mode != HdmiModeTx.HDMI_2_1:
            warnings.warn("Current device mode is not HDMI 2.1, please, use TMDS controls or change HDMI mode.")
            return None
        if not self.__caps.support_frl:
            warnings.warn("Current device does not support FRl.")
            return None

        return self.__frl

    @property
    def status(self) -> StatusTx:
        """
        Returns object of class `StatusTx` for working with link status.

        Returns:
            object of `StatusTx` type
        """
        return self.__status

    def __str__(self):
        __str = f"Status:\n{self.status.__str__()}\n"
        if self.__status.hdmi_mode == HdmiModeTx.HDMI_2_1 and self.__caps.support_frl:
            __str += f"FRL:\n{self.frl.__str__()}\n"
        if self.__status.hdmi_mode != HdmiModeTx.HDMI_2_1 and self.__caps.support_tmds:
            __str += f"TMDS:\n{self.tmds.__str__()}\n"
        return __str


class HdmiLinkRx:
    """
    Main class describes HDMI link on Sink (RX - receiver) side. Contains following objects for working with link:
    - TMDS `tmds`.
    - FRL `frl`.
    - ARC `arc`.
    - Status `status`.
    """
    def __init__(self, port_io: PortIO):
        self.__io = port_io
        self.__tmds = TmdsRx(self.__io)
        self.__status = StatusRx(self.__io)
        self.__frl = FrlControlRx(self.__io)
        self.__arc = ArcRx(self.__io)
        self.__caps = HdmiCapabilities(TSI_HDRX_CAPABILITY_R, self.__io)

    @property
    def tmds(self) -> Optional[TmdsRx]:
        """
        Returns object of class `TmdsRx` for working with TMDS.
        None if TMDS does not support on the device.

        Returns:
            object of `TmdsRx`|None type
        """
        if self.__status.hdmi_mode == HdmiModeTx.HDMI_2_1:
            warnings.warn("Current device mode is HDMI 2.1, please, use FRL controls or change HDMI mode.")
            return None
        if not self.__caps.support_tmds:
            warnings.warn("Current device does not support TMDS.")
            return None

        return self.__tmds

    @property
    def frl(self) -> Optional[FrlControlRx]:
        """
        Returns object of class `FrlControlRx` for working with FRL.
        None if FRL does not support on the device.

        Returns:
            object of `FrlControlRx`|None type
        """
        if self.__status.hdmi_mode != HdmiModeRx.HDMI_2_1:
            warnings.warn("Current device mode is not HDMI 2.1, please, use TMDS controls or change HDMI mode.")
            return None
        if not self.__caps.support_frl:
            warnings.warn("Current device does not support FRl.")
            return None

        return self.__frl

    @property
    def arc(self) -> Optional[ArcRx]:
        """
        Returns object of class `ArcRx` for working with ARC.
        None if ARC does not support on the device.

        Returns:
            object of `ArcRx`|None type
        """
        if not self.__caps.support_arc:
            warnings.warn("Current device does not support ARC.")
            return None

        return self.__arc

    @property
    def status(self) -> StatusRx:
        """
        Returns object of class `StatusRx` for working with link status.

        Returns:
            object of `StatusRx` type
        """
        return self.__status

    def __str__(self):
        __str = f"Status:\n{self.status.__str__()}\n"
        if self.__status.hdmi_mode == HdmiModeTx.HDMI_2_1 and self.__caps.support_frl:
            __str += f"FRL:\n{self.frl.__str__()}\n"
        if self.__status.hdmi_mode != HdmiModeTx.HDMI_2_1 and self.__caps.support_tmds:
            __str += f"TMDS:\n{self.tmds.__str__()}\n"
        if self.__caps.support_arc:
            __str += f"ARC:\n{self.arc.__str__()}\n"
        __str += f"Stream info:\n{self.status.stream(0).__str__()}\n"
        return __str
