#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
#   "nicegui==3.16.0",
# ]
# ///

from nicegui import events
from nicegui import ui

type TableValue = str | int | float
type TableRow = dict[str, TableValue]

STATUS_COLORS = {
    "Ready": "positive",
    "Low": "warning",
    "Backorder": "negative",
}

COLUMNS = [
    {
        "name": "actions",
        "label": "Actions",
        "required": True,
        "align": "center",
    },
    {
        "name": "name",
        "label": "Product",
        "field": "name",
        "required": True,
        "sortable": True,
        "align": "left",
        "headerClasses": "bg-grey-2 text-grey-9 font-bold",
        "classes": "font-medium",
        "headerStyle": "width: 40%; min-width: 12rem",
        "style": "width: 40%; min-width: 12rem",
    },
    {
        "name": "category",
        "label": "Category",
        "field": "category",
        "sortable": True,
        "align": "left",
        "headerStyle": "width: 9rem",
        "style": "width: 9rem",
    },
    {
        "name": "stock",
        "label": "In stock",
        "field": "stock",
        "sortable": True,
        "align": "right",
        "headerStyle": "width: 7rem",
        "style": "width: 7rem",
        ":classes": "row => row.stock < 10 ? 'text-negative font-bold' : ''",
        ":format": "value => value == null ? '' : `${value} units`",
    },
    {
        "name": "price",
        "label": "Unit price",
        "field": "price",
        "sortable": True,
        "align": "right",
        "headerStyle": "width: 8rem",
        "style": "width: 8rem",
        ":format": "value => value == null ? '' : `$${value.toFixed(2)}`",
    },
    {
        "name": "status",
        "label": "Status",
        "field": "status",
        "sortable": True,
        "align": "center",
        "headerStyle": "width: 8rem",
        "style": "width: 8rem",
        "colorByValue": STATUS_COLORS,
    },
    {
        "name": "updated_at",
        "label": "Updated",
        "field": "updated_at",
        "sortable": True,
        "align": "left",
        "headerStyle": "width: 13rem",
        "style": "width: 13rem",
        ":sort": "(left, right) => Date.parse(left) - Date.parse(right)",
        ":format": """(() => {
            const formatter = new Intl.DateTimeFormat('en-US', {
                dateStyle: 'medium',
                timeStyle: 'short',
                timeZone: 'UTC',
            });
            return value => {
                if (!value) return '';
                const timestamp = Date.parse(value);
                return Number.isNaN(timestamp) ? 'Invalid date' : formatter.format(timestamp);
            };
        })()""",
    },
]

ROWS: list[TableRow] = [
    {
        "id": 101,
        "name": "Desk lamp",
        "category": "Lighting",
        "stock": 7,
        "price": 42.5,
        "status": "Low",
        "updated_at": "2026-08-31T16:20:00Z",
    },
    {
        "id": 102,
        "name": "Task chair",
        "category": "Seating",
        "stock": 18,
        "price": 289.0,
        "status": "Ready",
        "updated_at": "2026-09-01T08:45:00Z",
    },
    {
        "id": 103,
        "name": "Monitor arm",
        "category": "Hardware",
        "stock": 0,
        "price": 119.95,
        "status": "Backorder",
        "updated_at": "2026-08-29T11:05:00Z",
    },
    {
        "id": 104,
        "name": "Cable tray",
        "category": "Hardware",
        "stock": 34,
        "price": 31.25,
        "status": "Ready",
        "updated_at": "2026-09-01T14:30:00Z",
    },
    {
        "id": 105,
        "name": "Side table",
        "category": "Furniture",
        "stock": 9,
        "price": 164.5,
        "status": "Low",
        "updated_at": "2026-08-30T19:15:00Z",
    },
    {
        "id": 106,
        "name": "Floor light",
        "category": "Lighting",
        "stock": 15,
        "price": 98.0,
        "status": "Ready",
        "updated_at": "2026-09-01T10:10:00Z",
    },
]


def render_table() -> ui.table:
    table = ui.table(
        columns=COLUMNS,
        column_defaults={"headerClasses": "text-grey-8"},
        rows=ROWS,
        row_key="id",
        pagination={
            "sortBy": "stock",
            "descending": True,
            "rowsPerPage": 5,
        },
    ).classes("w-full max-w-5xl")

    (
        table.props(
            # Surface and cell layout.
            "flat bordered separator=horizontal wrap-cells"
        )
        .props(
            # Local sorting and page-size choices; zero means "all rows".
            'binary-state-sort :rows-per-page-options="[5, 10, 0]"'
        )
        .props(
            # Compact cells only below Quasar's medium breakpoint.
            ':dense="Quasar.Screen.lt.md"'
        )
        .props(
            # Distinguish an empty dataset from a filter with no matches.
            'no-data-label="No inventory items" no-results-label="No matching inventory items"'
        )
    )

    with table.add_slot("top-left"), ui.row(align_items="center").classes("gap-2"):
        ui.icon("inventory_2", size="sm", color="primary")
        ui.label("Inventory").classes("text-xl font-medium")
        ui.badge(str(len(ROWS)), color="grey-3", text_color="grey-9")

    with table.add_slot("top-right"):
        ui.input(placeholder="Search inventory").props("dense outlined clearable debounce=250").bind_value_to(
            table,
            "filter",
        )

    with table.add_slot("body-cell-status"), table.cell("status"):
        ui.badge(outline=True).props(':label="props.value" :color="props.col.colorByValue[props.value] ?? \'grey\'"')

    def open_product(event: events.GenericEventArguments) -> None:
        product = next((row for row in table.rows if row[table.row_key] == event.args), None)
        if product is None:
            ui.notify("Product no longer exists", type="negative")
            return
        ui.notify(f"Opening {product['name']}")

    with (
        table.add_slot("body-cell-actions"),
        table.cell("actions"),
        ui.button(icon="open_in_new")
        .props("round flat size='sm'")
        .on(
            "click.stop",
            handler=open_product,
            js_handler="() => emit(props.key)",
        ),
    ):
        ui.tooltip("Open product")

    with table.add_slot("no-data"), ui.row(align_items="center").classes("w-full justify-center gap-2 p-6 text-grey-7"):
        ui.icon("inventory_2", size="2em").props(":name=\"props.filter ? 'filter_alt_off' : 'inventory_2'\"")
        ui.element("span").props(':textContent="props.message"')

    optional_columns = [column for column in table.columns if not column.get("required")]

    def set_visible_columns(names: list[str]) -> None:
        table.props["visible-columns"] = names
        table.update()

    ui.select(
        {column["name"]: column["label"] for column in optional_columns},
        value=[column["name"] for column in optional_columns],
        label="Visible columns",
        multiple=True,
        clearable=True,
        on_change=lambda event: set_visible_columns(event.value),
    ).props("outlined dense options-dense").classes("w-64")

    return table


if __name__ in {"__main__", "__mp_main__"}:
    with ui.column(align_items="center").classes("w-full gap-4 p-4"):
        render_table()

    ui.run(port=8888, reload=True)
