import contextvars
from typing import TypeVar, Type

__all__ = ('DataMixin', 'ContextInstanceMixin')


class DataMixin:
    @property
    def data(self):
        data = getattr(self, '_data', None)
        if data is None:
            data = {}
            setattr(self, '_data', data)
        return data

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

    def __setitem__(self, key, value):
        self.data[key] = value

    def __delitem__(self, key):
        del self.data[key]

    def __contains__(self, key):
        return key in self.data

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


T = TypeVar('T')


class ContextInstanceMixin:
    def __init_subclass__(cls, **kwargs):
        cls.__context_instance = contextvars.ContextVar(f'instance_{cls.__name__}')
        return cls

    @classmethod
    def get_current(cls: Type[T], no_error=True) -> T:
        if no_error:
            return cls.__context_instance.get(None)
        return cls.__context_instance.get()

    @classmethod
    def set_current(cls: Type[T], value: T):
        if not isinstance(value, cls):
            raise TypeError(f'Value should be instance of {cls.__name__!r} not {type(value).__name__!r}')
        cls.__context_instance.set(value)
