import warnings
from enum import IntEnum
from typing import Optional, Union, List

from .dut_default_params import *
from .report import generate_html_report, TestAdditionalInfo, TestResult


class TestStatusEnum(IntEnum):
    Idle = 0
    Completed = 1
    InProgress = 2


class TestGroupId(IntEnum):
    """
    Class `TestGroupId` contains all possible variants of Test groups ID.
    """
    UNKNOWN = -1
    AUDIO_TEST = 0x00
    DP_RX_ELECTRICAL = 0x01
    HDMI_RX_ELECTRICAL = 0x02
    DVI_RX_ELECTRICAL = 0x03
    CEC_FUNCTIONAL = 0x05
    DP_RX_CRC = 0x06
    DP_RX_SIMPLE_LT = 0x07
    DP_HDCP_CTS_AUTHENTICATION = 0x0A
    HDMI_RX_CRC = 0x0B
    USB_TYPE_C_ELECTRICAL = 0x0C
    DP_RX_LL_CTS = 0x0E
    DP_TX_LL_CTS = 0x0F
    DP_TX_LL_CTS_DSC = 0x10
    DP_RX_LL_CTS_DSC = 0x11
    DP_2_1_RX_LL_CTS = 0x12
    DP_2_1_TX_LL_CTS = 0x13
    DP_2_1_LTTPR_CTS = 0x14
    DP_HDCP_CTS_1A = 0x26
    DP_HDCP_CTS_1B = 0x27
    DP_HDCP_CTS_2C = 0x28
    DP_HDCP_CTS_3A = 0x29
    DP_HDCP_CTS_3B = 0x2A
    DP_HDCP_CTS_3C = 0x2B
    DP_TX_DISPLAYID = 0x32
    DP_RX_DISPLAYID = 0x33
    HDMI_RX_VRR = 0x34
    HDMI_TX_VRR = 0x35
    DP_TX_ADAPTIVESYNC = 0x36
    DP_RX_ADAPTIVESYNC = 0x37
    DP_2_1_RX_LTTPR_CTS = 0x38
    DP_2_1_TX_LTTPR_CTS = 0x39
    DP_2_1_RX_DSC_CTS = 0x3A
    DP_2_1_TX_DSC_CTS = 0x3B
    DP_2_1_TX_DISPAYID = 0x3C
    DP_2_1_RX_DISPAYID = 0x3D
    DP_2_1_TX_ADAPTIVESYNC = 0x3E
    DP_2_1_RX_ADAPTIVESYNC = 0x3F
    HD_RX_DSC_CTS = 0x40
    HD_TX_DSC_CTS = 0x41
    HD_TX_CONTINUITY = 0x42
    HD_TX_CABLE_CHECK = 0x43
    PIXEL_VIDEO_TEST = 0x3E8
    HDR10_TEST = -2

    @classmethod
    def has_value(cls, value) -> bool:
        return value in iter(cls)


class SubTestResultObject:
    """
    Class `SubTestResultObject` contains information about testing of one test.
    - Set and get Test result `test_result`.
    - Set and get FW logs after testing `fw_logs`.
    - Set and get Configuration information `config_info`.
    - Set and get Error code `error_code`.
    - Set and get Error logs `error_logs`.
    - Set and get Test name `test_name`.
    - Set and get Group name `group_name`.
    """
    def __init__(self, group_name: str, debug: bool):
        self.__test_result = TestResult.Unknown
        self.__fw_logs = ""
        self.__config_info = ""
        self.__error_code = 0
        self.__error_logs = ""
        self.__test_name = ""
        self.__group_name = group_name
        self.__test_delay = 0
        self.__debug = debug
        self.__json_config_info = ""

    @property
    def test_result(self) -> TestResult:
        """
        Returns result after testing.

        Returns:
            object of `TestResult` type
        """
        return self.__test_result

    @test_result.setter
    def test_result(self, test_result: TestResult):
        """
        Set new test result.

        Args:
            test_result (TestResult)
        """
        self.__test_result = test_result

    @property
    def fw_logs(self) -> str:
        """
        Returns FW logs after testing.

        Returns:
            object of str type
        """
        return self.__fw_logs

    @fw_logs.setter
    def fw_logs(self, fw_logs: str):
        """
        Set new test result.

        Args:
            fw_logs (str)
        """
        self.__fw_logs = fw_logs

    @property
    def config_info(self) -> str:
        """
        Returns config info after testing.

        Returns:
            object of str type
        """
        return self.__config_info

    @config_info.setter
    def config_info(self, config_info: str):
        """
        Set new config info.

        Args:
            config_info (str)
        """
        self.__config_info = config_info

    @property
    def error_code(self) -> int:
        """
        Returns error code after testing.

        Returns:
            object of int type
        """
        return self.__error_code

    @error_code.setter
    def error_code(self, error_code: int):
        """
        Set new error code.

        Args:
            error_code (int)
        """
        self.__error_code = error_code

    @property
    def error_logs(self) -> str:
        """
        Returns error logs after testing.

        Returns:
            object of str type
        """
        return self.__error_logs

    @error_logs.setter
    def error_logs(self, error_logs: str):
        """
        Set new error logs.

        Args:
            error_logs (str)
        """
        self.__error_logs = error_logs

    @property
    def test_name(self) -> str:
        """
        Returns test name.

        Returns:
            object of str type
        """
        return self.__test_name

    @test_name.setter
    def test_name(self, test_name: str):
        """
        Set new test name.

        Args:
            test_name (str)
        """
        self.__test_name = test_name

    @property
    def group_name(self) -> str:
        """
        Returns test group name.

        Returns:
            object of str type
        """
        return self.__group_name

    @group_name.setter
    def group_name(self, group_name: str):
        """
        Set new test group name.

        Args:
            group_name (str)
        """
        self.__group_name = group_name

    @property
    def test_delay(self) -> int:
        """
        Returns test delay.

        Returns:
            object of int type
        """
        return self.__test_delay

    @test_delay.setter
    def test_delay(self, test_delay: int):
        """
        Set new test delay.

        Args:
            test_delay (int)
        """
        self.__test_delay = test_delay

    @property
    def debug(self) -> bool:
        """
        Returns debug test state (if you want to use special debug flags, your report will not valid).

        Returns:
            object of bool type
        """
        return self.__debug

    @property
    def json_config_info(self):
        """
        Returns json test config info.

        Returns:
            object of base64 str type
        """
        return self.__json_config_info

    @json_config_info.setter
    def json_config_info(self, json_config_info):
        """
        Set new json config info.

        Args:
            json_config_info: base64 str type
        """
        self.__json_config_info = json_config_info


class TestResultObject:
    """
    Class `TestResultObject` allows get test results.
    - Test result of selected test `test_result`.
    - All test results `all_test_results`.
    """
    def __init__(self, results: Union[SubTestResultObject, List[SubTestResultObject]]):
        if isinstance(results, SubTestResultObject):
            self.__sub_tests = [results]
        else:
            self.__sub_tests = results

    def test_result(self, index: int) -> Optional[SubTestResultObject]:
        """
        Test result of selected test.

        Args:
            index (int)

        Returns:
            object of `SubTestResultObject`|None type
        """
        if index < 0 or index > len(self.__sub_tests) - 1:
            warnings.warn("Incorrect test result object index. Please, select index again.")
            return None
        return self.__sub_tests[index]

    def all_test_results(self) -> list:
        """
        Returns:
            object of list type
        """
        return self.__sub_tests
