"""
Orders service s-expression page components.

Each function renders a complete page section (full page, OOB, or pagination)
using shared s-expression components.  Called from route handlers in place
of ``render_template()``.
"""
from __future__ import annotations

import os
from typing import Any

from shared.sx.jinja_bridge import load_service_components
from shared.sx.helpers import (
    call_url,
    sx_call, SxExpr,
)
from shared.infrastructure.urls import market_product_url, cart_url

# Load orders-specific .sx components + handlers at import time
load_service_components(os.path.dirname(os.path.dirname(__file__)),
                        service_name="orders")


# ---------------------------------------------------------------------------
# Header helpers (shared auth + orders-specific) — sx-native
# ---------------------------------------------------------------------------

def _auth_nav_sx(ctx: dict) -> str:
    """Auth section desktop nav items as sx."""
    parts = [
        sx_call("nav-link",
            href=call_url(ctx, "account_url", "/newsletters/"),
            label="newsletters",
            select_colours=ctx.get("select_colours", ""),
        ),
    ]
    account_nav = ctx.get("account_nav")
    if account_nav:
        parts.append(str(account_nav))
    return "(<> " + " ".join(parts) + ")"


def _auth_header_sx(ctx: dict, *, oob: bool = False) -> str:
    """Build the account section header row as sx."""
    return sx_call(
        "menu-row-sx",
        id="auth-row", level=1, colour="sky",
        link_href=call_url(ctx, "account_url", "/"),
        link_label="account", icon="fa-solid fa-user",
        nav=SxExpr(_auth_nav_sx(ctx)),
        child_id="auth-header-child", oob=oob,
    )


def _orders_header_sx(ctx: dict, list_url: str) -> str:
    """Build the orders section header row as sx."""
    return sx_call(
        "menu-row-sx",
        id="orders-row", level=2, colour="sky",
        link_href=list_url, link_label="Orders", icon="fa fa-gbp",
        child_id="orders-header-child",
    )


# ---------------------------------------------------------------------------
# Orders list rendering
# ---------------------------------------------------------------------------

def _status_pill_cls(status: str) -> str:
    """Return Tailwind classes for order status pill."""
    sl = status.lower()
    if sl == "paid":
        return "border-emerald-300 bg-emerald-50 text-emerald-700"
    if sl in ("failed", "cancelled"):
        return "border-rose-300 bg-rose-50 text-rose-700"
    return "border-stone-300 bg-stone-50 text-stone-700"


def _order_row_data(order: Any, detail_url: str) -> dict:
    """Extract display data from an order model object."""
    status = order.status or "pending"
    pill = _status_pill_cls(status)
    created = order.created_at.strftime("%-d %b %Y, %H:%M") if order.created_at else "\u2014"
    total = f"{order.currency or 'GBP'} {order.total_amount or 0:.2f}"
    return dict(
        oid=f"#{order.id}", created=created,
        desc=order.description or "", total=total,
        pill_desktop=f"inline-flex items-center rounded-full border px-2 py-0.5 text-[11px] sm:text-xs {pill}",
        pill_mobile=f"inline-flex items-center rounded-full border px-2 py-0.5 text-[11px] {pill}",
        status=status, url=detail_url,
    )



def _orders_rows_sx(orders: list, page: int, total_pages: int,
                      url_for_fn: Any, qs_fn: Any) -> str:
    """S-expression wire format for order rows (client renders)."""
    from shared.utils import route_prefix
    pfx = route_prefix()

    order_dicts = [
        _order_row_data(o, pfx + url_for_fn("orders.defpage_order_detail", order_id=o.id))
        for o in orders
    ]
    next_url = (pfx + url_for_fn("orders.orders_rows") + qs_fn(page=page + 1)) if page < total_pages else None
    return sx_call("order-rows-from-data",
                   orders=order_dicts, page=page, total_pages=total_pages,
                   next_url=next_url)


def _orders_main_panel_sx(orders: list, rows_sx: str) -> str:
    """Main panel with table or empty state (sx)."""
    if not orders:
        return sx_call("order-empty-state")
    return sx_call("order-table", rows=SxExpr(rows_sx))


def _orders_summary_sx(ctx: dict) -> str:
    """Filter section for orders list (sx)."""
    return sx_call("order-list-header", search_mobile=SxExpr(search_mobile_sx(ctx)))



# ---------------------------------------------------------------------------
# Public API: orders list
# ---------------------------------------------------------------------------





# ---------------------------------------------------------------------------
# Single order detail
# ---------------------------------------------------------------------------

def _order_items_sx(order: Any) -> str:
    """Render order items list as sx."""
    if not order or not order.items:
        return ""
    item_dicts = [
        dict(
            href=market_product_url(item.product_slug),
            product_image=item.product_image,
            product_title=item.product_title or "Unknown product",
            product_id=str(item.product_id),
            quantity=str(item.quantity),
            price=f"{item.currency or order.currency or 'GBP'} {item.unit_price or 0:.2f}",
        )
        for item in order.items
    ]
    return sx_call("order-items-from-data", items=item_dicts)


def _calendar_items_sx(calendar_entries: list | None) -> str:
    """Render calendar bookings for an order as sx."""
    if not calendar_entries:
        return ""
    entry_dicts = []
    for e in calendar_entries:
        st = e.state or ""
        pill = (
            "bg-emerald-100 text-emerald-800" if st == "confirmed"
            else "bg-amber-100 text-amber-800" if st == "provisional"
            else "bg-blue-100 text-blue-800" if st == "ordered"
            else "bg-stone-100 text-stone-700"
        )
        ds = e.start_at.strftime("%-d %b %Y, %H:%M") if e.start_at else ""
        if e.end_at:
            ds += f" \u2013 {e.end_at.strftime('%-d %b %Y, %H:%M')}"
        entry_dicts.append(dict(
            name=e.name,
            pill=f"inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium {pill}",
            status=st.capitalize(), date_str=ds,
            cost=f"\u00a3{e.cost or 0:.2f}",
        ))
    return sx_call("order-calendar-from-data", entries=entry_dicts)


def _order_main_sx(order: Any, calendar_entries: list | None) -> str:
    """Main panel for single order detail (sx)."""
    summary = sx_call(
        "order-summary-card",
        order_id=order.id,
        created_at=order.created_at.strftime("%-d %b %Y, %H:%M") if order.created_at else None,
        description=order.description, status=order.status, currency=order.currency,
        total_amount=f"{order.total_amount:.2f}" if order.total_amount else None,
    )
    items = _order_items_sx(order)
    calendar = _calendar_items_sx(calendar_entries)
    return sx_call(
        "order-detail-panel",
        summary=SxExpr(summary),
        items=SxExpr(items) if items else None,
        calendar=SxExpr(calendar) if calendar else None,
    )


def _order_filter_sx(order: Any, list_url: str, recheck_url: str,
                       pay_url: str, csrf_token: str) -> str:
    """Filter section for single order detail (sx)."""
    created = order.created_at.strftime("%-d %b %Y, %H:%M") if order.created_at else "\u2014"
    status = order.status or "pending"

    pay = ""
    if status != "paid":
        pay = sx_call("order-pay-btn", url=pay_url)

    return sx_call(
        "order-detail-filter",
        info=f"Placed {created} \u00b7 Status: {status}",
        list_url=list_url, recheck_url=recheck_url,
        csrf=csrf_token,
        pay=SxExpr(pay) if pay else None,
    )






# ---------------------------------------------------------------------------
# Public API: Checkout error
# ---------------------------------------------------------------------------

def _checkout_error_filter_sx() -> str:
    return sx_call("checkout-error-header")


def _checkout_error_content_sx(error: str | None, order: Any | None) -> str:
    err_msg = error or "Unexpected error while creating the hosted checkout session."
    order_sx = ""
    if order:
        order_sx = sx_call("checkout-error-order-id", oid=f"#{order.id}")
    back_url = cart_url("/")
    return sx_call(
        "checkout-error-content",
        msg=err_msg,
        order=SxExpr(order_sx) if order_sx else None,
        back_url=back_url,
    )


async def render_checkout_error_page(ctx: dict, error: str | None = None, order: Any | None = None) -> str:
    """Full page: checkout error (sx wire format)."""
    hdr = root_header_sx(ctx)
    inner = _auth_header_sx(ctx)
    hdr = "(<> " + hdr + " " + header_child_sx(inner) + ")"
    filt = _checkout_error_filter_sx()
    content = _checkout_error_content_sx(error, order)
    return full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)


# ---------------------------------------------------------------------------
# Public API: Checkout return
# ---------------------------------------------------------------------------

def _ticket_items_sx(order_tickets: list | None) -> str:
    """Render ticket items for an order as sx."""
    if not order_tickets:
        return ""
    ticket_dicts = []
    for tk in order_tickets:
        st = tk.state or ""
        pill = (
            "bg-emerald-100 text-emerald-800" if st == "confirmed"
            else "bg-amber-100 text-amber-800" if st == "reserved"
            else "bg-blue-100 text-blue-800" if st == "checked_in"
            else "bg-stone-100 text-stone-700"
        )
        ds = tk.entry_start_at.strftime("%-d %b %Y, %H:%M") if tk.entry_start_at else ""
        if tk.entry_end_at:
            ds += f" – {tk.entry_end_at.strftime('%-d %b %Y, %H:%M')}"
        ticket_dicts.append(dict(
            name=tk.entry_name,
            pill=f"inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium {pill}",
            state=st.replace("_", " ").capitalize(),
            type_name=tk.ticket_type_name or None,
            date_str=ds,
            code=tk.code,
            price=f"£{tk.price or 0:.2f}",
        ))
    return sx_call("checkout-return-tickets-from-data", tickets=ticket_dicts)


async def render_checkout_return_page(ctx: dict, order: Any | None,
                                      status: str,
                                      calendar_entries: list | None = None,
                                      order_tickets: list | None = None) -> str:
    """Full page: checkout return after SumUp payment (sx wire format)."""
    filt = sx_call("checkout-return-header", status=status)

    if not order:
        content = sx_call("checkout-return-missing")
    else:
        summary = sx_call(
            "order-summary-card",
            order_id=order.id,
            created_at=order.created_at.strftime("%-d %b %Y, %H:%M") if order.created_at else None,
            description=order.description, status=order.status,
            currency=order.currency,
            total_amount=f"{order.total_amount:.2f}" if order.total_amount else None,
        )
        items = _order_items_sx(order)
        calendar = _calendar_items_sx(calendar_entries)
        tickets = _ticket_items_sx(order_tickets)

        status_msg = ""
        if order.status == "failed":
            status_msg = sx_call("checkout-return-failed", order_id=order.id)
        elif order.status == "paid":
            status_msg = sx_call("checkout-return-paid")

        content = sx_call(
            "checkout-return-content",
            summary=SxExpr(summary),
            items=SxExpr(items) if items else None,
            calendar=SxExpr(calendar) if calendar else None,
            tickets=SxExpr(tickets) if tickets else None,
            status_message=SxExpr(status_msg) if status_msg else None,
        )

    hdr = root_header_sx(ctx)
    inner = _auth_header_sx(ctx)
    hdr = "(<> " + hdr + " " + header_child_sx(inner) + ")"

    return full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
