import abc
import typing

_SESSION_HEADERS_SESSION_ID = 'X-ConioSessionId'
_SESSION_HEADERS_REQUEST_ID = 'X-ConioRequestId'
_SESSION_HEADERS_MFA_TOKEN = 'X-CONIOMFATOKEN'
_SESSION_HEADERS_MFA_CODE = 'X-CONIOMFACODE'


class HeadersWrapper(metaclass=abc.ABCMeta):
    @property
    @abc.abstractmethod
    def headers(self) -> typing.Dict:
        pass

    @headers.setter
    @abc.abstractmethod
    def headers(self, headers: typing.Dict):
        pass

    @property
    @abc.abstractmethod
    def session_id(self) -> typing.Optional[str]:
        pass

    @session_id.setter
    @abc.abstractmethod
    def session_id(self, session_id: str):
        pass

    @property
    @abc.abstractmethod
    def request_id(self) -> typing.Optional[str]:
        pass

    @request_id.setter
    @abc.abstractmethod
    def request_id(self, request_id: str):
        pass

    @property
    @abc.abstractmethod
    def mfa_token(self) -> typing.Optional[str]:
        pass

    @mfa_token.setter
    @abc.abstractmethod
    def mfa_token(self, mfa_token: str):
        pass

    @property
    @abc.abstractmethod
    def mfa_code(self) -> typing.Optional[str]:
        pass

    @mfa_code.setter
    @abc.abstractmethod
    def mfa_code(self, mfa_code: str):
        pass

    @abc.abstractmethod
    def get(self, key, default=None):
        pass


class HeadersWrapperImpl(HeadersWrapper):
    def __init__(self):
        self._headers = {}
        self._uppercase_headers = {}

    def reset(self):
        self._headers = {}
        self._uppercase_headers = {}

    @property
    def headers(self) -> typing.Dict:
        return self._headers

    @headers.setter
    def headers(self, headers: typing.Dict):
        self._headers = headers
        self._uppercase_headers ={k.upper(): v for k, v in headers.items()}

    @property
    def session_id(self) -> typing.Optional[str]:
        return self.get(_SESSION_HEADERS_SESSION_ID)

    @session_id.setter
    def session_id(self, session_id: str):
        self[_SESSION_HEADERS_SESSION_ID] = session_id

    @property
    def request_id(self) -> typing.Optional[str]:
        return self.get(_SESSION_HEADERS_REQUEST_ID)

    @request_id.setter
    def request_id(self, request_id: str):
        self[_SESSION_HEADERS_REQUEST_ID] = request_id

    @property
    def mfa_token(self) -> typing.Optional[str]:
        return self.get(_SESSION_HEADERS_MFA_TOKEN)

    @mfa_token.setter
    def mfa_token(self, mfa_token: str):
        self[_SESSION_HEADERS_MFA_TOKEN] = mfa_token

    @property
    def mfa_code(self) -> typing.Optional[str]:
        return self.get(_SESSION_HEADERS_MFA_CODE)

    @mfa_code.setter
    def mfa_code(self, mfa_code: str):
        self[_SESSION_HEADERS_MFA_CODE] = mfa_code

    def get(self, key, default=None):
        return self._uppercase_headers.get(key.upper(), default)

    def __getitem__(self, item):
        return self._uppercase_headers[item.upper()]

    def __setitem__(self, key, value):
        self._headers[key] = value
        self._uppercase_headers[key.upper()] = value
