from django.apps import apps
from django.utils.decorators import method_decorator

from .decorators import shop_session


class ShopSessionMixin:
    """Mixin that authenticates requests against a valid Shopify shop session.

    Staff bypass can be enabled globally via SHOPIFY_STAFF_BYPASS = True in
    Django settings, or per-view with allow_staff_bypass = True.

    Optionally restrict bypass to specific HTTP methods via
    SHOPIFY_STAFF_BYPASS_METHODS (e.g. ["GET", "HEAD", "OPTIONS"]).
    When None (default), all methods are allowed.

    The user attribute that holds the shop is configurable via
    SHOPIFY_STAFF_SHOP_ATTR (default: "admin_shop").
    """

    allow_staff_bypass = None

    def _get_allow_staff_bypass(self):
        """Return per-view override or the global SHOPIFY_STAFF_BYPASS setting."""
        if self.allow_staff_bypass is not None:
            return self.allow_staff_bypass
        return apps.get_app_config("shopify_app").SHOPIFY_STAFF_BYPASS

    def _get_staff_shop_attr(self):
        """Return the user model attribute name that holds the staff shop."""
        return apps.get_app_config("shopify_app").SHOPIFY_STAFF_SHOP_ATTR

    def _get_staff_shop(self, request):
        """Return the shop instance from the staff user, or None."""
        return getattr(request.user, self._get_staff_shop_attr(), None)

    def _is_method_allowed_for_bypass(self, method):
        """Check if the HTTP method is allowed for staff bypass."""
        allowed = apps.get_app_config("shopify_app").SHOPIFY_STAFF_BYPASS_METHODS
        if allowed is None:
            return True
        return method.upper() in [m.upper() for m in allowed]

    def dispatch(self, request, *args, **kwargs):
        """Route to staff bypass or Shopify session auth based on configuration."""
        if (
            self._get_allow_staff_bypass()
            and self._is_method_allowed_for_bypass(request.method)
            and self._is_staff_with_shop(request)
        ):
            request.shop = self._get_staff_shop(request)
            return super().dispatch(request, *args, **kwargs)

        return self._shop_session_dispatch(request, *args, **kwargs)

    @method_decorator(shop_session)
    def _shop_session_dispatch(self, request, *args, **kwargs):
        """Dispatch with Shopify session token validation applied."""
        return super().dispatch(request, *args, **kwargs)

    def _is_staff_with_shop(self, request):
        """Check if the request user is an authenticated staff member with a shop."""
        return (
            request.user.is_authenticated
            and request.user.is_staff
            and self._get_staff_shop(request)
        )
