"""
Public API Permissions

This module provides permission classes for the public API,
including scope-based permission checking for API tokens.
"""

from rest_framework import permissions
from .models import APIScope


class HasAPIToken(permissions.BasePermission):
    """
    Permission class that requires a valid API token.

    This permission checks that the request was authenticated with
    an API token (not a user session or other auth method).

    Usage:
        class MyView(APIView):
            permission_classes = [HasAPIToken]
    """

    message = 'Valid API token required.'

    def has_permission(self, request, view):
        """Check if request has a valid API token."""
        return (
            hasattr(request, 'api_token') and
            request.api_token is not None and
            request.api_token.is_valid()
        )


class HasScope(permissions.BasePermission):
    """
    Permission class that requires specific API scopes.

    This permission checks that the API token has the required scope(s)
    for the requested action. Scopes can be specified at the view level
    or determined dynamically based on the HTTP method.

    Usage:
        class MyView(APIView):
            permission_classes = [HasAPIToken, HasScope]
            required_scopes = ['services:read']

        # Or with method-specific scopes:
        class MyView(APIView):
            permission_classes = [HasAPIToken, HasScope]
            required_scopes = {
                'GET': ['services:read'],
                'POST': ['services:write'],
            }

        # Or use the decorator:
        @require_scopes(['services:read'])
        class MyView(APIView):
            pass
    """

    message = 'API token lacks required scope for this operation.'

    def has_permission(self, request, view):
        """Check if the API token has the required scope(s)."""
        # First check that we have an API token
        if not hasattr(request, 'api_token') or request.api_token is None:
            return False

        token = request.api_token

        # Get required scopes from the view
        required_scopes = self._get_required_scopes(request, view)

        if not required_scopes:
            # No scopes required, allow access
            return True

        # Check if token has any of the required scopes
        # (OR logic - having any one scope is sufficient)
        return token.has_any_scope(required_scopes)

    def _get_required_scopes(self, request, view):
        """
        Get the required scopes for this request.

        Supports:
        - List of scopes: ['services:read', 'services:write']
        - Dict of method -> scopes: {'GET': ['read'], 'POST': ['write']}
        - Callable that returns scopes: lambda request, view: [...]
        """
        required_scopes = getattr(view, 'required_scopes', None)

        if required_scopes is None:
            return []

        if callable(required_scopes):
            return required_scopes(request, view)

        if isinstance(required_scopes, dict):
            # Method-specific scopes
            method = request.method.upper()
            return required_scopes.get(method, [])

        # Assume it's a list of scopes
        return list(required_scopes)


class HasAllScopes(HasScope):
    """
    Like HasScope but requires ALL scopes (AND logic).

    Usage:
        class MyView(APIView):
            permission_classes = [HasAPIToken, HasAllScopes]
            required_scopes = ['services:read', 'customers:read']
    """

    message = 'API token lacks all required scopes for this operation.'

    def has_permission(self, request, view):
        """Check if the API token has ALL required scopes."""
        if not hasattr(request, 'api_token') or request.api_token is None:
            return False

        token = request.api_token
        required_scopes = self._get_required_scopes(request, view)

        if not required_scopes:
            return True

        return token.has_all_scopes(required_scopes)


def require_scopes(*scopes):
    """
    Decorator to specify required scopes for a view or viewset action.

    Usage:
        @require_scopes('services:read')
        class MyView(APIView):
            permission_classes = [HasAPIToken, HasScope]

        # Or on a viewset action:
        class MyViewSet(ViewSet):
            @require_scopes('services:write')
            def create(self, request):
                pass
    """
    def decorator(view_or_func):
        view_or_func.required_scopes = list(scopes)
        return view_or_func
    return decorator


# Convenience permission classes for common scope combinations

class CanReadServices(HasScope):
    """Permission requiring services:read scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.SERVICES_READ]


class CanReadResources(HasScope):
    """Permission requiring resources:read scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.RESOURCES_READ]


class CanReadAvailability(HasScope):
    """Permission requiring availability:read scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.AVAILABILITY_READ]


class CanReadBookings(HasScope):
    """Permission requiring bookings:read scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.BOOKINGS_READ]


class CanWriteBookings(HasScope):
    """Permission requiring bookings:write scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.BOOKINGS_WRITE]


class CanReadCustomers(HasScope):
    """Permission requiring customers:read scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.CUSTOMERS_READ]


class CanWriteCustomers(HasScope):
    """Permission requiring customers:write scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.CUSTOMERS_WRITE]


class CanReadBusiness(HasScope):
    """Permission requiring business:read scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.BUSINESS_READ]


class CanManageWebhooks(HasScope):
    """Permission requiring webhooks:manage scope."""

    def _get_required_scopes(self, request, view):
        return [APIScope.WEBHOOKS_MANAGE]


class BookingsReadWritePermission(HasScope):
    """
    Permission for bookings endpoints.

    - GET requests require bookings:read
    - POST/PATCH/DELETE require bookings:write
    """

    def _get_required_scopes(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return [APIScope.BOOKINGS_READ]
        return [APIScope.BOOKINGS_WRITE]


class CustomersReadWritePermission(HasScope):
    """
    Permission for customers endpoints.

    - GET requests require customers:read
    - POST/PATCH/DELETE require customers:write
    """

    def _get_required_scopes(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return [APIScope.CUSTOMERS_READ]
        return [APIScope.CUSTOMERS_WRITE]
