"""pagination 单元测试."""

import pytest

from packages.application.common.pagination import (
    PaginatedResponse,
    PaginationMeta,
    PaginationParams,
    paginate,
)

# ── PaginationParams ────────────────────────────────────────────────────────


class TestPaginationParams:
    def test_default_values(self):
        params = PaginationParams()
        assert params.page == 1
        assert params.page_size == 20

    def test_custom_values(self):
        params = PaginationParams(page=3, page_size=50)
        assert params.page == 3
        assert params.page_size == 50

    def test_offset_calculation(self):
        params = PaginationParams(page=1, page_size=20)
        assert params.offset == 0

        params = PaginationParams(page=3, page_size=20)
        assert params.offset == 40

        params = PaginationParams(page=10, page_size=50)
        assert params.offset == 450

    def test_limit_equals_page_size(self):
        params = PaginationParams(page_size=30)
        assert params.limit == 30

    def test_page_must_be_at_least_1(self):
        with pytest.raises(ValueError):
            PaginationParams(page=0)

    def test_page_size_must_be_at_least_1(self):
        with pytest.raises(ValueError):
            PaginationParams(page_size=0)

    def test_page_size_max_100(self):
        with pytest.raises(ValueError):
            PaginationParams(page_size=101)


# ── PaginationMeta ──────────────────────────────────────────────────────────


class TestPaginationMeta:
    def test_from_params_first_page(self):
        params = PaginationParams(page=1, page_size=10)
        meta = PaginationMeta.from_params(params, total=25)
        assert meta.page == 1
        assert meta.page_size == 10
        assert meta.total == 25
        assert meta.total_pages == 3  # ceil(25/10)
        assert meta.has_next is True
        assert meta.has_prev is False

    def test_from_params_last_page(self):
        params = PaginationParams(page=3, page_size=10)
        meta = PaginationMeta.from_params(params, total=25)
        assert meta.page == 3
        assert meta.total_pages == 3
        assert meta.has_next is False
        assert meta.has_prev is True

    def test_from_params_middle_page(self):
        params = PaginationParams(page=2, page_size=10)
        meta = PaginationMeta.from_params(params, total=25)
        assert meta.has_next is True
        assert meta.has_prev is True

    def test_from_params_single_page(self):
        params = PaginationParams(page=1, page_size=20)
        meta = PaginationMeta.from_params(params, total=5)
        assert meta.total_pages == 1
        assert meta.has_next is False
        assert meta.has_prev is False

    def test_from_params_zero_total(self):
        params = PaginationParams(page=1, page_size=20)
        meta = PaginationMeta.from_params(params, total=0)
        assert meta.total == 0
        assert meta.total_pages == 0
        assert meta.has_next is False
        assert meta.has_prev is False

    def test_from_params_exact_page_size(self):
        params = PaginationParams(page=1, page_size=10)
        meta = PaginationMeta.from_params(params, total=10)
        assert meta.total_pages == 1

    def test_from_params_one_extra(self):
        params = PaginationParams(page=1, page_size=10)
        meta = PaginationMeta.from_params(params, total=11)
        assert meta.total_pages == 2


# ── PaginatedResponse ───────────────────────────────────────────────────────


class TestPaginatedResponse:
    def test_create_response(self):
        params = PaginationParams(page=1, page_size=5)
        data = [1, 2, 3, 4, 5]
        response = PaginatedResponse.create(data, params, total=15)
        assert response.data == data
        assert response.pagination.page == 1
        assert response.pagination.total == 15
        assert response.pagination.total_pages == 3


# ── paginate function ───────────────────────────────────────────────────────


class TestPaginate:
    def test_first_page(self):
        items = list(range(30))
        params = PaginationParams(page=1, page_size=10)
        result = paginate(items, params)
        assert result.data == list(range(10))
        assert result.pagination.total == 30
        assert result.pagination.total_pages == 3
        assert result.pagination.has_next is True
        assert result.pagination.has_prev is False

    def test_last_page(self):
        items = list(range(25))
        params = PaginationParams(page=3, page_size=10)
        result = paginate(items, params)
        assert result.data == list(range(20, 25))
        assert len(result.data) == 5
        assert result.pagination.has_next is False
        assert result.pagination.has_prev is True

    def test_single_page(self):
        items = list(range(5))
        params = PaginationParams(page=1, page_size=10)
        result = paginate(items, params)
        assert result.data == items
        assert result.pagination.total_pages == 1

    def test_empty_list(self):
        items = []
        params = PaginationParams(page=1, page_size=10)
        result = paginate(items, params)
        assert result.data == []
        assert result.pagination.total == 0
        assert result.pagination.total_pages == 0

    def test_page_beyond_end(self):
        items = list(range(5))
        params = PaginationParams(page=10, page_size=10)
        result = paginate(items, params)
        assert result.data == []
        assert result.pagination.total == 5

    def test_page_size_larger_than_items(self):
        items = list(range(5))
        params = PaginationParams(page=1, page_size=100)
        result = paginate(items, params)
        assert result.data == items
        assert result.pagination.total_pages == 1

    def test_middle_page(self):
        items = list(range(100))
        params = PaginationParams(page=5, page_size=10)
        result = paginate(items, params)
        assert result.data == list(range(40, 50))
        assert result.pagination.has_next is True
        assert result.pagination.has_prev is True
