"""Table layout rendering: header row, data rows, and cells using CSS table display."""

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

# %% auto #0
__all__ = ['SORT_ICON_SIZE', 'render_header_cell', 'render_header_row', 'render_data_cell', 'render_data_row', 'render_slot',
           'render_table_rows', 'render_cell_oob', 'render_row_oob', 'render_visible_cells_oob']

# %% ../../nbs/components/table.ipynb #78dad85f
from typing import Any, Callable, List, Optional, Tuple

from fasthtml.common import Div, Span

from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.typography import font_weight, truncate, font_size
from cjm_fasthtml_tailwind.utilities.borders import border
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import flex_display, items as items_align, gap
from cjm_fasthtml_tailwind.utilities.interactivity import cursor as cursor_tw
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.tables import table_display
from cjm_fasthtml_tailwind.core.base import combine_classes

from cjm_fasthtml_daisyui.utilities.semantic_colors import border_dui, bg_dui, text_dui

from cjm_fasthtml_lucide_icons.factory import lucide_icon

# Design system recipes (V11 icon-size roles)
from cjm_fasthtml_design_system.icons import icons

from cjm_fasthtml_virtual_collection.core.models import (
    ColumnDef, VirtualCollectionConfig, VirtualCollectionState,
    VirtualCollectionUrls, CellRenderContext, RowRenderContext,
)
from ..core.html_ids import VirtualCollectionHtmlIds

# %% ../../nbs/components/table.ipynb #c45cb2ee
SORT_ICON_SIZE = icons.dense_inline  # Tailwind size scale for sort indicator icons (V11 dense_inline role)

def _sort_indicator(column: ColumnDef,  # Column definition
                    state: VirtualCollectionState,  # Collection state (for current sort)
                   ) -> Any:  # Sort icon element or empty string
    """Render sort indicator icon for a sortable header cell."""
    if not column.sortable:
        return ""
    if state.sort_column == column.key:
        icon_name = "arrow-up" if state.sort_ascending else "arrow-down"
        return lucide_icon(icon_name, size=SORT_ICON_SIZE, cls=str(text_dui.primary))
    return lucide_icon("arrow-up-down", size=SORT_ICON_SIZE,
                       cls=str(text_dui.base_content))


def render_header_cell(column: ColumnDef,  # Column definition
                       state: VirtualCollectionState,  # Collection state
                       sort_url: str = "",  # Sort URL (empty = no click-to-sort)
                      ) -> Div:  # Header cell element
    """Render a single table header cell with optional sort indicator."""
    indicator = _sort_indicator(column, state)

    if column.header and indicator:
        # Flex container for text + icon inline
        content = Div(
            Span(column.header),
            indicator,
            cls=combine_classes(flex_display, items_align.center, gap(1)),
        )
    elif column.header:
        content = Span(column.header)
    else:
        content = ""

    cls = combine_classes(
        table_display.cell,
        p.x(2), p.y(1),
        font_weight.semibold, font_size.sm,
        border.b(), border_dui.base_300,
        cursor_tw.pointer if column.sortable and sort_url else None,
        column.header_cls or None,
    )

    # Click-to-sort HTMX attributes
    sort_attrs = {}
    if column.sortable and sort_url:
        sort_attrs = dict(
            hx_post=f"{sort_url}?column={column.key}",
            hx_swap="none",
        )

    return Div(content, cls=cls, **sort_attrs)

# %% ../../nbs/components/table.ipynb #0eabb26b
def render_header_row(config: VirtualCollectionConfig,  # Collection config
                      ids: VirtualCollectionHtmlIds,     # HTML IDs
                      state: VirtualCollectionState = None,  # Collection state (for sort indicators)
                      sort_url: str = "",                # Sort URL (empty = no click-to-sort)
                     ) -> Div:  # Header row element
    """Render the table header row with optional sort indicators."""
    if state is None:
        state = VirtualCollectionState()
    cells = [render_header_cell(col, state, sort_url) for col in config.columns]
    return Div(
        *cells,
        id=ids.header,
        cls=combine_classes(table_display.row, bg_dui.base_200),
    )

# %% ../../nbs/components/table.ipynb #b6c98199
def render_data_cell(item: Any,                    # Data item
                     column: ColumnDef,             # Column definition
                     row_index: int,                # Row index
                     total_items: int,              # Total item count
                     ids: VirtualCollectionHtmlIds,  # HTML IDs
                     render_cell: Callable,          # Consumer cell render callback
                     is_cursor: bool = False,        # Whether row is keyboard cursor
                    ) -> Div:  # Cell element with stable ID
    """Render a single data cell with a stable ID for OOB updates."""
    ctx = CellRenderContext(
        row_index=row_index,
        column=column,
        total_items=total_items,
        is_cursor=is_cursor,
    )
    content = render_cell(item, ctx)
    cls = combine_classes(
        table_display.cell,
        p.x(2), p.y(1),
        border.b(), border_dui.base_200,
        column.cell_cls or None,
    )
    return Div(
        content,
        id=ids.cell_id(row_index, column.key),
        cls=cls,
    )

# %% ../../nbs/components/table.ipynb #9284c20c
def render_data_row(item: Any,                       # Data item
                    row_index: int,                   # Row index in full collection
                    config: VirtualCollectionConfig,   # Collection config
                    state: VirtualCollectionState,     # Collection state
                    ids: VirtualCollectionHtmlIds,     # HTML IDs
                    render_cell: Callable,             # Consumer cell render callback
                    focus_url: str = "",               # URL for click-to-focus (empty = disabled)
                   ) -> Div:  # Row element with stable ID
    """Render a single data row with all cells."""
    is_cursor = (row_index == state.cursor_index)

    cells = [
        render_data_cell(
            item, col, row_index, state.total_items, ids, render_cell, is_cursor
        )
        for col in config.columns
    ]

    row_cls = combine_classes(
        table_display.row,
        bg_dui.base_200.hover,
        cursor_tw.pointer if focus_url else None,
        bg_dui.base_300 if is_cursor else None,
    )

    # Click-to-focus HTMX attributes (skip clicks on interactive children)
    focus_attrs = {}
    if focus_url:
        focus_attrs = dict(
            hx_post=f"{focus_url}?row_index={row_index}",
            hx_swap="none",
            hx_trigger="click[!event.target.closest('input,button,a')]",
        )

    return Div(
        *cells,
        id=ids.row_id(row_index),
        cls=row_cls,
        **focus_attrs,
    )

# %% ../../nbs/components/table.ipynb #v5btl2d4va
def render_slot(
    slot_index: int,                       # Position in viewport (0-based)
    item: Any,                             # Data item
    item_index: int,                       # Row index in full collection
    config: VirtualCollectionConfig,       # Collection config
    state: VirtualCollectionState,         # Collection state
    ids: VirtualCollectionHtmlIds,         # HTML IDs
    render_cell: Callable,                 # Consumer cell render callback
    oob: bool = False,                     # Whether to render as OOB swap
    focus_url: str = "",                   # URL for click-to-focus (empty = disabled)
) -> Div:  # Slot wrapper (display:contents) containing the data row
    """Render a viewport slot wrapping a data row with display:contents."""
    inner_row = render_data_row(
        item, item_index, config, state, ids, render_cell, focus_url=focus_url,
    )
    return Div(
        inner_row,
        id=ids.slot_id(slot_index),
        cls=combine_classes(display_tw.contents),
        hx_swap_oob="innerHTML" if oob else None,
    )

# %% ../../nbs/components/table.ipynb #510630aa
def render_table_rows(items: list,                       # Full item list
                      config: VirtualCollectionConfig,    # Collection config
                      state: VirtualCollectionState,      # Collection state
                      ids: VirtualCollectionHtmlIds,      # HTML IDs
                      render_cell: Callable,              # Consumer cell render callback
                      focus_url: str = "",                # URL for click-to-focus (empty = disabled)
                     ) -> Div:  # Table-row-group container with slot wrappers
    """Render all visible rows in the current window as a table-row-group."""
    from cjm_fasthtml_virtual_collection.core.windowing import compute_window

    render_start, render_end = compute_window(
        state.window_start, state.visible_rows, state.total_items
    )

    slots = [
        render_slot(
            slot_index=slot_idx, item=items[item_idx], item_index=item_idx,
            config=config, state=state, ids=ids, render_cell=render_cell,
            focus_url=focus_url,
        )
        for slot_idx, item_idx in enumerate(range(render_start, render_end))
    ]

    return Div(*slots, id=ids.rows, cls=combine_classes(table_display.row_group))

# %% ../../nbs/components/table.ipynb #gsvxddb56a8
def render_cell_oob(item: Any,                       # Data item
                    column: ColumnDef,                # Column to render
                    row_index: int,                   # Row index
                    total_items: int,                 # Total item count
                    ids: VirtualCollectionHtmlIds,    # HTML IDs
                    render_cell: Callable,            # Consumer cell render callback
                    is_cursor: bool = False,          # Whether row is keyboard cursor
                   ) -> Div:  # Cell element with hx-swap-oob
    """Render a single cell with OOB swap for targeted update."""
    cell = render_data_cell(item, column, row_index, total_items, ids, render_cell, is_cursor)
    cell.attrs["hx-swap-oob"] = "outerHTML"
    return cell


def render_row_oob(item: Any,                       # Data item
                   row_index: int,                   # Row index
                   config: VirtualCollectionConfig,  # Collection config
                   state: VirtualCollectionState,    # Collection state
                   ids: VirtualCollectionHtmlIds,    # HTML IDs
                   render_cell: Callable,            # Consumer cell render callback
                  ) -> Div:  # Row element with hx-swap-oob
    """Render a full row with OOB swap for targeted update."""
    row = render_data_row(item, row_index, config, state, ids, render_cell)
    row.attrs["hx-swap-oob"] = "outerHTML"
    return row


def render_visible_cells_oob(
    column: ColumnDef,                # Column to re-render
    item_indices: List[int],          # Item indices that changed
    items: list,                      # Full items list
    state: VirtualCollectionState,    # Current VC state (for window bounds)
    ids: VirtualCollectionHtmlIds,    # HTML IDs
    render_cell: Callable,            # Consumer cell render callback
) -> Tuple[Div, ...]:                # OOB cell elements for visible items only
    """Batch-render OOB cell updates for specified items within the visible window."""
    from cjm_fasthtml_virtual_collection.core.windowing import compute_window

    render_start, render_end = compute_window(
        state.window_start, state.visible_rows, state.total_items
    )
    oob_cells = []
    for idx in item_indices:
        if render_start <= idx < render_end:
            oob_cells.append(render_cell_oob(
                items[idx], column, idx, state.total_items,
                ids, render_cell, is_cursor=(idx == state.cursor_index),
            ))
    return tuple(oob_cells)
