"""Subscription gate middleware.

``SubscriptionCheckMiddleware``
    Checks the tenant's subscription status on every API request and
    blocks suspended/expired tenants before the view is reached.

Exempt paths (configurable via ``SUBSCRIPTION_EXEMPT_PREFIXES`` setting):
    /api/v1/auth/
    /api/v1/subscription/
    /admin/
"""

from __future__ import annotations

import json

from django.conf import settings
from django.http import HttpRequest, HttpResponse

# Paths that are always allowed regardless of subscription status.
_DEFAULT_EXEMPT = (
    "/api/v1/auth/",
    "/api/v1/subscription/",
    "/admin/",
    "/static/",
    "/media/",
)


def _is_exempt(path: str, exempt_prefixes: tuple[str, ...]) -> bool:
    return any(path.startswith(prefix) for prefix in exempt_prefixes)


def _json_response(status: int, code: str, message: str) -> HttpResponse:
    body = json.dumps({"code": code, "message": message})
    return HttpResponse(body, status=status, content_type="application/json")


class SubscriptionCheckMiddleware:
    """Block API requests for tenants whose subscription is suspended or expired.

    Inserted **after** ``TenantResolverMiddleware`` so that ``request.tenant``
    is already populated.

    Status mapping:
      - ``suspended``  → 403 Forbidden
      - ``expired``    → 402 Payment Required
      - ``cancelled``  → 402 Payment Required
      - ``trial`` / ``active`` → allowed
      - No subscription row   → allowed (grace period — handled by seed_plans + onboarding)
    """

    def __init__(self, get_response):
        self.get_response = get_response
        self.exempt_prefixes: tuple[str, ...] = tuple(
            getattr(settings, "SUBSCRIPTION_EXEMPT_PREFIXES", _DEFAULT_EXEMPT)
        )

    def __call__(self, request: HttpRequest) -> HttpResponse:
        tenant = getattr(request, "tenant", None)

        if tenant is not None and not _is_exempt(request.path, self.exempt_prefixes):
            block = self._check_subscription(tenant)
            if block is not None:
                return block

        return self.get_response(request)

    @staticmethod
    def _check_subscription(tenant) -> HttpResponse | None:
        """Return an error HttpResponse if the tenant is blocked, else None."""
        from simorgh.apps.subscription.models import SubscriptionStatus
        from simorgh.apps.subscription.selectors import get_active_subscription

        sub = get_active_subscription(tenant.pk)
        if sub is None:
            # No subscription yet — allow (onboarding flow handles this).
            return None

        if sub.status == SubscriptionStatus.SUSPENDED:
            return _json_response(
                403,
                "SUBSCRIPTION_SUSPENDED",
                "Your account has been suspended. Please contact support.",
            )

        if sub.status in (SubscriptionStatus.EXPIRED, SubscriptionStatus.CANCELLED):
            return _json_response(
                402,
                "SUBSCRIPTION_EXPIRED",
                "Your subscription has expired. Please renew to continue.",
            )

        return None
