"""Quota enforcement middleware for tier-based limits."""

from __future__ import annotations

from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware

from hieromem_api.errors import QuotaExceededError
from hieromem_api.tenants import Tenant
from hieromem_api.tiers import get_tier_limit
from hieromem_api.usage_tracker import get_usage_tracker


class QuotaMiddleware(BaseHTTPMiddleware):
    """Enforce tier-based quotas on memory operations."""

    async def dispatch(self, request: Request, call_next):
        """Check quotas before processing, record usage after."""
        tenant: Tenant | None = getattr(request.state, "tenant", None)

        if not tenant:
            # No tenant = no quota enforcement (e.g., health checks)
            return await call_next(request)

        # Check quotas before processing
        await self._check_quotas(request, tenant)

        # Process request
        response = await call_next(request)

        # Record usage after successful operation
        if response.status_code < 400:
            await self._record_usage(request, tenant)

        return response

    async def _check_quotas(self, request: Request, tenant: Tenant) -> None:
        """Check if tenant is within quota for this operation."""
        path = request.url.path
        tracker = get_usage_tracker()

        # Check remember quota
        if path in ["/remember", "/memory/remember"]:
            limit = get_tier_limit(tenant.tier, "memories_per_month")
            if not tracker.check_quota(tenant.tenant_id, "remember", limit):
                usage = tracker.get_usage(tenant.tenant_id)
                raise QuotaExceededError(
                    message=f"Monthly memory quota exceeded for {tenant.tier} tier",
                    details={
                        "tier": tenant.tier,
                        "limit": limit,
                        "used": usage.memories_this_month,
                        "upgrade_url": "/billing/upgrade",
                    },
                )

        # Check recall quota
        elif path in ["/recall", "/memory/recall", "/dual-recall", "/memory/dual-recall"]:
            limit = get_tier_limit(tenant.tier, "recalls_per_day")
            if limit is not None and not tracker.check_quota(tenant.tenant_id, "recall", limit):
                usage = tracker.get_usage(tenant.tenant_id)
                raise QuotaExceededError(
                    message=f"Daily recall quota exceeded for {tenant.tier} tier",
                    details={
                        "tier": tenant.tier,
                        "limit": limit,
                        "used": usage.recalls_today,
                        "upgrade_url": "/billing/upgrade",
                    },
                )

    async def _record_usage(self, request: Request, tenant: Tenant) -> None:
        """Record usage after successful operation."""
        path = request.url.path
        tracker = get_usage_tracker()

        if path in ["/remember", "/memory/remember"]:
            tracker.record_remember(tenant.tenant_id)
        elif path in ["/recall", "/memory/recall", "/dual-recall", "/memory/dual-recall"]:
            tracker.record_recall(tenant.tenant_id)


__all__ = ["QuotaMiddleware"]
