"""Cart internal inbox endpoint.

Receives AP-shaped activities from other services via HMAC-authenticated
POST to ``/internal/inbox``. Routes to handlers registered via the
internal inbox dispatch infrastructure.
"""
from __future__ import annotations

import logging
from datetime import datetime, timezone

from quart import Blueprint, g, jsonify, request
from sqlalchemy import select

from shared.infrastructure.internal_inbox import dispatch_internal_activity, register_internal_handler
from shared.infrastructure.internal_inbox_client import INBOX_HEADER
from shared.models.market import CartItem

log = logging.getLogger(__name__)


def register() -> Blueprint:
    bp = Blueprint("inbox", __name__, url_prefix="/internal/inbox")

    @bp.before_request
    async def _require_inbox_header():
        if not request.headers.get(INBOX_HEADER):
            return jsonify({"error": "forbidden"}), 403
        from shared.infrastructure.internal_auth import validate_internal_request
        if not validate_internal_request():
            return jsonify({"error": "forbidden"}), 403

    @bp.post("")
    async def handle_inbox():
        body = await request.get_json()
        if not body:
            return jsonify({"error": "empty body"}), 400
        try:
            result = await dispatch_internal_activity(g.s, body)
            return jsonify(result)
        except ValueError as exc:
            return jsonify({"error": str(exc)}), 400
        except Exception as exc:
            log.exception("Internal inbox dispatch failed")
            return jsonify({"error": str(exc)}), 500

    # --- Handler: Add rose:CartItem ---
    async def _handle_add_cart_item(session, body: dict) -> dict:
        obj = body["object"]
        user_id = obj.get("user_id")
        session_id = obj.get("session_id")
        product_id = obj["product_id"]
        count = obj.get("quantity", 1)
        market_place_id = obj.get("market_place_id")

        # Look for existing cart item
        filters = [
            CartItem.deleted_at.is_(None),
            CartItem.product_id == product_id,
        ]
        if user_id is not None:
            filters.append(CartItem.user_id == user_id)
        else:
            filters.append(CartItem.session_id == session_id)

        existing = await session.scalar(select(CartItem).where(*filters))

        if existing:
            if count > 0:
                existing.quantity = count
            else:
                existing.deleted_at = datetime.now(timezone.utc)
            ci = existing
        else:
            if count <= 0:
                return {"ok": True, "action": "noop"}
            ci = CartItem(
                user_id=user_id,
                session_id=session_id,
                product_id=product_id,
                quantity=count,
                market_place_id=market_place_id,
                # Denormalized product data
                product_title=obj.get("product_title"),
                product_slug=obj.get("product_slug"),
                product_image=obj.get("product_image"),
                product_brand=obj.get("product_brand"),
                product_regular_price=obj.get("product_regular_price"),
                product_special_price=obj.get("product_special_price"),
                product_price_currency=obj.get("product_price_currency"),
                # Denormalized marketplace data
                market_place_name=obj.get("market_place_name"),
                market_place_container_id=obj.get("market_place_container_id"),
            )
            session.add(ci)

        await session.flush()
        return {
            "ok": True,
            "cart_item_id": ci.id,
            "quantity": ci.quantity,
        }

    register_internal_handler("Add", "rose:CartItem", _handle_add_cart_item)

    # --- Handler: Remove rose:CartItem ---
    async def _handle_remove_cart_item(session, body: dict) -> dict:
        obj = body["object"]
        user_id = obj.get("user_id")
        session_id = obj.get("session_id")
        product_id = obj["product_id"]

        filters = [
            CartItem.deleted_at.is_(None),
            CartItem.product_id == product_id,
        ]
        if user_id is not None:
            filters.append(CartItem.user_id == user_id)
        else:
            filters.append(CartItem.session_id == session_id)

        existing = await session.scalar(select(CartItem).where(*filters))
        if existing:
            existing.deleted_at = datetime.now(timezone.utc)
            await session.flush()

        return {"ok": True}

    register_internal_handler("Remove", "rose:CartItem", _handle_remove_cart_item)

    # --- Handler: Update rose:CartItem ---
    async def _handle_update_cart_item(session, body: dict) -> dict:
        obj = body["object"]
        user_id = obj.get("user_id")
        session_id = obj.get("session_id")
        product_id = obj["product_id"]
        quantity = obj.get("quantity", 1)

        filters = [
            CartItem.deleted_at.is_(None),
            CartItem.product_id == product_id,
        ]
        if user_id is not None:
            filters.append(CartItem.user_id == user_id)
        else:
            filters.append(CartItem.session_id == session_id)

        existing = await session.scalar(select(CartItem).where(*filters))
        if existing:
            if quantity <= 0:
                existing.deleted_at = datetime.now(timezone.utc)
            else:
                existing.quantity = quantity
            await session.flush()
            return {"ok": True, "quantity": existing.quantity}

        return {"ok": True, "action": "noop"}

    register_internal_handler("Update", "rose:CartItem", _handle_update_cart_item)

    return bp
