"""Pagination utilities and components for the media gallery."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/patterns/pagination.ipynb.

# %% auto #0
__all__ = ['PaginationInfo', 'render_pagination', 'render_pagination_info']

# %% ../../nbs/patterns/pagination.ipynb #c3d4e5f6
from dataclasses import dataclass
from typing import Any, List, Optional

from fasthtml.common import Div, Button, Span

# Tailwind utilities
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import flex_display, items, justify, gap
from cjm_fasthtml_tailwind.core.base import combine_classes

# DaisyUI utilities
from cjm_fasthtml_daisyui.components.actions.button import (
    btn, btn_colors, btn_sizes, btn_styles
)
from cjm_fasthtml_daisyui.components.navigation.pagination import join, join_item
from cjm_fasthtml_daisyui.utilities.semantic_colors import text_dui

# Local imports
from ..core.config import PaginationConfig
from ..core.html_ids import GalleryHtmlIds
from ..core.icons import get_gallery_icon

# %% ../../nbs/patterns/pagination.ipynb #e5f6a7b8
@dataclass
class PaginationInfo:
    """Computed pagination information."""
    total_items: int       # Total number of items
    items_per_page: int    # Items per page
    current_page: int      # Current page (1-indexed)
    
    @property
    def total_pages(self) -> int:  # Total number of pages
        """Calculate total pages."""
        if self.total_items == 0:
            return 1
        return (self.total_items + self.items_per_page - 1) // self.items_per_page
    
    @property
    def has_prev(self) -> bool:  # True if there's a previous page
        """Check if previous page exists."""
        return self.current_page > 1
    
    @property
    def has_next(self) -> bool:  # True if there's a next page
        """Check if next page exists."""
        return self.current_page < self.total_pages
    
    @property
    def start_index(self) -> int:  # 0-based start index for current page
        """Get start index for current page."""
        return (self.current_page - 1) * self.items_per_page
    
    @property
    def end_index(self) -> int:  # 0-based end index (exclusive)
        """Get end index for current page."""
        return min(self.start_index + self.items_per_page, self.total_items)
    
    @property
    def items_on_page(self) -> int:  # Number of items on current page
        """Get number of items on current page."""
        return self.end_index - self.start_index
    
    def get_visible_pages(
        self,
        max_visible: int = 5  # Maximum visible page buttons
    ) -> List[int]:  # List of page numbers to show
        """Get list of page numbers to display."""
        if self.total_pages <= max_visible:
            return list(range(1, self.total_pages + 1))
        
        # Center around current page
        half = max_visible // 2
        start = max(1, self.current_page - half)
        end = min(self.total_pages, start + max_visible - 1)
        
        # Adjust if we're near the end
        if end - start + 1 < max_visible:
            start = max(1, end - max_visible + 1)
        
        return list(range(start, end + 1))

# %% ../../nbs/patterns/pagination.ipynb #h8c9d0e1
def render_pagination(
    info: PaginationInfo,             # Pagination info
    page_url: str,                    # URL for page change handler
    hx_target: Optional[str] = None,  # HTMX target for swap
    max_visible: int = 5,             # Maximum visible page buttons
) -> Any:  # Pagination component
    """Render pagination controls."""
    if info.total_pages <= 1:
        return None  # No pagination needed
    
    buttons = []
    visible_pages = info.get_visible_pages(max_visible)
    
    # First button
    buttons.append(
        _page_button(
            content=get_gallery_icon("first", size=4),
            page=1,
            disabled=not info.has_prev,
            page_url=page_url,
            hx_target=hx_target,
            title="First page"
        )
    )
    
    # Previous button
    buttons.append(
        _page_button(
            content=get_gallery_icon("prev", size=4),
            page=info.current_page - 1,
            disabled=not info.has_prev,
            page_url=page_url,
            hx_target=hx_target,
            title="Previous page"
        )
    )
    
    # Ellipsis before if needed
    if visible_pages[0] > 1:
        buttons.append(
            Button(
                "...",
                cls=combine_classes(btn, btn_sizes.sm, join_item),
                disabled=True
            )
        )
    
    # Page number buttons
    for page in visible_pages:
        is_current = page == info.current_page
        buttons.append(
            _page_button(
                content=str(page),
                page=page,
                is_current=is_current,
                page_url=page_url,
                hx_target=hx_target
            )
        )
    
    # Ellipsis after if needed
    if visible_pages[-1] < info.total_pages:
        buttons.append(
            Button(
                "...",
                cls=combine_classes(btn, btn_sizes.sm, join_item),
                disabled=True
            )
        )
    
    # Next button
    buttons.append(
        _page_button(
            content=get_gallery_icon("next", size=4),
            page=info.current_page + 1,
            disabled=not info.has_next,
            page_url=page_url,
            hx_target=hx_target,
            title="Next page"
        )
    )
    
    # Last button
    buttons.append(
        _page_button(
            content=get_gallery_icon("last", size=4),
            page=info.total_pages,
            disabled=not info.has_next,
            page_url=page_url,
            hx_target=hx_target,
            title="Last page"
        )
    )
    
    return Div(
        Div(*buttons, cls=str(join)),
        id=GalleryHtmlIds.PAGINATION,
        cls=combine_classes(flex_display, justify.center, p(4))
    )

# %% ../../nbs/patterns/pagination.ipynb #i9d0e1f2
def _page_button(
    content: Any,                     # Button content
    page: int,                        # Page number
    page_url: str,                    # URL for page handler
    disabled: bool = False,           # Disable button
    is_current: bool = False,         # Is this the current page
    hx_target: Optional[str] = None,  # HTMX target
    title: Optional[str] = None,      # Button title
) -> Button:  # Page button
    """Render a single page button."""
    btn_cls = combine_classes(
        btn, btn_sizes.sm, join_item,
        btn_colors.primary if is_current else None
    )
    
    attrs = {
        "cls": btn_cls,
        "disabled": disabled or is_current,
    }
    
    if title:
        attrs["title"] = title
        attrs["aria-label"] = title
    
    if not disabled and not is_current:
        attrs["hx_post"] = page_url
        attrs["hx_vals"] = f'{{"page": {page}}}'
        if hx_target:
            attrs["hx_target"] = hx_target
        attrs["hx_swap"] = "outerHTML"
    
    return Button(content, **attrs)

# %% ../../nbs/patterns/pagination.ipynb #l2g3h4i5
def render_pagination_info(
    info: PaginationInfo,  # Pagination info
) -> Any:  # Info text component
    """Render pagination info text."""
    if info.total_items == 0:
        return Span(
            "No items",
            cls=str(text_dui.base_content.opacity(60))
        )
    
    start = info.start_index + 1
    end = info.end_index
    total = info.total_items
    
    return Span(
        f"Showing {start}-{end} of {total} items",
        cls=str(text_dui.base_content.opacity(60))
    )
