from asgiref.sync import sync_to_async


class PaginationResult:
    def __init__(self, items, total_pages, current_page, has_next, has_prev, total_items):
        self.items = items
        self.total_pages = total_pages
        self.current_page = current_page
        self.has_next = has_next
        self.has_prev = has_prev
        self.total_items = total_items


class PaginatorOutput:
    def __init__(self, instance, joiner='\n', close=True, btn_sizes=2):
        self.instance = instance
        self.joiner = joiner
        self.close = close
        self.btn_sizes = btn_sizes


class Paginator:
    def __init__(self, data, per_page=10, formatter=None, reverse=False):
        self._data = data
        self._per_page = per_page
        self.formatter = formatter
        self.reverse = reverse
        self.total_items = None
        self.last_fetched_page = None
        self.is_memory = isinstance(data, list)
        print(f"is_memory: {self.is_memory}")
        if self.is_memory:
            self.total_items = len(data)


    async def get_total_items(self):
        if self.is_memory:
            return self.total_items
        if self.total_items is None:
            self.total_items = await sync_to_async(self._data.count)()
        return self.total_items

    async def get_items(self, offset, limit):
        sort = -1 if self.reverse else None
        if self.is_memory:
            out=self._data[offset:offset + limit]
            if self.reverse:
                return list(reversed(out))
        return await sync_to_async(lambda: list(self._data[offset:offset + limit:sort]))()

    def set_last_fetched_page(self, **kwargs):
        self.last_fetched_page = PaginationResult(
            items=kwargs.get('items', []),
            total_pages=kwargs.get('total_pages', 0),
            current_page=kwargs.get('current_page', 0),
            has_next=kwargs.get('has_next', False),
            has_prev=kwargs.get('has_prev', False),
            total_items=kwargs.get('total_items', 0)
        )

    async def paginate(self, page: int = 1) -> PaginationResult:
        total_items = await self.get_total_items()
        total_pages = (total_items + self._per_page - 1) // self._per_page
        page = max(1, min(page, total_pages))

        offset = (page - 1) * self._per_page
        items = await self.get_items(offset, self._per_page)

        if self.formatter:
            items = [self.formatter(item) for item in items]

        result = PaginationResult(
            items=items,
            total_pages=total_pages,
            current_page=page,
            has_next=page < total_pages,
            has_prev=page > 1,
            total_items=total_items
        )

        self.last_fetched_page = result
        return result
