"""
通用分页器
"""

from math import ceil
from typing import Generic, List, Optional, TypeVar

from pydantic import BaseModel, Field

T = TypeVar("T")


class PaginationParams(BaseModel):
    """分页参数"""

    page: int = Field(1, ge=1, description="页码（从 1 开始）")
    page_size: int = Field(20, ge=1, le=100, description="每页数量（最大 100）")

    @property
    def offset(self) -> int:
        """计算偏移量"""
        return (self.page - 1) * self.page_size

    @property
    def limit(self) -> int:
        """返回限制数量"""
        return self.page_size


class PaginationMeta(BaseModel):
    """分页元数据"""

    page: int = Field(..., description="当前页码")
    page_size: int = Field(..., description="每页数量")
    total: int = Field(..., description="总记录数")
    total_pages: int = Field(..., description="总页数")
    has_next: bool = Field(..., description="是否有下一页")
    has_prev: bool = Field(..., description="是否有上一页")

    @classmethod
    def from_params(
        cls,
        params: PaginationParams,
        total: int,
    ) -> "PaginationMeta":
        """从参数和总数创建元数据"""
        total_pages = ceil(total / params.page_size) if total > 0 else 0

        return cls(
            page=params.page,
            page_size=params.page_size,
            total=total,
            total_pages=total_pages,
            has_next=params.page < total_pages,
            has_prev=params.page > 1,
        )


class PaginatedResponse(BaseModel, Generic[T]):
    """分页响应"""

    data: List[T] = Field(..., description="数据列表")
    pagination: PaginationMeta = Field(..., description="分页信息")

    @classmethod
    def create(
        cls,
        data: List[T],
        params: PaginationParams,
        total: int,
    ) -> "PaginatedResponse[T]":
        """创建分页响应"""
        return cls(
            data=data,
            pagination=PaginationMeta.from_params(params, total),
        )


def paginate(
    items: List[T],
    params: PaginationParams,
) -> PaginatedResponse[T]:
    """
    内存分页（适用于 InMemory Repository）

    Args:
        items: 完整列表
        params: 分页参数

    Returns:
        分页响应
    """
    total = len(items)
    start = params.offset
    end = start + params.limit
    page_data = items[start:end]

    return PaginatedResponse.create(
        data=page_data,
        params=params,
        total=total,
    )
