"""Cart page data service — provides serialized dicts for .sx defpages."""
from __future__ import annotations

from typing import Any


def _serialize_cart_item(item: Any) -> dict:
    from quart import url_for
    from shared.infrastructure.urls import market_product_url

    p = item.product if hasattr(item, "product") else item
    slug = p.slug if hasattr(p, "slug") else ""
    unit_price = getattr(p, "special_price", None) or getattr(p, "regular_price", None)
    currency = getattr(p, "regular_price_currency", "GBP") or "GBP"
    return {
        "slug": slug,
        "title": p.title if hasattr(p, "title") else "",
        "image": p.image if hasattr(p, "image") else None,
        "brand": getattr(p, "brand", None),
        "is_deleted": getattr(item, "is_deleted", False),
        "unit_price": float(unit_price) if unit_price else None,
        "special_price": float(p.special_price) if getattr(p, "special_price", None) else None,
        "regular_price": float(p.regular_price) if getattr(p, "regular_price", None) else None,
        "currency": currency,
        "quantity": item.quantity,
        "product_id": p.id,
        "product_url": market_product_url(slug),
        "qty_url": url_for("cart_global.update_quantity", product_id=p.id),
    }


def _serialize_cal_entry(e: Any) -> dict:
    name = getattr(e, "name", None) or getattr(e, "calendar_name", "")
    start = e.start_at if hasattr(e, "start_at") else ""
    end = getattr(e, "end_at", None)
    cost = getattr(e, "cost", 0) or 0
    end_str = f" \u2013 {end}" if end else ""
    return {
        "name": name,
        "date_str": f"{start}{end_str}",
        "cost": float(cost),
    }


def _serialize_ticket_group(tg: Any) -> dict:
    name = tg.entry_name if hasattr(tg, "entry_name") else tg.get("entry_name", "")
    tt_name = tg.ticket_type_name if hasattr(tg, "ticket_type_name") else tg.get("ticket_type_name", "")
    price = tg.price if hasattr(tg, "price") else tg.get("price", 0)
    quantity = tg.quantity if hasattr(tg, "quantity") else tg.get("quantity", 0)
    line_total = tg.line_total if hasattr(tg, "line_total") else tg.get("line_total", 0)
    entry_id = tg.entry_id if hasattr(tg, "entry_id") else tg.get("entry_id", "")
    tt_id = tg.ticket_type_id if hasattr(tg, "ticket_type_id") else tg.get("ticket_type_id", "")
    start_at = tg.entry_start_at if hasattr(tg, "entry_start_at") else tg.get("entry_start_at")
    end_at = tg.entry_end_at if hasattr(tg, "entry_end_at") else tg.get("entry_end_at")

    date_str = start_at.strftime("%-d %b %Y, %H:%M") if start_at else ""
    if end_at:
        date_str += f" \u2013 {end_at.strftime('%-d %b %Y, %H:%M')}"

    return {
        "entry_name": name,
        "ticket_type_name": tt_name or None,
        "price": float(price or 0),
        "quantity": quantity,
        "line_total": float(line_total or 0),
        "entry_id": entry_id,
        "ticket_type_id": tt_id or None,
        "date_str": date_str,
    }


def _serialize_page_group(grp: Any) -> dict | None:
    post = grp.get("post") if isinstance(grp, dict) else getattr(grp, "post", None)
    cart_items = grp.get("cart_items", []) if isinstance(grp, dict) else getattr(grp, "cart_items", [])
    cal_entries = grp.get("calendar_entries", []) if isinstance(grp, dict) else getattr(grp, "calendar_entries", [])
    tickets = grp.get("tickets", []) if isinstance(grp, dict) else getattr(grp, "tickets", [])

    if not cart_items and not cal_entries and not tickets:
        return None

    post_data = None
    if post:
        post_data = {
            "slug": post.slug if hasattr(post, "slug") else post.get("slug", ""),
            "title": post.title if hasattr(post, "title") else post.get("title", ""),
            "feature_image": post.feature_image if hasattr(post, "feature_image") else post.get("feature_image"),
        }
    market_place = grp.get("market_place") if isinstance(grp, dict) else getattr(grp, "market_place", None)
    mp_data = None
    if market_place:
        mp_data = {"name": market_place.name if hasattr(market_place, "name") else market_place.get("name", "")}

    return {
        "post": post_data,
        "product_count": grp.get("product_count", 0) if isinstance(grp, dict) else getattr(grp, "product_count", 0),
        "calendar_count": grp.get("calendar_count", 0) if isinstance(grp, dict) else getattr(grp, "calendar_count", 0),
        "ticket_count": grp.get("ticket_count", 0) if isinstance(grp, dict) else getattr(grp, "ticket_count", 0),
        "total": float(grp.get("total", 0) if isinstance(grp, dict) else getattr(grp, "total", 0)),
        "market_place": mp_data,
    }


class CartPageService:
    """Service for cart page data, callable via (service "cart-page" ...)."""

    async def overview_data(self, session, **kw):
        from shared.infrastructure.urls import cart_url
        from bp.cart.services import get_cart_grouped_by_page

        page_groups = await get_cart_grouped_by_page(session)
        grp_dicts = [d for d in (_serialize_page_group(grp) for grp in page_groups) if d]
        return {
            "page_groups": grp_dicts,
            "cart_url_base": cart_url(""),
        }

    async def page_cart_data(self, session, **kw):
        from quart import g, request, url_for
        from shared.infrastructure.urls import login_url
        from shared.utils import route_prefix
        from bp.cart.services import total, calendar_total, ticket_total
        from bp.cart.services.page_cart import (
            get_cart_for_page, get_calendar_entries_for_page, get_tickets_for_page,
        )
        from bp.cart.services.ticket_groups import group_tickets

        post = g.page_post
        cart = await get_cart_for_page(session, post.id)
        cal_entries = await get_calendar_entries_for_page(session, post.id)
        page_tickets = await get_tickets_for_page(session, post.id)
        ticket_groups = group_tickets(page_tickets)

        # Build summary data
        product_qty = sum(ci.quantity for ci in cart) if cart else 0
        ticket_qty = len(page_tickets) if page_tickets else 0
        item_count = product_qty + ticket_qty

        product_total = total(cart) or 0
        cal_total = calendar_total(cal_entries) or 0
        tk_total = ticket_total(page_tickets) or 0
        grand = float(product_total) + float(cal_total) + float(tk_total)

        symbol = "\u00a3"
        if cart and hasattr(cart[0], "product") and getattr(cart[0].product, "regular_price_currency", None):
            cur = cart[0].product.regular_price_currency
            symbol = "\u00a3" if cur == "GBP" else cur

        user = getattr(g, "user", None)
        page_post = getattr(g, "page_post", None)

        summary = {
            "item_count": item_count,
            "grand_total": grand,
            "symbol": symbol,
            "is_logged_in": bool(user),
        }

        if user:
            if page_post:
                action = url_for("page_cart.page_checkout")
            else:
                action = url_for("cart_global.checkout")
            summary["checkout_action"] = route_prefix() + action
            summary["user_email"] = user.email
        else:
            summary["login_href"] = login_url(request.url)

        return {
            "cart_items": [_serialize_cart_item(i) for i in cart],
            "cal_entries": [_serialize_cal_entry(e) for e in cal_entries],
            "ticket_groups": [_serialize_ticket_group(tg) for tg in ticket_groups],
            "summary": summary,
        }

    async def admin_data(self, session, **kw):
        """Populate post context for cart-admin layout headers."""
        from quart import g
        from shared.infrastructure.fragments import fetch_fragments

        post = g.page_post
        slug = post.slug if post else ""
        post_id = post.id if post else None

        # Fetch container_nav for post header
        container_nav = ""
        if post_id:
            nav_params = {
                "container_type": "page",
                "container_id": str(post_id),
                "post_slug": slug,
            }
            events_nav, market_nav = await fetch_fragments([
                ("events", "container-nav", nav_params),
                ("market", "container-nav", nav_params),
            ], required=False)
            container_nav = events_nav + market_nav

        return {
            "post": {
                "id": post_id,
                "slug": slug,
                "title": (post.title if post else "")[:160],
                "feature_image": getattr(post, "feature_image", None),
            },
            "container_nav": container_nav,
        }

    async def payments_admin_data(self, session, **kw):
        """Admin data + payments data combined for cart-payments page."""
        admin = await self.admin_data(session)
        payments = await self.payments_data(session)
        return {**admin, **payments}

    async def payments_data(self, session, **kw):
        from shared.sx.page import get_template_context

        ctx = await get_template_context()
        page_config = ctx.get("page_config")
        pc_data = None
        if page_config:
            pc_data = {
                "sumup_api_key": bool(getattr(page_config, "sumup_api_key", None)),
                "sumup_merchant_code": getattr(page_config, "sumup_merchant_code", None) or "",
                "sumup_checkout_prefix": getattr(page_config, "sumup_checkout_prefix", None) or "",
            }
        return {"page_config": pc_data}
