"""Public render functions called from bp routes."""
from __future__ import annotations

from typing import Any

from shared.sx.parser import SxExpr
from shared.sx.helpers import (
    sx_call,
    post_header_sx as _post_header_sx,
    oob_header_sx as _oob_header_sx,
    full_page_sx, oob_page_sx,
)

from .utils import _clear_deeper_oob, _product_detail_sx, _product_meta_sx
from .cards import _product_cards_sx, _market_cards_sx
from .filters import _desktop_filter_sx, _mobile_filter_summary_sx
from .layouts import (
    _market_header_sx, _product_header_sx, _product_admin_header_sx,
    _mobile_nav_panel_sx,
)
from .helpers import _markets_admin_panel_sx


# ---------------------------------------------------------------------------
# Browse page
# ---------------------------------------------------------------------------

def _product_grid(cards_sx: str) -> str:
    """Wrap product cards in a grid as sx."""
    return sx_call("market-product-grid", cards=SxExpr(cards_sx))


async def render_browse_page(ctx: dict) -> str:
    """Full page: product browse with filters."""
    cards = _product_cards_sx(ctx)
    content = _product_grid(cards)

    from shared.sx.helpers import render_to_sx_with_env
    hdr = await render_to_sx_with_env("market-browse-layout-full", {})
    menu = _mobile_nav_panel_sx(ctx)
    filter_sx = await _mobile_filter_summary_sx(ctx)
    aside_sx = await _desktop_filter_sx(ctx)

    return await full_page_sx(ctx, header_rows=hdr, content=content,
                          menu=menu, filter=filter_sx, aside=aside_sx)


async def render_browse_oob(ctx: dict) -> str:
    """OOB response: product browse."""
    cards = _product_cards_sx(ctx)
    content = _product_grid(cards)

    # Layout handles all OOB headers via auto-fetch macros
    oobs = sx_call("market-browse-layout-oob")
    menu = _mobile_nav_panel_sx(ctx)
    filter_sx = await _mobile_filter_summary_sx(ctx)
    aside_sx = await _desktop_filter_sx(ctx)

    return await oob_page_sx(oobs=oobs, content=content,
                         menu=menu, filter=filter_sx, aside=aside_sx)


def render_browse_cards(ctx: dict) -> str:
    """Pagination fragment: product cards -- sx wire format."""
    return _product_cards_sx(ctx)


# ---------------------------------------------------------------------------
# Product detail
# ---------------------------------------------------------------------------

async def render_product_page(ctx: dict, d: dict) -> str:
    """Full page: product detail."""
    content = _product_detail_sx(d, ctx)
    meta = _product_meta_sx(d, ctx)

    from shared.sx.helpers import render_to_sx_with_env
    hdr = await render_to_sx_with_env("market-product-layout-full", {},
        post_header=await _post_header_sx(ctx),
        market_header=_market_header_sx(ctx),
        product_header=_product_header_sx(ctx, d))
    return await full_page_sx(ctx, header_rows=hdr, content=content, meta=meta)


async def render_product_oob(ctx: dict, d: dict) -> str:
    """OOB response: product detail."""
    content = _product_detail_sx(d, ctx)

    oobs = sx_call("market-oob-wrap",
        parts=SxExpr("(<> " + _market_header_sx(ctx, oob=True) + " "
            + await _oob_header_sx("market-header-child", "product-header-child",
                              _product_header_sx(ctx, d)) + " "
            + _clear_deeper_oob("post-row", "post-header-child",
                               "market-row", "market-header-child",
                               "product-row", "product-header-child") + ")"))
    menu = _mobile_nav_panel_sx(ctx)
    return await oob_page_sx(oobs=oobs, content=content, menu=menu)


# ---------------------------------------------------------------------------
# Product admin
# ---------------------------------------------------------------------------

async def render_product_admin_page(ctx: dict, d: dict) -> str:
    """Full page: product admin."""
    content = _product_detail_sx(d, ctx)

    from shared.sx.helpers import render_to_sx_with_env
    hdr = await render_to_sx_with_env("market-product-admin-layout-full", {},
        post_header=await _post_header_sx(ctx),
        market_header=_market_header_sx(ctx),
        product_header=_product_header_sx(ctx, d),
        admin_header=_product_admin_header_sx(ctx, d))
    return await full_page_sx(ctx, header_rows=hdr, content=content)


async def render_product_admin_oob(ctx: dict, d: dict) -> str:
    """OOB response: product admin."""
    content = _product_detail_sx(d, ctx)

    oobs = sx_call("market-oob-wrap",
        parts=SxExpr("(<> " + _product_header_sx(ctx, d, oob=True) + " "
            + await _oob_header_sx("product-header-child", "product-admin-header-child",
                              _product_admin_header_sx(ctx, d)) + " "
            + _clear_deeper_oob("post-row", "post-header-child",
                               "market-row", "market-header-child",
                               "product-row", "product-header-child",
                               "product-admin-row", "product-admin-header-child") + ")"))
    return await oob_page_sx(oobs=oobs, content=content)


# ---------------------------------------------------------------------------
# Market admin list panel
# ---------------------------------------------------------------------------

async def render_markets_admin_list_panel(ctx: dict) -> str:
    """Render the markets admin panel HTML for POST/DELETE response."""
    return await _markets_admin_panel_sx(ctx)


# ---------------------------------------------------------------------------
# Public API: POST handler fragment renderers
# ---------------------------------------------------------------------------

def render_all_markets_cards(markets: list, has_more: bool,
                                     page_info: dict, page: int) -> str:
    """Pagination fragment: all markets cards."""
    from quart import url_for
    from shared.utils import route_prefix

    prefix = route_prefix()
    next_url = prefix + url_for("all_markets.markets_fragment", page=page + 1)
    return _market_cards_sx(markets, page_info, page, has_more, next_url)


def render_page_markets_cards(markets: list, has_more: bool,
                                      page: int, post_slug: str) -> str:
    """Pagination fragment: page-scoped markets cards."""
    from quart import url_for
    from shared.utils import route_prefix

    prefix = route_prefix()
    next_url = prefix + url_for("page_markets.markets_fragment", page=page + 1)
    return _market_cards_sx(markets, {}, page, has_more, next_url,
                               show_page_badge=False, post_slug=post_slug)


def render_like_toggle_button(slug: str, liked: bool, *,
                               like_url: str | None = None,
                               item_type: str = "product") -> str:
    """Render a standalone like toggle button for HTMX POST response."""
    from shared.browser.app.csrf import generate_csrf_token
    from quart import url_for
    from shared.utils import host_url

    csrf = generate_csrf_token()
    if not like_url:
        like_url = host_url(url_for("market.browse.product.like_toggle", product_slug=slug))

    if liked:
        colour = "text-red-600"
        icon = "fa-solid fa-heart"
        label = f"Unlike this {item_type}"
    else:
        colour = "text-stone-300"
        icon = "fa-regular fa-heart"
        label = f"Like this {item_type}"

    return sx_call(
        "market-like-toggle-button",
        colour=colour, action=like_url,
        hx_headers={"X-CSRFToken": csrf},
        label=label, icon_cls=icon,
    )


def render_cart_added_response(cart: list, item: Any, d: dict) -> str:
    """Render the HTMX response after add-to-cart.

    Returns OOB fragments: cart-mini icon + product add/remove buttons + cart item row.
    """
    from shared.browser.app.csrf import generate_csrf_token
    from quart import url_for
    from shared.infrastructure.urls import cart_url as _cart_url

    csrf = generate_csrf_token()
    slug = d.get("slug", "")
    count = sum(getattr(ci, "quantity", 0) for ci in cart)

    # 1. Cart mini icon OOB
    if count > 0:
        cart_href = _cart_url("/")
        cart_mini = sx_call("market-cart-mini-count", href=cart_href, count=str(count))
    else:
        from shared.config import config
        blog_href = config().get("blog_url", "/")
        logo = config().get("logo", "")
        cart_mini = sx_call("market-cart-mini-empty", href=blog_href, logo=logo)

    # 2. Add/remove buttons OOB
    action = url_for("market.browse.product.cart", product_slug=slug)
    quantity = getattr(item, "quantity", 0) if item else 0
    if not quantity:
        cart_add = sx_call(
            "market-cart-add-empty",
            cart_id=f"cart-{slug}", action=action, csrf=csrf,
        )
    else:
        cart_href = _cart_url("/") if callable(_cart_url) else "/"
        cart_add = sx_call(
            "market-cart-add-quantity",
            cart_id=f"cart-{slug}", action=action, csrf=csrf,
            minus_val=str(quantity - 1), plus_val=str(quantity + 1),
            quantity=str(quantity), cart_href=cart_href,
        )
    add_sx = sx_call(
        "market-cart-add-oob",
        id=f"cart-add-{slug}",
        inner=cart_add,
    )

    return "(<> " + cart_mini + " " + add_sx + ")"
