from __future__ import annotations

from quart import (
    g,
    Blueprint,
    abort,
    redirect,
    make_response,
)
from sqlalchemy import select, func, update

from models.market import Product
from ..browse.services.slugs import canonical_html_slug
from ..browse.services.blacklist.product import is_product_blocked
from ..browse.services import db_backend as cb
from ..browse.services import _massage_product
from shared.utils import host_url
from shared.browser.app.redis_cacher import cache_page, clear_cache
from ..cart.services import total
from shared.infrastructure.actions import call_action
from .services.product_operations import massage_full_product
from shared.sx.helpers import sx_response


def register():
    bp = Blueprint("product", __name__, url_prefix="/product/<product_slug>")
    @bp.url_value_preprocessor
    def pull_product_slug(endpoint, values):
      # product_slug is distinct from the app-level "slug"/"page_slug" params,
      # so it won't be popped by the app-level preprocessor in app.py.
      g.product_slug = values.pop("product_slug", None)

    # ─────────────────────────────────────────────────────────────
    # BEFORE REQUEST: Slug or numeric ID resolver
    # ─────────────────────────────────────────────────────────────
    @bp.before_request
    async def resolve_product():
        from quart import request as req

        raw_slug = g.product_slug = getattr(g, "product_slug", None)
        if raw_slug is None:
            return

        is_post = req.method == "POST"

        # 1. If slug is INT → load product by ID
        if raw_slug.isdigit():
            product_id = int(raw_slug)

            product = await cb.db_product_full_id(
                g.s, product_id, user_id=g.user.id if g.user else 0
            )

            if not product:
                abort(404)

            # If product is deleted → SHOW as-is
            if product["deleted_at"]:
                d = product
                g.item_data = {"d": d, "slug": product["slug"], "liked": False}
                return

            # Not deleted → redirect to canonical slug (GET only)
            if not is_post:
                canon = canonical_html_slug(product["slug"])
                return redirect(
                    host_url(url_for("market.browse.product.product_detail", product_slug=canon))
                )

            g.item_data = {"d": product, "slug": product["slug"], "liked": False}
            return

        # 2. Normal slug-based behaviour
        if is_product_blocked(raw_slug):
            abort(404)

        canon = canonical_html_slug(raw_slug)
        if canon != raw_slug and not is_post:
            return redirect(
                host_url(url_for("market.browse.product.product_detail", product_slug=canon))
            )

        # hydrate full product
        d = await cb.db_product_full(
            g.s, canon, user_id=g.user.id if g.user else 0
        )
        if not d:
            abort(404)
        g.item_data = {"d": d, "slug": canon, "liked": d.get("is_liked", False)}

    @bp.context_processor
    def context():
      item_data = getattr(g, "item_data", None)
      
      if item_data:
          return {
              **item_data,
          }
      else:
         return {}  

    # ─────────────────────────────────────────────────────────────
    # RENDER PRODUCT
    # ─────────────────────────────────────────────────────────────
    @bp.get("/")
    @cache_page(tag="browse")
    async def product_detail():
        from shared.browser.app.utils.htmx import is_htmx_request

        from shared.sx.page import get_template_context
        from sxc.pages.renders import render_product_page, render_product_oob

        tctx = await get_template_context()
        item_data = getattr(g, "item_data", {})
        d = item_data.get("d", {})
        tctx["liked_by_current_user"] = item_data.get("liked", False)
        if not is_htmx_request():
            html = await render_product_page(tctx, d)
            return html
        else:
            sx_src = await render_product_oob(tctx, d)
            return sx_response(sx_src)

    @bp.post("/like/toggle/")
    @clear_cache(tag="browse", tag_scope="user")
    async def like_toggle():
      product_slug = g.product_slug

      from sxc.pages.renders import render_like_toggle_button

      if not g.user:
          return sx_response(render_like_toggle_button(product_slug, False), status=403)

      user_id = g.user.id

      result = await call_action("likes", "toggle", payload={
          "user_id": user_id, "target_type": "product", "target_slug": product_slug,
      })
      liked = result["liked"]

      return sx_response(render_like_toggle_button(product_slug, liked))



    @bp.get("/admin/")
    async def admin():
      from shared.browser.app.utils.htmx import is_htmx_request

      from shared.sx.page import get_template_context
      from sxc.pages.renders import render_product_admin_page, render_product_admin_oob

      tctx = await get_template_context()
      item_data = getattr(g, "item_data", {})
      d = item_data.get("d", {})
      tctx["liked_by_current_user"] = item_data.get("liked", False)
      if not is_htmx_request():
          html = await render_product_admin_page(tctx, d)
          return await make_response(html)
      else:
          sx_src = await render_product_admin_oob(tctx, d)
          return sx_response(sx_src)
    
    
    from bp.cart.services.identity import current_cart_identity
    from quart import request, url_for
    from shared.infrastructure.internal_inbox_client import send_internal_activity
    from shared.infrastructure.data_client import fetch_data

    @bp.post("/cart/")
    @clear_cache(tag="browse", tag_scope="user")
    async def cart():
        slug = g.product_slug
        # Load product from local db_market
        product = await g.s.scalar(
            select(Product).where(
                Product.slug == slug,
                Product.deleted_at.is_(None),
            )
        )
        if not product:
            return await make_response("Product not found", 404)

        # Read `count` from body (JSON or form), default to 1
        count = 1
        try:
            if request.is_json:
                data = await request.get_json()
                if data is not None and "count" in data:
                    count = int(data["count"])
            else:
                form = await request.form
                if "count" in form:
                    count = int(form["count"])
        except (ValueError, TypeError):
            count = 1

        ident = current_cart_identity()
        market = getattr(g, "market", None)

        # Build AP activity with denormalized product data
        activity_type = "Add" if count > 0 else "Remove"
        activity = {
            "type": activity_type,
            "object": {
                "type": "rose:CartItem",
                "user_id": ident["user_id"],
                "session_id": ident["session_id"],
                "product_id": product.id,
                "quantity": count,
                "market_place_id": market.id if market else None,
                # Denormalized product data
                "product_title": product.title,
                "product_slug": product.slug,
                "product_image": product.image,
                "product_brand": product.brand,
                "product_regular_price": str(product.regular_price) if product.regular_price is not None else None,
                "product_special_price": str(product.special_price) if product.special_price is not None else None,
                "product_price_currency": product.regular_price_currency,
                # Denormalized marketplace data
                "market_place_name": market.name if market else None,
                "market_place_container_id": market.container_id if market else None,
            },
        }

        await send_internal_activity("cart", activity)

        # Fetch updated cart items from cart service for template rendering
        raw_cart = await fetch_data(
            "cart", "cart-items",
            params={
                k: v for k, v in {
                    "user_id": ident["user_id"],
                    "session_id": ident["session_id"],
                }.items() if v is not None
            },
            required=False,
        ) or []

        # Build minimal cart list for template (product slug + quantity)
        from types import SimpleNamespace
        g.cart = [
            SimpleNamespace(
                product_id=ci["product_id"],
                product=SimpleNamespace(slug=ci["product_slug"]),
                quantity=ci["quantity"],
            )
            for ci in raw_cart
        ]

        ci_ns = next(
            (item for item in g.cart if item.product_id == product.id),
            None,
        )

        # htmx response: OOB-swap mini cart + product buttons
        if request.headers.get("SX-Request") == "true" or request.headers.get("HX-Request") == "true":
            from sxc.pages.renders import render_cart_added_response
            item_data = getattr(g, "item_data", {})
            d = item_data.get("d", {})
            return sx_response(render_cart_added_response(g.cart, ci_ns, d))

        # normal POST: go to cart page
        from shared.infrastructure.urls import cart_url
        return redirect(cart_url("/"))

    

    return bp
