import httpx
import logfire
from fastapi import APIRouter, Depends, Form
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select

from app.cache import invalidate_restaurant_stats_cache
from app.db.session import commit_write, get_bypass_session
from app.dependencies import get_restate_client, restate_proxy
from app.models.order import Order
from app.payments.mollie import PaymentNotConfiguredError, get_payment

router = APIRouter(prefix="/webhooks", tags=["webhooks"])


@router.post("/mollie")
async def mollie_webhook(
    id: str = Form(...),
    session: AsyncSession = Depends(get_bypass_session),
    client: httpx.AsyncClient = Depends(get_restate_client),
) -> dict[str, str]:
    with logfire.span("mollie_webhook", payment_id=id):
        try:
            payment_data = await get_payment(id, client=client)
        except PaymentNotConfiguredError as exc:
            logfire.warning("mollie_not_configured", payment_id=id, error=str(exc))
            return {"status": "error", "reason": "payment_provider_not_configured"}
        except Exception as exc:
            logfire.error("mollie_fetch_failed", payment_id=id, error=str(exc))
            return {"status": "error"}

        status = payment_data.get("status", "unknown")
        metadata: dict = payment_data.get("metadata", {})
        reservation_id = metadata.get("reservation_id")

        # ── Reservation deposit payment — route to Restate PaymentService ───────
        if reservation_id:
            awakeable_id = metadata.get("awakeable_id", "")
            logfire.info(
                "mollie_reservation_webhook",
                payment_id=id,
                reservation_id=reservation_id,
                status=status,
            )
            try:
                await restate_proxy(
                    client,
                    "PaymentService",
                    "mollie_webhook",
                    {
                        "payment_id": id,
                        "status": status,
                        "awakeable_id": awakeable_id,
                        "reservation_id": reservation_id,
                    },
                    mode="service",
                )
            except Exception as exc:
                logfire.error(
                    "mollie_reservation_proxy_failed",
                    payment_id=id,
                    error=str(exc),
                )
            return {"status": "ok"}

        # ── Order payment — handle directly (existing behaviour) ─────────────────
        order_id = metadata.get("order_id")

        if not order_id:
            logfire.warning("mollie_webhook_no_order_id", payment_id=id)
            return {"status": "ok"}

        # Bypass session (owner pool, BYPASSRLS) — webhook has no user JWT,
        # so we resolve the order by id and trust the application-level
        # ownership check below. Order.id is globally unique; a direct lookup
        # is both faster and simpler than the per-tenant iteration RLS forced
        # when this path lived on the GUC-scoped pool.
        result = await session.execute(select(Order).where(Order.id == order_id))
        order = result.scalar_one_or_none()
        if order is None:
            logfire.warning("mollie_webhook_order_not_found", order_id=order_id)
            return {"status": "ok"}
        logfire.info(
            "mollie_order_resolved",
            order_id=order_id,
            restaurant_id=order.restaurant_id,
        )

        mollie_to_order_status = {
            "paid": "paid",
            "canceled": "cancelled",
            "expired": "cancelled",
            "failed": "cancelled",
        }
        new_status = mollie_to_order_status.get(status)

        if new_status and order.status != new_status:
            order.status = new_status
            order.mollie_payment_id = id
            session.add(order)
            await commit_write(session)
            invalidate_restaurant_stats_cache(order.restaurant_id)
            logfire.info(
                "mollie_order_updated",
                order_id=order_id,
                payment_id=id,
                status=new_status,
            )

    return {"status": "ok"}
