# Path: src/pyoffers/utils.py
# class cached_property:
#     def __init__(self, func):
#         self.func = func
# 
#     def __get__(self, obj, cls):
#         if obj is None:  # pragma: no cover
#             return self
#         value = obj.__dict__[self.func.__name__] = self.func(obj)
#         return value
# 
# Path: src/pyoffers/models/core.py
# class Model(metaclass=SelectiveInheritanceMeta):
#     """Abstract model for HasOffers entity."""
# 
#     generic_methods = ()
#     related_object_name = None
#     display_attribute = "id"
# 
#     def __init__(self, manager, **kwargs):
#         self._manager = manager
#         self._data = kwargs
#         self.__dict__.update(kwargs)
# 
#     def __str__(self):
#         return "{}: {}".format(self.__class__.__name__, self._data.get(self.display_attribute, self._data.get("id")))
# 
#     def __repr__(self):
#         return "<%s>" % self
# 
#     def __eq__(self, other):
#         return isinstance(other, self.__class__) and self.id == other.id
# 
#     def as_dict(self):
#         return self._data
# 
#     def _get_related_manager(self, base_manager_class, related_object_name=None):
#         return RelatedManager(
#             api=self._manager.api,
#             base_manager_class=base_manager_class,
#             related_object_name=related_object_name or self.related_object_name,
#             id=self.id,
#         )
# 
#     @generic_method
#     def update(self, **kwargs):
#         return self._manager.update(self.id, **kwargs)
# 
#     @generic_method
#     def delete(self, **kwargs):
#         return self._manager.delete(self.id)
# 
# class ModelManager(metaclass=SelectiveInheritanceMeta):
#     """Proxy for API methods with predefined model.
# 
#     Used to structure API. Every manager works only with single model methods.
# 
#     Class properties:
#         - model: model class
#         - model_aliases: possible names by which HO API might return instances of the model
#         - name: a name by which a manager will be referenced in API instance
#         - generic_methods: what methods to inherit from base ``ModelManager``
#         - forbid_registration: whether the manager shouldn't be accessible in API instance
#     """
# 
#     model = None
#     model_aliases = None
#     name = None
#     generic_methods = ()
#     forbid_registration = False
# 
#     def __init__(self, api):
#         self.api = api
# 
#     def init_instance(self, data):
#         return self.model(manager=self, **data)  # pylint: disable=not-callable
# 
#     def _call(self, method, target=None, **kwargs):
#         if target is None:
#             target = self.target
#         return self.api._call(target, method, **kwargs)
# 
#     @property
#     def target(self):
#         return self.model.__name__
# 
#     @generic_method
#     def create(self, **kwargs):
#         return self._call("create", data=kwargs)
# 
#     @generic_method
#     def update(self, id, **kwargs):
#         return self._call("update", id=id, data=kwargs)
# 
#     @generic_method
#     def delete(self, id):
#         return self.update(id=id, status="deleted")
# 
#     @generic_method
#     def find_by_id(self, id, fields=None, contain=None):
#         assert fields is None or isinstance(fields, (tuple, list)), "Fields should be a tuple or list"
#         return self._call("findById", id=id, fields=fields, contain=contain)
# 
#     @generic_method
#     def find_all(self, sort=(), limit=None, page=None, fields=None, contain=None, **kwargs):
#         assert limit is None or isinstance(limit, int), "Limit should be an integer"
#         assert page is None or isinstance(page, int), "Page should be an integer"
#         assert fields is None or isinstance(fields, (tuple, list)), "Fields should be a tuple or list"
#         return self._call(
#             "findAll",
#             filters=Filter(**kwargs),
#             sort=Sort(sort, self.model.__name__),
#             limit=limit,
#             page=page,
#             fields=fields,
#             contain=contain,
#             single_result=False,
#         )
# 
#     @generic_method
#     def find_all_ids(self, **kwargs):
#         return self._call("findAllIds", filters=Filter(**kwargs), single_result=False, raw=True)


from csv import DictReader
from io import BytesIO, StringIO
from zipfile import ZipFile
from ..utils import cached_property
from .core import Model, ModelManager

    def __str__(self):
        return "{}: {} ({})".format(self.__class__.__name__, self.offer_id, self.transaction_id)


class LogItemManager(ModelManager):
    """Works with exact type of log."""

    def __init__(self, *args, log_type, **kwargs):
        self.log_type = log_type
        super().__init__(*args, **kwargs)

    def _call(self, method, **kwargs):
        return self.api._call("RawLog", method, log_type=self.log_type, **kwargs)

    def list_date_dirs(self):
        response = self._call("listDateDirs", raw=True)
        return [DateDir(manager=self, **kwargs) for kwargs in response["dateDirs"]]

    def list_logs(self, dir_name):
        response = self._call("listLogs", date_dir=dir_name, raw=True)
        return [LogFile(manager=self, **kwargs) for kwargs in response["logFiles"]]

    def get_download_link(self, log_filename):
        return self._call("getDownloadLink", log_filename=log_filename, raw=True)["link"]

    def find_all(self, date):
        return sum([log_file.records for log_file in self.list_logs(date)], [])



# Path: src/pyoffers/utils.py
# class cached_property:
#     def __init__(self, func):
#         self.func = func
# 
#     def __get__(self, obj, cls):
#         if obj is None:  # pragma: no cover
#             return self
#         value = obj.__dict__[self.func.__name__] = self.func(obj)
#         return value
# 
# Path: src/pyoffers/models/core.py
# class Model(metaclass=SelectiveInheritanceMeta):
#     """Abstract model for HasOffers entity."""
# 
#     generic_methods = ()
#     related_object_name = None
#     display_attribute = "id"
# 
#     def __init__(self, manager, **kwargs):
#         self._manager = manager
#         self._data = kwargs
#         self.__dict__.update(kwargs)
# 
#     def __str__(self):
#         return "{}: {}".format(self.__class__.__name__, self._data.get(self.display_attribute, self._data.get("id")))
# 
#     def __repr__(self):
#         return "<%s>" % self
# 
#     def __eq__(self, other):
#         return isinstance(other, self.__class__) and self.id == other.id
# 
#     def as_dict(self):
#         return self._data
# 
#     def _get_related_manager(self, base_manager_class, related_object_name=None):
#         return RelatedManager(
#             api=self._manager.api,
#             base_manager_class=base_manager_class,
#             related_object_name=related_object_name or self.related_object_name,
#             id=self.id,
#         )
# 
#     @generic_method
#     def update(self, **kwargs):
#         return self._manager.update(self.id, **kwargs)
# 
#     @generic_method
#     def delete(self, **kwargs):
#         return self._manager.delete(self.id)
# 
# class ModelManager(metaclass=SelectiveInheritanceMeta):
#     """Proxy for API methods with predefined model.
# 
#     Used to structure API. Every manager works only with single model methods.
# 
#     Class properties:
#         - model: model class
#         - model_aliases: possible names by which HO API might return instances of the model
#         - name: a name by which a manager will be referenced in API instance
#         - generic_methods: what methods to inherit from base ``ModelManager``
#         - forbid_registration: whether the manager shouldn't be accessible in API instance
#     """
# 
#     model = None
#     model_aliases = None
#     name = None
#     generic_methods = ()
#     forbid_registration = False
# 
#     def __init__(self, api):
#         self.api = api
# 
#     def init_instance(self, data):
#         return self.model(manager=self, **data)  # pylint: disable=not-callable
# 
#     def _call(self, method, target=None, **kwargs):
#         if target is None:
#             target = self.target
#         return self.api._call(target, method, **kwargs)
# 
#     @property
#     def target(self):
#         return self.model.__name__
# 
#     @generic_method
#     def create(self, **kwargs):
#         return self._call("create", data=kwargs)
# 
#     @generic_method
#     def update(self, id, **kwargs):
#         return self._call("update", id=id, data=kwargs)
# 
#     @generic_method
#     def delete(self, id):
#         return self.update(id=id, status="deleted")
# 
#     @generic_method
#     def find_by_id(self, id, fields=None, contain=None):
#         assert fields is None or isinstance(fields, (tuple, list)), "Fields should be a tuple or list"
#         return self._call("findById", id=id, fields=fields, contain=contain)
# 
#     @generic_method
#     def find_all(self, sort=(), limit=None, page=None, fields=None, contain=None, **kwargs):
#         assert limit is None or isinstance(limit, int), "Limit should be an integer"
#         assert page is None or isinstance(page, int), "Page should be an integer"
#         assert fields is None or isinstance(fields, (tuple, list)), "Fields should be a tuple or list"
#         return self._call(
#             "findAll",
#             filters=Filter(**kwargs),
#             sort=Sort(sort, self.model.__name__),
#             limit=limit,
#             page=page,
#             fields=fields,
#             contain=contain,
#             single_result=False,
#         )
# 
#     @generic_method
#     def find_all_ids(self, **kwargs):
#         return self._call("findAllIds", filters=Filter(**kwargs), single_result=False, raw=True)


# Path: src/pyoffers/models/raw_log.py
from csv import DictReader
from io import BytesIO, StringIO
from zipfile import ZipFile
from ..utils import cached_property
from .core import Model, ModelManager


    def __str__(self):
        return "{}: {} ({})".format(self.__class__.__name__, self.offer_id, self.transaction_id)


class LogItemManager(ModelManager):
    """Works with exact type of log."""

    def __init__(self, *args, log_type, **kwargs):
        self.log_type = log_type
        super().__init__(*args, **kwargs)

    def _call(self, method, **kwargs):
        return self.api._call("RawLog", method, log_type=self.log_type, **kwargs)

    def list_date_dirs(self):
        response = self._call("listDateDirs", raw=True)
        return [DateDir(manager=self, **kwargs) for kwargs in response["dateDirs"]]

    def list_logs(self, dir_name):
        response = self._call("listLogs", date_dir=dir_name, raw=True)
        return [LogFile(manager=self, **kwargs) for kwargs in response["logFiles"]]

    def get_download_link(self, log_filename):
        return self._call("getDownloadLink", log_filename=log_filename, raw=True)["link"]

    def find_all(self, date):
        return sum([log_file.records for log_file in self.list_logs(date)], [])



class RawLogManager(ModelManager):