from math import ceil
from typing import Any, TypeVar


T = TypeVar('T')


class PaginationResult[T]:
    def __init__(self, items: list[T], total_count: int, page: int, per_page: int):
        self.items = items
        self.total_count = total_count
        self.page = page
        self.per_page = per_page
        self.total_pages = ceil(total_count / per_page) if per_page > 0 else 1
        self.has_prev = page > 1
        self.has_next = page < self.total_pages
        self.prev_page = page - 1 if self.has_prev else None
        self.next_page = page + 1 if self.has_next else None


def paginate_list[T](items: list[T], page: int = 1, per_page: int = 10) -> PaginationResult[T]:
    total_count = len(items)

    start_index = (page - 1) * per_page
    end_index = start_index + per_page

    page_items = items[start_index:end_index]

    return PaginationResult(items=page_items, total_count=total_count, page=page, per_page=per_page)


def get_pagination_info(total_count: int, page: int = 1, per_page: int = 10) -> dict[str, Any]:
    total_pages = ceil(total_count / per_page) if per_page > 0 else 1

    return {
        'total_count': total_count,
        'page': page,
        'per_page': per_page,
        'total_pages': total_pages,
        'has_prev': page > 1,
        'has_next': page < total_pages,
        'prev_page': page - 1 if page > 1 else None,
        'next_page': page + 1 if page < total_pages else None,
        'offset': (page - 1) * per_page,
    }


def get_page_numbers(current_page: int, total_pages: int, max_visible: int = 5) -> list[int]:
    if total_pages <= max_visible:
        return list(range(1, total_pages + 1))

    half_visible = max_visible // 2
    start_page = max(1, current_page - half_visible)
    end_page = min(total_pages, start_page + max_visible - 1)

    if end_page - start_page + 1 < max_visible:
        start_page = max(1, end_page - max_visible + 1)

    return list(range(start_page, end_page + 1))
