"""Domain components for games / purchases / sessions."""

from typing import Any

from django.template.defaultfilters import floatformat
from django.urls import reverse

from common.components.core import Children, Node, Safe, as_children
from common.components.primitives import (
    A,
    Div,
    Icon,
    Popover,
    PopoverTruncated,
    Span,
)
from games.models import Game, Purchase, Session


def GameLink(
    game_id: int,
    name: str = "",
    children: Children = None,
) -> Node:
    """Link to a game's detail page. Uses children (slot) if provided, otherwise name."""
    from django.urls import reverse

    display = as_children(children) or [name]
    link = reverse("games:view_game", args=[game_id])

    return Span(
        attributes=[("class", "truncate-container")],
        children=[
            A(
                href=link,
                attributes=[
                    ("class", "underline decoration-slate-500 sm:decoration-2"),
                ],
                children=display,
            ),
        ],
    )


_STATUS_COLORS = {
    "u": "bg-gray-500",
    "p": "bg-orange-400",
    "f": "bg-green-500",
    "a": "bg-red-500",
    "r": "bg-purple-500",
}


def GameStatus(
    children: Children = None,
    status: str = "u",
    display: str = "",
    class_: str = "",
) -> Node:
    """Colored status dot with label. Status codes: u/p/f/a/r."""
    children = children or []
    outer_class = (
        f"{'flex' if display == 'flex' else 'inline-flex'} "
        "gap-2 items-center align-middle"
    )
    if class_:
        outer_class += f" {class_}"
    dot_color = _STATUS_COLORS.get(status, _STATUS_COLORS["u"])

    dot = Span(
        attributes=[("class", f"rounded-xl w-3 h-3 {dot_color}")],
        children=["\xa0"],
    )

    return Span(
        attributes=[("class", outer_class)],
        children=[dot] + as_children(children),
    )


def PriceConverted(
    children: Children = None,
) -> Node:
    """Wrap content in a span that indicates the price was converted."""
    children = children or []
    return Span(
        attributes=[
            ("title", "Price is a result of conversion and rounding."),
            ("class", "decoration-dotted underline"),
        ],
        children=as_children(children),
    )


def LinkedPurchase(purchase: Purchase) -> Node:
    link = reverse("games:view_purchase", args=[int(purchase.id)])
    link_content = ""
    popover_content = ""
    game_count = purchase.games.count()
    popover_if_not_truncated = False
    if game_count == 1:
        link_content += purchase.games.first().name
        popover_content = link_content
    if game_count > 1:
        if purchase.name:
            link_content += f"{purchase.name}"
            popover_content += f"<h1>{purchase.name}</h1><br>"
        else:
            link_content += f"{game_count} games"
            popover_if_not_truncated = True
        popover_content += f"""
        <ul class="list-disc list-inside">
            {"".join(f"<li>{game.name}</li>" for game in purchase.games.all())}
        </ul>
        """
    icon = (
        (purchase.platform.icon if purchase.platform else "unspecified")
        if game_count == 1
        else "unspecified"
    )
    if link_content == "":
        raise ValueError("link_content is empty!!")
    a_content = Div(
        [("class", "inline-flex gap-2 items-center")],
        [
            Icon(
                icon,
                [("title", "Multiple")],
            ),
            PopoverTruncated(
                input_string=link_content,
                popover_content=Safe(popover_content),
                popover_if_not_truncated=popover_if_not_truncated,
            ),
        ],
    )
    return A(href=link, children=[a_content])


def NameWithIcon(
    name: str = "",
    game: Game | None = None,
    session: Session | None = None,
    linkify: bool = True,
    emulated: bool = False,
) -> Node:
    _name, platform, final_emulated, create_link, link = _resolve_name_with_icon(
        name, game, session, linkify
    )

    content = Div(
        [("class", "inline-flex gap-2 items-center")],
        [
            Icon(
                platform.icon,
                [("title", platform.name)],
            )
            if platform
            else "",
            Icon("emulated", [("title", "Emulated")]) if final_emulated else "",
            PopoverTruncated(_name),
        ],
    )

    return (
        A(
            href=link,
            children=[content],
        )
        if create_link
        else content
    )


def _resolve_name_with_icon(
    name: str,
    game: Game | None,
    session: Session | None,
    linkify: bool,
) -> tuple[str, Any, bool, bool, str]:
    create_link = False
    link = ""
    platform = None
    final_emulated = False

    if session is not None:
        game = session.game
        platform = game.platform
        final_emulated = session.emulated
        if linkify:
            create_link = True
            link = reverse("games:view_game", args=[int(game.pk)])
    elif game is not None:
        platform = game.platform
        if linkify:
            create_link = True
            link = reverse("games:view_game", args=[int(game.pk)])

    _name = name or (game.name if game else "")

    return _name, platform, final_emulated, create_link, link


def PurchasePrice(purchase) -> Node:
    return Popover(
        popover_content=f"{floatformat(purchase.price)} {purchase.price_currency}",
        wrapped_content=f"{floatformat(purchase.converted_price)} {purchase.converted_currency}",
        wrapped_classes="underline decoration-dotted",
    )


_SELECTOR_MENU_CLASS = (
    "absolute top-[105%] left-0 w-full whitespace-nowrap z-10 text-sm "
    "font-medium bg-gray-800/20 backdrop-blur-lg rounded-md rounded-t-none "
    "border border-gray-200 dark:border-gray-700"
)
_SELECTOR_TOGGLE_CLASS = (
    "relative px-4 py-2 text-sm font-medium bg-white border border-gray-200 "
    "rounded-lg hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 "
    "dark:hover:text-white dark:hover:bg-gray-700 hover:cursor-pointer"
)
_SELECTOR_OPTION_CLASS = (
    "block w-full text-left px-4 py-2 rounded-sm cursor-pointer "
    "hover:bg-gray-700 hover:text-white dark:hover:bg-gray-700 "
    "dark:hover:text-white border-0"
)


def GameStatusSelector(game, game_statuses, csrf_token: str) -> Node:
    """Light-DOM custom element; behavior in ts/elements/game-status-selector.ts."""
    from common.components.core import Element
    from common.components.custom_elements import _GameStatusSelector
    from common.components.primitives import Li, Ul

    options = [
        Li()[
            Element(
                "button",
                [
                    ("type", "button"),
                    ("data-option", ""),
                    ("data-value", str(value)),
                    ("class", _SELECTOR_OPTION_CLASS),
                ],
                GameStatus(status=value, children=[label], display="flex"),
            )
        ]
        for value, label in game_statuses
    ]
    current_label = Span(data_label="")[
        GameStatus(
            status=game.status,
            children=[game.get_status_display()],
            display="flex",
        )
    ]
    toggle = Element(
        "button",
        [("type", "button"), ("data-toggle", ""), ("class", _SELECTOR_TOGGLE_CLASS)],
        Span(class_="flex flex-row gap-4 justify-between items-center")[
            current_label, Icon("arrowdown")
        ],
    )
    menu = Div(data_menu="", hidden=True, class_=_SELECTOR_MENU_CLASS)[Ul()[*options]]
    dropdown = Div(
        data_dropdown="", class_="inline-flex rounded-md shadow-2xs relative"
    )[toggle, menu]
    return _GameStatusSelector(game_id=game.id, status=game.status, csrf=csrf_token)[
        Div(class_="flex gap-2 items-center")[dropdown]
    ]


def SessionDeviceSelector(session, session_devices, csrf_token: str) -> Node:
    """Light-DOM custom element; behavior in ts/elements/session-device-selector.ts."""
    from common.components.core import Element
    from common.components.custom_elements import _SessionDeviceSelector
    from common.components.primitives import Li, Ul

    current_name = session.device.name if session.device else "Unknown"
    options = [
        Li()[
            Element(
                "button",
                [
                    ("type", "button"),
                    ("data-option", ""),
                    ("data-value", str(device.id)),
                    ("class", _SELECTOR_OPTION_CLASS),
                ],
                children=[device.name],
            )
        ]
        for device in session_devices
    ]
    toggle = Element(
        "button",
        [("type", "button"), ("data-toggle", ""), ("class", _SELECTOR_TOGGLE_CLASS)],
        Span(class_="flex flex-row gap-4 justify-between items-center")[
            Span(data_label="")[current_name], Icon("arrowdown")
        ],
    )
    menu = Div(data_menu="", hidden=True, class_=_SELECTOR_MENU_CLASS)[Ul()[*options]]
    dropdown = Div(
        data_dropdown="", class_="inline-flex rounded-md shadow-2xs relative"
    )[toggle, menu]
    return _SessionDeviceSelector(session_id=session.id, csrf=csrf_token)[
        Div(class_="flex gap-2 items-center")[dropdown]
    ]
