import json
import base64
from enum import IntEnum
from typing import Union


class CMTFormat(IntEnum):
    RGB_LEGACY = 0
    XVYCC_422_BT601 = 1
    XVYCC_444_BT601 = 2
    RGB_WIDE_FIXED = 3
    RGB_CEA = 4
    YCBCR_422_BT601 = 5
    YCBCR_444_BT601 = 6
    DCI_P3 = 7
    XVYCC_422_BT709 = 9
    XVYCC_444_BT709 = 10
    RGB_WIDE_FLOAT = 11
    RGB_ADOBE = 12
    YCBCR_422_BT709 = 13
    YCBCR_444_BT709 = 14
    COLOR_PROFILE = 15
    Y_ONLY = 16
    RAW = 17


class CMTVSCFormat(IntEnum):
    SRGB = 0x00
    RGB_WIDE_FIXED_VCS = 0x01
    RGB_WIDE_FLOAT_VCS = 0x02
    RGB_ADOBE_V = 0x03
    RGB_DCI_P3 = 0x04
    RGB_CUSTOM_PROFILE = 0x05
    RGB_BT2020 = 0x06

    YCBCR_444_BT601_VCS = 0x10
    YCBCR_444_BT709_VCS = 0x11
    YCBCR_444_XVYCC601 = 0x12
    YCBCR_444_XVYCC709 = 0x13
    YCBCR_444_SYCC601 = 0x14
    YCBCR_444_ADOBE_YCC601 = 0x15
    YCBCR_444_BT2020_YCCBCCRC = 0x16
    YCBCR_444_BT2020_YCBCR = 0x17

    YCBCR_422_BT601_VCS = 0x20
    YCBCR_422_BT709_VCS = 0x21
    YCBCR_422_XVYCC601 = 0x22
    YCBCR_422_XVYCC709 = 0x23
    YCBCR_422_SYCC601 = 0x24
    YCBCR_422_ADOBE_YCC601 = 0x25
    YCBCR_422_BT2020_YCCBCCRC = 0x26
    YCBCR_422_BT2020_YCBCR = 0x27

    YCBCR_420_BT601 = 0x30
    YCBCR_420_BT709 = 0x31
    YCBCR_420_XVYCC601 = 0x32
    YCBCR_420_XVYCC709 = 0x33
    YCBCR_420_SYCC601 = 0x34
    YCBCR_420_ADOBE_YCC601 = 0x35
    YCBCR_420_BT2020_YCCBCCRC = 0x36
    YCBCR_420_BT2020_YCBCR = 0x37

    Y_ONLY_DICOM = 0x40
    RAW_CUSTOM_PROFILE = 0x50

    YCBCR_SIMPLE_422_BT601 = 0x60
    YCBCR_SIMPLE_422_BT709 = 0x61
    YCBCR_SIMPLE_422_XVYCC601 = 0x62
    YCBCR_SIMPLE_422_XVYCC709 = 0x63
    YCBCR_SIMPLE_422_SYCC601 = 0x64
    YCBCR_SIMPLE_422_ADOBE_YCC601 = 0x65
    YCBCR_SIMPLE_422_BT2020_YCCBCCRC = 0x66
    YCBCR_SIMPLE_422_BT2020_YCBCR = 0x67


class CMTBitDepth(IntEnum):
    BPC_6 = 0
    BPC_8 = 1
    BPC_10 = 2
    BPC_12 = 3
    BPC_16 = 4

    # BPP_RAW_6 = 1
    # BPP_RAW_7 = 2
    # BPP_RAW_8 = 3
    # BPP_RAW_10 = 4
    # BPP_RAW_12 = 5
    # BPP_RAW_14 = 6
    # BPP_RAW_16 = 7


class CMTVSCBitDepth(IntEnum):
    BPC_RGB_6 = 0
    BPC_RGB_8 = 1
    BPC_RGB_10 = 2
    BPC_RGB_12 = 3
    BPC_RGB_16 = 4

    BPC_YCBCR_8 = 1
    BPC_YCBCR_10 = 2
    BPC_YCBCR_12 = 3
    BPC_YCBCR_16 = 4

    # BPP_RAW_6 = 1
    # BPP_RAW_7 = 2
    # BPP_RAW_8 = 3
    # BPP_RAW_10 = 4
    # BPP_RAW_12 = 5
    # BPP_RAW_14 = 6
    # BPP_RAW_16 = 7


def make_cf(color_format: CMTFormat, bpc: CMTBitDepth):
    return (((color_format & 15) << 1) | ((bpc & 7) << 5))


def make_vsc_cf(color_format: CMTVSCFormat, bpc: CMTVSCBitDepth):
    return ((1 << 14) | ((color_format << 16) | ((bpc & 7) << 24)))


class TestReportConfigType(IntEnum):
    Another = -1
    Dp1_4_Source = 0
    Dp2_1_Source = 1
    Dp1_4_Sink = 2
    Dp2_1_Sink = 3
    Dp2_1_Lttpr = 4


class TestResult(IntEnum):
    Unknown = -1
    Passed = 0
    Failed = 1
    Skipped = 2
    Aborted = 3


def contains(params, config_id):
    for item in params:
        if item.config_id_name == config_id:
            return True
    return False


def is_need_to_update_test_configuration(params):
    if contains(params, "TSI_DP14_SRCCTS_TIMEOUT"):
        return TestReportConfigType.Dp1_4_Source
    elif contains(params, "TSI_DP20_SRCCTS_TIMEOUT"):
        return TestReportConfigType.Dp2_1_Source
    elif contains(params, "TSI_DP14_SINKCTS_TIMEOUT"):
        return TestReportConfigType.Dp1_4_Sink
    elif contains(params, "TSI_DP20_SINKCTS_TIMEOUT"):
        return TestReportConfigType.Dp2_1_Sink
    else:
        return TestReportConfigType.Another


def search_bit(mask):
    count = 0
    if mask:
        while not (mask & 1):
            mask >>= 1
            count += 1
    return count


def update_default_value(value, default_value, mask):
    old_value = default_value
    offset = search_bit(mask)
    value = (value << offset) & mask
    old_value &= ~mask
    old_value |= value
    return old_value


def convert_to_cdf_json_base64(params, test_group):
    group_info = str(hex(test_group)).replace("0x", "").zfill(8)
    result_json = {"Header_Type": f"Group_0x{group_info}_Config"}

    for item in params:
        result_json.update({item.config_id_name:
                            f"{int(item.default_value) if isinstance(item.default_value, bool) else item.default_value}"})

    temp = json.dumps(result_json, indent=4)

    sample_string_bytes = temp.encode()
    base64_bytes = base64.b64encode(sample_string_bytes)
    base64_string = base64_bytes.decode()

    return base64_string
