from enum import IntEnum
from typing import Union


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

    Tv = 0x0,
    RecDevice1 = 0x1,
    RecDevice2 = 0x2,
    Tuner1 = 0x3,
    PlayDevice1 = 0x4,
    AudioSystem = 0x5,
    Tuner2 = 0x6,
    Tuner3 = 0x7,
    PlayDevice2 = 0x8,
    RecDevice3 = 0x9,
    Tuner4 = 0xA,
    PlayDevice3 = 0xB,
    Reserved1 = 0xC,
    Reserved2 = 0xD,
    SpecificUse = 0xE,
    Broadcast = 0xF,
    Unregistered = Broadcast


class DeviceTypeEnum(IntEnum):
    CECSwitch = 0x1 << 2,
    AudioSystem = 0x1 << 3,
    PlayBack = 0x1 << 4,
    Tuner = 0x1 << 5,
    Rec = 0x1 << 6,
    TV = 0x1 << 7


class CecResetDataCommand(IntEnum):
    """
    Class `PRCommand` contains all possible variants of Panel Replay Command.
    """
    OneFrame = 1,
    AllFrames = 2


class DeviceType:

    def __init__(self, cec_switch: bool = False, audio_system: bool = False, pb_device: bool = False,
                 tuner: bool = False, rec_dev: bool = False, tv: bool = False):
        self.cec_switch = cec_switch
        self.audio_system = audio_system
        self.pb_device = pb_device
        self.tuner = tuner
        self.rec_dev = rec_dev
        self.tv = tv

    def __str__(self) -> str:
        return f"CEC switch - {self.cec_switch}\n" \
               f"Audio System - {self.audio_system}\n" \
               f"PD Device - {self.pb_device}\n" \
               f"Tuner - {self.tuner}\n" \
               f"Rec dev - {self.rec_dev}\n" \
               f"TV - {self.tv}\n"


class CECStatus:

    def __init__(self, buffer_overflowed: bool = False):
        self.buffer_overflowed = buffer_overflowed

    def __str__(self) -> str:
        return f"Buffer Overflowed - {self.buffer_overflowed}\n"


class CECCommand:

    def __init__(self, logical_address: LogicalAddressEnum = LogicalAddressEnum.Tv,
                 phy_address: int = 0x0, op_code: int = 0x0, op_code_param: Union[int, list] = 0x0,
                 device_type: DeviceType = DeviceType(),
                 destination: LogicalAddressEnum = LogicalAddressEnum.Broadcast):
        self.__logical_address = logical_address
        self.__phy_address = phy_address
        self.__op_code = op_code
        self.__op_code_param = op_code_param
        self.__device_type = device_type
        self.__destination = destination

    @property
    def logical_address(self) -> LogicalAddressEnum:
        return self.__logical_address

    @logical_address.setter
    def logical_address(self, address: LogicalAddressEnum):
        self.__logical_address = address

    @property
    def phy_address(self) -> int:
        return self.__phy_address

    @phy_address.setter
    def phy_address(self, address: int):
        self.__phy_address = address

    @property
    def op_code(self) -> int:
        return self.__op_code

    @op_code.setter
    def op_code(self, op_code: int):
        self.__op_code = op_code

    @property
    def op_code_param(self) -> Union[int, list]:
        return self.__op_code_param

    @op_code_param.setter
    def op_code_param(self, param: Union[int, list]):
        self.__op_code_param = param

    @property
    def device_type(self) -> DeviceType:
        return self.__device_type

    @device_type.setter
    def device_type(self, dev_type: DeviceType):
        self.__device_type = dev_type

    @property
    def destination(self) -> LogicalAddressEnum:
        return self.__destination

    @destination.setter
    def destination(self, address: LogicalAddressEnum):
        self.__destination = address
