"""Grid layout component for displaying media files as cards."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/components/grid_view.ipynb.

# %% auto #0
__all__ = ['CARD_SIZE_CLASSES', 'render_media_card', 'render_grid_view', 'render_grid_empty_state']

# %% ../../nbs/components/grid_view.ipynb #c3d4e5f6
from typing import Any, List, Optional

from fasthtml.common import Div, Span, Button, Img

# Tailwind utilities
from cjm_fasthtml_tailwind.utilities.sizing import w, h, min_h
from cjm_fasthtml_tailwind.utilities.spacing import p, m
from cjm_fasthtml_tailwind.utilities.typography import (
    font_size, font_weight, truncate, text_align
)
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import (
    flex_display, flex_direction, items, justify, grid_display, grid_cols, gap
)
from cjm_fasthtml_tailwind.utilities.borders import border, rounded
from cjm_fasthtml_tailwind.utilities.interactivity import cursor
from cjm_fasthtml_tailwind.utilities.layout import position, top, right, left, z, object_fit, overflow
from cjm_fasthtml_tailwind.core.base import combine_classes

# DaisyUI utilities
from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui, border_dui
from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
from cjm_fasthtml_daisyui.components.data_display.badge import badge

# Local imports
from cjm_file_discovery.core.models import FileInfo, FileType
from ..core.config import GalleryConfig, CardSize
from ..core.html_ids import GalleryHtmlIds
from cjm_fasthtml_media_gallery.core.icons import (
    get_media_type_icon, MEDIA_TYPE_BADGE_COLORS, get_gallery_icon
)

# %% ../../nbs/components/grid_view.ipynb #e5f6a7b8
CARD_SIZE_CLASSES: dict[CardSize, dict[str, str]] = {
    CardSize.SMALL: {
        "card_height": str(h(32)),
        "icon_size": 6,
        "thumbnail_height": str(h(20)),
    },
    CardSize.MEDIUM: {
        "card_height": str(h(48)),
        "icon_size": 10,
        "thumbnail_height": str(h(32)),
    },
    CardSize.LARGE: {
        "card_height": str(h(64)),
        "icon_size": 14,
        "thumbnail_height": str(h(48)),
    },
}

# %% ../../nbs/components/grid_view.ipynb #g7b8c9d0
def render_media_card(
    file_info: FileInfo,              # File to render
    config: GalleryConfig,            # Gallery configuration
    index: int,                       # Index in the grid
    file_url: Optional[str] = None,   # URL for thumbnail/preview
    is_selected: bool = False,        # Whether file is selected
    preview_url: Optional[str] = None,  # URL for preview action
    select_url: Optional[str] = None,   # URL for selection action
    hx_target: Optional[str] = None,    # HTMX target for swaps
) -> Any:  # Card component
    """Render a media file as a grid card."""
    size_config = CARD_SIZE_CLASSES[config.grid.card_size]
    can_select = config.can_select(file_info)
    
    # Card styling
    card_cls = combine_classes(
        "group relative",
        flex_display, flex_direction.col,
        bg_dui.base_100, border_radius.box,
        border(),
        border_dui.primary if is_selected else border_dui.base_300,
        "hover:border-primary hover:shadow-md",
        "transition-all duration-200",
        cursor.pointer if (config.preview.enable_preview or can_select) else None,
        overflow.hidden
    )
    
    item_id = GalleryHtmlIds.grid_item_id(index)
    
    # Card click action
    card_attrs = {
        "id": item_id,
        "cls": card_cls,
        "data-path": file_info.path,
        "data-index": str(index),
    }
    
    # Primary action: preview or select
    if config.preview.enable_preview and preview_url:
        card_attrs["hx_post"] = preview_url
        card_attrs["hx_vals"] = f'{{"path": "{file_info.path}"}}'
        card_attrs["hx_target"] = f"#{config.preview_modal_id}"
        card_attrs["hx_swap"] = "innerHTML"
    
    # Thumbnail or icon area
    thumbnail_area = _render_thumbnail_area(
        file_info, config, file_url, size_config
    )
    
    # File info area
    info_area = _render_info_area(file_info, config)
    
    # Selection indicator
    selection_indicator = None
    if can_select:
        selection_indicator = _render_selection_indicator(
            is_selected, select_url, file_info.path, hx_target
        )
    
    # Type badge
    type_badge = None
    if config.grid.show_file_type:
        type_badge = _render_type_badge(file_info)
    
    return Div(
        selection_indicator,
        type_badge,
        thumbnail_area,
        info_area,
        **card_attrs
    )

# %% ../../nbs/components/grid_view.ipynb #h8c9d0e1
def _render_thumbnail_area(
    file_info: FileInfo,              # File info
    config: GalleryConfig,            # Gallery config
    file_url: Optional[str],          # URL for image thumbnail
    size_config: dict,                # Size configuration
) -> Any:  # Thumbnail area component
    """Render the thumbnail/icon area of a card."""
    area_cls = combine_classes(
        flex_display, items.center, justify.center,
        w.full, size_config["thumbnail_height"],
        bg_dui.base_200,
        overflow.hidden
    )
    
    # Show thumbnail for images if enabled and URL available
    if (config.grid.show_thumbnails and 
        file_info.file_type == FileType.IMAGE and 
        file_url):
        return Div(
            Img(
                src=file_url,
                alt=file_info.name,
                cls=combine_classes(w.full, h.full, object_fit.cover),
                loading="lazy"
            ),
            cls=area_cls
        )
    
    # Otherwise show file type icon
    return Div(
        get_media_type_icon(file_info.file_type, size=size_config["icon_size"]),
        cls=area_cls
    )

# %% ../../nbs/components/grid_view.ipynb #i9d0e1f2
def _render_info_area(
    file_info: FileInfo,              # File info
    config: GalleryConfig,            # Gallery config
) -> Any:  # Info area component
    """Render the file info area of a card."""
    info_cls = combine_classes(
        flex_display, flex_direction.col,
        p(3), gap(1)
    )
    
    # File name
    name = Span(
        file_info.name,
        cls=combine_classes(
            font_size.sm, font_weight.medium,
            truncate, text_dui.base_content
        ),
        title=file_info.name
    )
    
    # File size
    size = None
    if config.grid.show_file_size and file_info.size_str:
        size = Span(
            file_info.size_str,
            cls=combine_classes(
                font_size.xs, text_dui.base_content.opacity(60)
            )
        )
    
    return Div(name, size, cls=info_cls)

# %% ../../nbs/components/grid_view.ipynb #j0e1f2g3
def _render_selection_indicator(
    is_selected: bool,                # Current selection state
    select_url: Optional[str],        # URL for selection action
    file_path: str,                   # File path for HTMX
    hx_target: Optional[str],         # HTMX target
) -> Any:  # Selection indicator component
    """Render the selection indicator checkbox."""
    indicator_cls = combine_classes(
        position.absolute, top(2), left(2), z(10),
        w(6), h(6), rounded.full,
        flex_display, items.center, justify.center,
        bg_dui.primary if is_selected else bg_dui.base_100,
        border(), border_dui.base_300 if not is_selected else border_dui.primary,
        "opacity-0 group-hover:opacity-100",
        "opacity-100" if is_selected else None,  # Always show if selected
        "transition-opacity duration-200"
    )
    
    attrs = {
        "cls": indicator_cls,
        "onclick": "event.stopPropagation()",  # Don't trigger card click
    }
    
    if select_url:
        attrs["hx_post"] = select_url
        attrs["hx_vals"] = f'{{"path": "{file_path}"}}'
        if hx_target:
            attrs["hx_target"] = hx_target
        attrs["hx_swap"] = "outerHTML"
    
    return Div(
        get_gallery_icon("check", size=4, cls=str(text_dui.primary_content)) if is_selected else None,
        **attrs
    )

# %% ../../nbs/components/grid_view.ipynb #k1f2g3h4
def _render_type_badge(
    file_info: FileInfo,              # File info
) -> Any:  # Type badge component
    """Render the file type badge."""
    badge_color = MEDIA_TYPE_BADGE_COLORS.get(
        file_info.file_type, str(badge)
    )
    
    type_label = file_info.file_type.value.upper()
    if file_info.extension:
        type_label = file_info.extension.upper()
    
    return Span(
        type_label,
        cls=combine_classes(
            position.absolute, top(2), right(2),
            badge, badge_color,
            font_size.xs
        )
    )

# %% ../../nbs/components/grid_view.ipynb #n4i5j6k7
def render_grid_view(
    files: List[FileInfo],            # Files to display
    config: GalleryConfig,            # Gallery configuration
    get_file_url: Optional[callable] = None,  # Function to get file URL
    selected_paths: Optional[List[str]] = None,  # Currently selected paths
    preview_url: Optional[str] = None,  # URL for preview action
    select_url: Optional[str] = None,   # URL for selection action
    hx_target: Optional[str] = None,    # HTMX target for swaps
    start_index: int = 0,               # Starting index for IDs (for pagination)
) -> Any:  # Grid view component
    """Render a grid view of media files."""
    selected_paths = selected_paths or []
    
    # Grid layout
    columns = config.grid.columns
    grid_cls = combine_classes(
        grid_display, grid_cols(columns), gap(4),
        p(4)
    )
    
    # Render cards
    cards = []
    for i, file_info in enumerate(files):
        file_url = get_file_url(file_info.path) if get_file_url else None
        is_selected = file_info.path in selected_paths
        
        card = render_media_card(
            file_info=file_info,
            config=config,
            index=start_index + i,
            file_url=file_url,
            is_selected=is_selected,
            preview_url=preview_url,
            select_url=select_url,
            hx_target=hx_target
        )
        cards.append(card)
    
    return Div(
        *cards,
        id=GalleryHtmlIds.GRID,
        cls=grid_cls
    )

# %% ../../nbs/components/grid_view.ipynb #q7l8m9n0
def render_grid_empty_state(
    message: str = "No media files found",  # Message to display
) -> Any:  # Empty state component
    """Render empty state for grid view."""
    return Div(
        Div(
            get_media_type_icon(FileType.IMAGE, size=16, with_color=False),
            cls=combine_classes(text_dui.base_content.opacity(30), m.b(4))
        ),
        Span(
            message,
            cls=combine_classes(font_size.lg, text_dui.base_content.opacity(60))
        ),
        id=GalleryHtmlIds.GRID,
        cls=combine_classes(
            flex_display, flex_direction.col, items.center, justify.center,
            min_h(64), p(8)
        )
    )
