from typing import TypeVar

from UniTAP.libs.lib_tsi.tsi_types import *
from enum import IntEnum
from typing import Type


class HdcpSink1XKeys(IntEnum):
    Unknown = -1
    Unload = H1_SINK_UNLOAD_KEYS
    Test = H1_SINK_LOAD_TEST_KEYS
    Production = H1_SINK_LOAD_PROD_KEYS


class HdcpSink2XKeys(IntEnum):
    Unknown = -1
    Unload = H2_SINK_UNLOAD_KEYS
    Production = H2_SINK_LOAD_PROD_KEYS
    TestR1 = H2_SINK_LOAD_TEST_KEYS_R1
    TestR2 = H2_SINK_LOAD_TEST_KEYS_R2


class HdcpSource1XKeys(IntEnum):
    Unknown = -1
    Unload = H1_SOURCE_UNLOAD_KEYS
    Test = H1_SOURCE_LOAD_TEST_KEYS
    Production = H1_SOURCE_LOAD_PROD_KEYS


class HdcpSource2XKeys(IntEnum):
    Unknown = -1
    Unload = H2_SOURCE_UNLOAD_KEYS
    Production = H2_SOURCE_LOAD_PROD_KEYS
    TestR1 = H2_SOURCE_LOAD_TEST_KEYS_R1
    TestR2 = H2_SOURCE_LOAD_TEST_KEYS_R2


class HdcpMode(IntEnum):
    Unknown = -1
    Mode1_4 = 0
    Mode2_3 = 1


class HdcpHwCaps:

    def __init__(self):
        self.hw_supported = False
        self.production_keys_available = False
        self.test_keys_available = False

    def __str__(self):
        return f"HW Supported: {self.hw_supported}\n" \
               f"Production keys available: {self.production_keys_available}\n" \
               f"Test keys available: {self.test_keys_available}\n"


class HdcpHwSinkCaps(HdcpHwCaps):

    def __init__(self, caps: int, hdcp_mode: HdcpMode):
        super().__init__()
        if hdcp_mode == HdcpMode.Mode1_4:
            self.hw_supported = ((caps >> 16) & 1) != 0
            self.production_keys_available = ((caps >> 17) & 1) != 0
            self.test_keys_available = ((caps >> 18) & 1) != 0
        else:
            self.hw_supported = ((caps >> 8) & 1) != 0
            self.production_keys_available = ((caps >> 9) & 1) != 0
            self.test_keys_available = ((caps >> 10) & 1) != 0


class HdcpHwSourceCaps(HdcpHwCaps):

    def __init__(self, caps: int, hdcp_mode: HdcpMode):
        super().__init__()
        if hdcp_mode == HdcpMode.Mode1_4:
            self.hw_supported = ((caps >> 24) & 1) != 0
            self.production_keys_available = ((caps >> 25) & 1) != 0
            self.test_keys_available = ((caps >> 26) & 1) != 0
        elif hdcp_mode == HdcpMode.Mode2_3:
            self.hw_supported = ((caps >> 8) & 1) != 0
            self.production_keys_available = ((caps >> 9) & 1) != 0
            self.test_keys_available = ((caps >> 10) & 1) != 0


class HdcpStatus:

    class Status1x:

        def __init__(self):
            self.active = False
            self.keys = None
            self.capable = False
            self.authenticated = False

        def __str__(self):
            return f"Active: {bool(self.active)}\n" \
                   f"Keys: {self.keys.name}\n" \
                   f"Capable: {bool(self.capable)}\n" \
                   f"Authenticated: {bool(self.authenticated)}\n"

        def __eq__(self, other):
            return self.active == other.active and \
                   self.keys == other.keys and \
                   self.capable == other.capable and \
                   self.authenticated == other.authenticated

    class StatusRx2x:

        def __init__(self):
            self.active = False
            self.keys = None
            self.capable = False
            self.authenticated = False
            self.km_is_stored = False
            self.content_level = 0

        def __str__(self):
            return f"Active: {bool(self.active)}\n" \
                   f"Keys: {self.keys.name}\n" \
                   f"Capable: {bool(self.capable)}\n" \
                   f"Authenticated: {bool(self.authenticated)}\n" \
                   f"Km is stored: {bool(self.km_is_stored)}\n" \
                   f"Content level: {self.content_level}\n"

        def __eq__(self, other):
            return self.active == other.active and \
                   self.keys == other.keys and \
                   self.capable == other.capable and \
                   self.authenticated == other.authenticated and \
                   self.km_is_stored == other.km_is_stored and \
                   self.content_level == other.content_level

    class StatusTx2x:

        def __init__(self):
            self.active = False
            self.keys = None
            self.capable = False
            self.authenticated = False
            self.km_is_stored = False
            self.content_level = 0
            self.try_authenticate = False
            self.try_encrypt = False

        def __str__(self):
            return f"Active: {bool(self.active)}\n" \
                   f"Keys: {self.keys.name}\n" \
                   f"Capable: {bool(self.capable)}\n" \
                   f"Authenticated: {bool(self.authenticated)}\n" \
                   f"Km is stored: {bool(self.km_is_stored)}\n" \
                   f"Content level: {self.content_level}\n"

        def __eq__(self, other):
            return self.active == other.active and \
                   self.keys == other.keys and \
                   self.capable == other.capable and \
                   self.authenticated == other.authenticated and \
                   self.km_is_stored == other.km_is_stored and \
                   self.content_level == other.content_level and \
                   self.try_authenticate == other.try_authenticate and \
                   self.try_encrypt == other.try_encrypt


class HdcpRxConfig:

    class Config1x:

        def __init__(self):
            self.keys = None
            self.capable = None

    class Config2x:

        def __init__(self):
            self.keys = None
            self.capable = None


class HdcpTxConfig:

    class Config1x:

        def __init__(self):
            self.encryption = None
            self.authenticate = None
            self.keys = None

        def __eq__(self, other):
            return self.encryption == other.encryption and \
                   self.authenticate == other.authenticate and \
                   self.keys == other.keys

    class Config2x:

        def __init__(self):
            self.encryption = None
            self.authenticate = None
            self.keys = None
            self.store_km = None
            self.content_level = None

        def __eq__(self, other):
            return self.encryption == other.encryption and \
                   self.authenticate == other.authenticate and \
                   self.keys == other.keys and \
                   self.store_km == other.store_km and \
                   self.content_level == other.content_level


HdcpRxConfigType = TypeVar("HdcpRxConfigType",
                           HdcpRxConfig.Config1x,
                           HdcpRxConfig.Config2x)

HdcpTxConfigType = TypeVar("HdcpTxConfigType",
                           HdcpTxConfig.Config1x,
                           HdcpTxConfig.Config2x)

HdcpStatusType = TypeVar("HdcpStatusType",
                         HdcpStatus.Status1x,
                         HdcpStatus.StatusRx2x,
                         HdcpStatus.StatusTx2x)
