# Copyright 2026 Marimo. All rights reserved.
from __future__ import annotations

from typing import Any

from marimo._output import md
from marimo._output.formatting import as_html
from marimo._output.hypertext import ContainerHtml, Html
from marimo._output.rich_help import mddoc
from marimo._plugins.core.web_component import build_stateless_plugin
from marimo._plugins.stateless.flex import vstack


@mddoc
class sidebar(ContainerHtml):
    """An `Html` object that displays content in a sidebar.

    This is a special layout component that will display the content in a sidebar
    layout, rather than below/above the cell.

    This component still needs to be the last expression in the cell,
    in order to display correctly.

    You may use more than one `mo.sidebar` - they will be displayed in the
    order they are called.

    Examples:
        ```python
        mo.sidebar(
            [
                mo.md("# marimo"),
                mo.nav_menu(
                    {
                        "#home": f"{mo.icon('lucide:home')} Home",
                        "#about": f"{mo.icon('lucide:user')} About",
                        "#contact": f"{mo.icon('lucide:phone')} Contact",
                        "Links": {
                            "https://twitter.com/marimo_io": "Twitter",
                            "https://github.com/marimo-team/marimo": "GitHub",
                        },
                    },
                    orientation="vertical",
                ),
            ]
        )
        ```

    Args:
        item (object): The content to display in the sidebar.
        footer (object, optional): The content to display at the bottom of the sidebar.
        width (str, optional): The width of the sidebar when open. Can be any valid CSS width
            value (e.g. "300px", "20rem"). If not provided, defaults to the standard width.
    """

    def __init__(
        self,
        item: object,
        footer: object | None = None,
        *,
        width: str | int | None = None,
    ) -> None:
        # If its a string, wrap in md
        if isinstance(item, str):
            item = md.md(item)
        # If its an array, wrap in vstack
        if isinstance(item, list):
            item = vstack(item)

        # Maybe add footer
        if footer:
            if isinstance(footer, str):
                footer = md.md(footer)
            if isinstance(footer, list):
                footer = vstack(footer)
            item = vstack([item, footer], justify="space-between")

        # Build props
        self._props: dict[str, Any] = {}
        if width is not None:
            # Width must be a string for JSON serialization
            self._props["width"] = str(width)

        # Retain a strong reference to the (processed) item so a wrapped UI
        # element is not garbage collected. The UI element registry holds
        # elements weakly and the slotted HTML only freezes their text, so
        # without this the item -- and, for the list form, the vstack wrapping
        # it -- would be collected and lose interactivity.
        super().__init__([as_html(item)])

    def _build_text(self) -> str:
        return build_stateless_plugin(
            "marimo-sidebar",
            self._props,
            self._children[0].text,
        )

    # Not supported
    def batch(self, *args: Any, **kwargs: Any) -> Any:
        del args, kwargs
        raise TypeError(".batch() is not supported on mo.sidebar")

    def center(self, *args: Any, **kwargs: Any) -> Html:
        del args, kwargs
        raise TypeError(".center() is not supported on mo.sidebar")

    def right(self, *args: Any, **kwargs: Any) -> Html:
        del args, kwargs
        raise TypeError(".right() is not supported on mo.sidebar")

    def left(self, *args: Any, **kwargs: Any) -> Html:
        del args, kwargs
        raise TypeError(".left() is not supported on mo.sidebar")

    def callout(self, *args: Any, **kwargs: Any) -> Html:
        del args, kwargs
        raise TypeError(".callout() is not supported on mo.sidebar")

    def style(self, *args: Any, **kwargs: Any) -> Html:
        del args, kwargs
        raise TypeError(".style() is not supported on mo.sidebar")
