"""
Functions for taking python objects and redndering them as HTML ready for use by our front-end.

Note that we implement "versioned" functions, here. Each function has a version number associated with it, representing the minimum front-end version that can understand the output of that function. In general, you probably only want to use the latest version of each function, unless you have a specific reason not to (for some reason you can't install the latest front-end, or you have multiple versions of the front-end in use and need to support an older one).
"""

import json
from typing import Any, Literal, Sequence

import html_generators as h
from django.utils.translation import get_language

from ._core import TableManager
from ._sort_specification import ColumnSort, FunctionSort, encode_sort


def render_table_v1_1_0(
    manager: TableManager[Any, Any],
    *,
    # Must be unique on your page; will be used for html element id
    id: str,
    # useful if you've called define_custom_element() multiple times, with different renderers configured
    tag_name: str = "qnc-data-table",
    filter_form_id: str = "",
    api_url: str = ".",
    page_size: int = 25,
    fill_last_page: bool = True,
    default_sort: ColumnSort | FunctionSort | None = None,
    has_selection_actions: bool = False,
    layout_storage: Literal["sessionStorage", "localStorage", None] = "localStorage",
    navigation_storage: Literal["sessionStorage", "localStorage", None] = None,
    selection_storage: Literal["sessionStorage", "localStorage", None] = None,
    sort_storage: Literal["sessionStorage", "localStorage", None] = "localStorage",
):
    """
    Render an HTML element which the front-end will turn into a data table.
    Requires front-end version 1.1.0 or later
    """
    return h.Element(
        tag_name,
        id=id,
        lang=get_language(),  # needed for css "hyphens" property to work
        table_config=json.dumps(
            dict(
                filter_form_id=filter_form_id,
                key_prefix=manager.key_prefix,
                api_url=api_url,
                page_size=page_size,
                page_limit=300,
                table_limit=1000,
                fill_last_page=fill_last_page,
                default_sort=encode_sort(default_sort),
                columns=[
                    dict(
                        key=key,
                        display=str(c.header),
                        help_text=str(c.help_text),
                        enabled=c.enabled,
                        fixed=c.fixed,
                        width=c.width,
                        sortable=c.sort_function is not None,
                        horizontal_alignment=c.horizontal_alignment,
                        data_vertical_alignment=c.data_vertical_alignment,
                    )
                    for key, c in manager.columns.items()
                ],
                allow_selection=has_selection_actions,
                layout_storage=layout_storage,
                navigation_storage=navigation_storage,
                selection_storage=selection_storage,
                sort_storage=sort_storage,
                extra_sort_functions=[
                    dict(
                        key=key,
                        display=sort_function.title,
                        help_text=sort_function.help_text,
                    )
                    for key, sort_function in manager.extra_sort_functions.items()
                ],
            )
        ),
    )


def render_selection_controller_v1_1_0(
    table_id: str,
    selection_action_buttons: Sequence[h.Element],
):
    """
    Render an HTML element which the front-end will turn into a "selection controller" (group of selection action buttons).
    Requires front-end version 1.1.0 or later. Actually, somewhat earlier will work, but we haven't checked how far back.
    """
    return h.Element(
        "qdt-selection-fieldset-controller",
        h.Fieldset(
            h.Legend(),
            h.Div(
                selection_action_buttons,
                style="display: flex; align-items: flex-start; flex-wrap: wrap; column-gap: 0.5em; row-gap: 1em;",
            ),
            style="margin-top: 0.5em;",
        ),
        table_id=table_id,
    )


def render_combined_v1_1_0(
    manager: TableManager[Any, Any],
    *,
    # Must be unique on your page; will be used for html element id
    id: str = "qnc-data-table-1",
    # useful if you've called define_custom_element() multiple times, with different renderers configured
    tag_name: str = "qnc-data-table",
    filter_form_id: str = "",
    api_url: str = ".",
    page_size: int = 25,
    fill_last_page: bool = True,
    default_sort: ColumnSort | FunctionSort | None = None,
    selection_action_buttons: Sequence[h.Element] = (),
    layout_storage: Literal["sessionStorage", "localStorage", None] = "localStorage",
    navigation_storage: Literal["sessionStorage", "localStorage", None] = None,
    selection_storage: Literal["sessionStorage", "localStorage", None] = None,
    sort_storage: Literal["sessionStorage", "localStorage", None] = "localStorage",
):
    """
    Renders both the data table and (if relevant) selection action buttons.
    Requires front-end version 1.1.0 or later
    """
    selection_action_buttons = list(selection_action_buttons)

    return h.Div(
        render_table_v1_1_0(
            manager,
            id=id,
            tag_name=tag_name,
            filter_form_id=filter_form_id,
            api_url=api_url,
            page_size=page_size,
            fill_last_page=fill_last_page,
            default_sort=default_sort,
            has_selection_actions=bool(selection_action_buttons),
            layout_storage=layout_storage,
            navigation_storage=navigation_storage,
            selection_storage=selection_storage,
            sort_storage=sort_storage,
        ),
        bool(selection_action_buttons)
        and render_selection_controller_v1_1_0(
            table_id=id,
            selection_action_buttons=selection_action_buttons,
        ),
    )
