"""
Public API v1 Views

This module contains all views for the public API v1 endpoints.
These views are designed for third-party integrations and use
API token authentication with scope-based permissions.

API Documentation is available at /api/v1/docs/
"""

from datetime import timedelta
from django.utils import timezone
from django.db.models import Count, Max
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from drf_spectacular.utils import (
    extend_schema,
    extend_schema_view,
    OpenApiParameter,
    OpenApiExample,
    OpenApiResponse,
)
from drf_spectacular.types import OpenApiTypes

from .authentication import APITokenAuthentication
from .permissions import (
    HasAPIToken,
    HasScope,
    CanReadBusiness,
    CanReadServices,
    CanReadResources,
    CanReadAvailability,
    BookingsReadWritePermission,
    CustomersReadWritePermission,
    CanManageWebhooks,
)
from .throttling import GlobalBurstRateThrottle, RateLimitHeadersMixin
from .serializers import (
    # Token serializers
    APITokenCreateSerializer,
    APITokenResponseSerializer,
    APITokenListSerializer,
    APIScopeSerializer,
    # Business serializers
    PublicBusinessSerializer,
    # Service serializers
    PublicServiceSerializer,
    # Resource serializers
    PublicResourceSerializer,
    # Availability serializers
    AvailabilityRequestSerializer,
    AvailabilityResponseSerializer,
    TimeSlotSerializer,
    # Appointment serializers
    PublicAppointmentSerializer,
    AppointmentCreateSerializer,
    AppointmentUpdateSerializer,
    AppointmentCancelSerializer,
    # Customer serializers
    PublicCustomerSerializer,
    CustomerCreateSerializer,
    CustomerUpdateSerializer,
    CustomerDetailSerializer,
    # Webhook serializers
    WebhookSubscriptionSerializer,
    WebhookSubscriptionCreateSerializer,
    WebhookSubscriptionWithSecretSerializer,
    WebhookSubscriptionUpdateSerializer,
    WebhookDeliverySerializer,
    WebhookDeliveryDetailSerializer,
    WebhookEventSerializer,
    # Error serializers
    ErrorSerializer,
    RateLimitErrorSerializer,
)
from .models import APIToken, APIScope, WebhookSubscription, WebhookDelivery, WebhookEvent
from smoothschedule.scheduling.schedule.models import Service, Resource, Event
from smoothschedule.identity.users.models import User


class PublicAPIViewMixin(RateLimitHeadersMixin):
    """
    Base mixin for all public API views.

    Provides:
    - API token authentication
    - Rate limiting with headers
    - Tenant scoping (queries are automatically scoped to the token's tenant)
    """
    authentication_classes = [APITokenAuthentication]
    throttle_classes = [GlobalBurstRateThrottle]

    def get_tenant(self):
        """Get the tenant associated with the current API token."""
        return getattr(self.request, 'tenant', None)


# =============================================================================
# API Token Management (requires user authentication, not API token)
# =============================================================================

@extend_schema_view(
    list=extend_schema(
        summary="List API tokens",
        description="List all API tokens for the current business. Requires owner role.",
        responses={200: APITokenListSerializer(many=True)},
        tags=['Tokens'],
    ),
    create=extend_schema(
        summary="Create API token",
        description=(
            "Create a new API token with specified scopes. "
            "The full token key is only returned once in this response - store it securely!"
        ),
        request=APITokenCreateSerializer,
        responses={
            201: APITokenResponseSerializer,
            400: ErrorSerializer,
        },
        tags=['Tokens'],
    ),
    destroy=extend_schema(
        summary="Revoke API token",
        description="Permanently revoke an API token. This cannot be undone.",
        responses={204: None},
        tags=['Tokens'],
    ),
)

class APITokenViewSet(viewsets.ViewSet):
    """
    ViewSet for managing API tokens.

    This endpoint requires regular user authentication (not API token auth)
    and is intended for business owners to manage their API tokens.

    Requires can_api_access permission.
    """
    # Use session/token auth for token management, not API token auth
    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [IsAuthenticated]

    def _check_api_access_permission(self, tenant):
        """Check if tenant has permission to use API access."""
        from rest_framework.exceptions import PermissionDenied

        if tenant and not tenant.has_feature('can_api_access'):
            raise PermissionDenied(
                "Your current plan does not include API Access. "
                "Please upgrade your subscription to manage API tokens."
            )

    def list(self, request):
        """List all API tokens for the current business."""
        user = request.user

        # For multi-tenant: get tenant from connection if not on user
        from django.db import connection
        tenant = getattr(user, 'tenant', None) or getattr(connection, 'tenant', None)

        if not tenant:
            return Response(
                {'error': 'forbidden', 'message': 'No business associated with user'},
                status=status.HTTP_403_FORBIDDEN
            )

        # Check API access permission
        self._check_api_access_permission(tenant)

        # Only owners can manage API tokens (roles are uppercase in DB)
        allowed_roles = ['OWNER', 'TENANT_OWNER', 'SUPERUSER', 'PLATFORM_MANAGER', 'TENANT_MANAGER']
        if user.role.upper() not in allowed_roles:
            return Response(
                {'error': 'forbidden', 'message': 'Only business owners can manage API tokens'},
                status=status.HTTP_403_FORBIDDEN
            )

        tokens = APIToken.objects.filter(tenant=tenant)
        serializer = APITokenListSerializer(tokens, many=True)
        return Response(serializer.data)

    def create(self, request):
        """Create a new API token."""
        user = request.user

        # For multi-tenant: get tenant from connection if not on user
        from django.db import connection
        tenant = getattr(user, 'tenant', None) or getattr(connection, 'tenant', None)

        if not tenant:
            return Response(
                {'error': 'forbidden', 'message': 'No business associated with user'},
                status=status.HTTP_403_FORBIDDEN
            )

        # Check API access permission
        self._check_api_access_permission(tenant)

        allowed_roles = ['OWNER', 'TENANT_OWNER', 'SUPERUSER', 'PLATFORM_MANAGER', 'TENANT_MANAGER']
        if user.role.upper() not in allowed_roles:
            return Response(
                {'error': 'forbidden', 'message': 'Only business owners can create API tokens'},
                status=status.HTTP_403_FORBIDDEN
            )

        serializer = APITokenCreateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Check if this is a sandbox token
        # Priority: 1) User's explicit choice, 2) Current request's sandbox mode
        is_sandbox = serializer.validated_data.get('is_sandbox', None)
        if is_sandbox is None:
            # If not explicitly set, inherit from current sandbox mode
            is_sandbox = getattr(request, 'sandbox_mode', False)
            import logging
            logger = logging.getLogger(__name__)
            logger.info(f"Token creation: request.sandbox_mode={is_sandbox}, from header: {request.META.get('HTTP_X_SANDBOX_MODE')}")

        # Generate the token with appropriate prefix
        full_key, key_hash, key_prefix = APIToken.generate_key(is_sandbox=is_sandbox)

        token = APIToken.objects.create(
            tenant=tenant,
            name=serializer.validated_data['name'],
            key_hash=key_hash,
            key_prefix=key_prefix,
            scopes=serializer.validated_data['scopes'],
            expires_at=serializer.validated_data.get('expires_at'),
            created_by=user,
            is_sandbox=is_sandbox,
            # SECURITY: Only store plaintext key for sandbox tokens (for docs)
            # NEVER store plaintext key for live production tokens
            plaintext_key=full_key if is_sandbox else None,
        )

        # Return the token with the full key (only time it's shown)
        response_data = APITokenResponseSerializer(token).data
        response_data['key'] = full_key

        return Response(response_data, status=status.HTTP_201_CREATED)

    def destroy(self, request, pk=None):
        """Revoke (delete) an API token."""
        user = request.user

        # For multi-tenant: get tenant from connection if not on user
        from django.db import connection
        tenant = getattr(user, 'tenant', None) or getattr(connection, 'tenant', None)

        if not tenant:
            return Response(
                {'error': 'forbidden', 'message': 'No business associated with user'},
                status=status.HTTP_403_FORBIDDEN
            )

        allowed_roles = ['OWNER', 'TENANT_OWNER', 'SUPERUSER', 'PLATFORM_MANAGER', 'TENANT_MANAGER']
        if user.role.upper() not in allowed_roles:
            return Response(
                {'error': 'forbidden', 'message': 'Only business owners can revoke API tokens'},
                status=status.HTTP_403_FORBIDDEN
            )

        try:
            token = APIToken.objects.get(pk=pk, tenant=tenant)
            token.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except APIToken.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'API token not found'},
                status=status.HTTP_404_NOT_FOUND
            )

    @extend_schema(
        summary="List available scopes",
        description="Get a list of all available API scopes and their descriptions.",
        responses={200: APIScopeSerializer(many=True)},
        tags=['Tokens'],
    )
    @action(detail=False, methods=['get'])
    def scopes(self, request):
        """List all available API scopes."""
        scopes = [
            {'scope': scope, 'description': desc}
            for scope, desc in APIScope.CHOICES
        ]
        return Response(scopes)

    @extend_schema(
        summary="List test tokens for documentation",
        description="Get a list of active test/sandbox tokens with their key prefixes for use in API documentation examples.",
        responses={200: OpenApiResponse(
            description="List of test tokens",
            examples=[
                OpenApiExample(
                    'Example response',
                    value=[
                        {
                            'id': 'tok_123',
                            'name': 'Test Token 1',
                            'key_prefix': 'ss_test_a1b2c3d4',
                            'created_at': '2025-11-28T10:00:00Z'
                        }
                    ]
                )
            ]
        )},
        tags=['Tokens'],
    )
    @action(detail=False, methods=['get'], url_path='test-tokens')
    def test_tokens(self, request):
        """
        List all active test tokens for the current business (for documentation examples).

        SECURITY: This endpoint ONLY returns test/sandbox tokens (is_sandbox=True).
        Live production tokens are NEVER exposed through this endpoint.
        """
        user = request.user

        # For multi-tenant: get tenant from connection if not on user
        from django.db import connection
        tenant = getattr(user, 'tenant', None) or getattr(connection, 'tenant', None)

        if not tenant:
            return Response(
                {'error': 'forbidden', 'message': 'No business associated with user'},
                status=status.HTTP_403_FORBIDDEN
            )

        # SECURITY: Get ONLY test/sandbox tokens (is_sandbox=True)
        # NEVER return live tokens through this endpoint
        test_tokens = APIToken.objects.filter(
            tenant=tenant,
            is_sandbox=True,  # CRITICAL: Only test tokens
            is_active=True
        ).order_by('-created_at')

        # Double-check each token is actually a sandbox token (belt and suspenders)
        test_tokens = [t for t in test_tokens if t.is_sandbox]

        # Return simplified token info for documentation purposes
        # For sandbox tokens, we can safely return the full plaintext key
        # since they're only used for testing/documentation
        token_data = [
            {
                'id': str(token.id),
                'name': token.name,
                'key_prefix': token.plaintext_key or token.key_prefix,  # Full key for sandbox tokens
                'created_at': token.created_at.isoformat(),
            }
            for token in test_tokens
        ]

        return Response(token_data)


# =============================================================================
# Public API Endpoints (API Token Auth)
# =============================================================================

@extend_schema(
    summary="Get business information",
    description="Retrieve public information about the business.",
    responses={
        200: PublicBusinessSerializer,
        401: ErrorSerializer,
    },
    tags=['Business'],
)
class PublicBusinessView(PublicAPIViewMixin, APIView):
    """
    Retrieve public business information.

    Returns the business name, branding colors, logo, timezone,
    and booking-related settings.

    **Required scope:** `business:read`
    """
    permission_classes = [HasAPIToken, CanReadBusiness]

    def get(self, request):
        tenant = self.get_tenant()
        if not tenant:
            return Response(
                {'error': 'not_found', 'message': 'Business not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        data = {
            'id': tenant.id,
            'name': tenant.name,
            'subdomain': tenant.subdomain,
            'logo_url': tenant.logo.url if tenant.logo else None,
            'primary_color': tenant.primary_color,
            'secondary_color': tenant.secondary_color,
            'timezone': str(tenant.timezone) if hasattr(tenant, 'timezone') else 'UTC',
            'cancellation_window_hours': getattr(tenant, 'cancellation_window_hours', 24),
        }

        serializer = PublicBusinessSerializer(data)
        return Response(serializer.data)


@extend_schema_view(
    list=extend_schema(
        summary="List services",
        description="Get all active services offered by the business.",
        responses={200: PublicServiceSerializer(many=True)},
        tags=['Services'],
    ),
    retrieve=extend_schema(
        summary="Get service details",
        description="Get detailed information about a specific service.",
        responses={
            200: PublicServiceSerializer,
            404: ErrorSerializer,
        },
        tags=['Services'],
    ),
)
class PublicServiceViewSet(PublicAPIViewMixin, viewsets.ViewSet):
    """
    ViewSet for listing and retrieving services.

    **Required scope:** `services:read`
    """
    permission_classes = [HasAPIToken, CanReadServices]

    def list(self, request):
        """List all active services."""
        from smoothschedule.scheduling.schedule.models import Service

        services = Service.objects.filter(is_active=True).order_by('display_order', 'name')

        data = []
        for service in services:
            photos = []
            if hasattr(service, 'photos') and service.photos:
                photos = [p.url for p in service.photos.all()] if hasattr(service.photos, 'all') else []

            data.append({
                'id': service.id,
                'name': service.name,
                'description': service.description,
                'duration': service.duration,
                'price': service.price,
                'photos': photos,
                'is_active': service.is_active,
            })

        return Response(data)

    def retrieve(self, request, pk=None):
        """Get a specific service."""
        from smoothschedule.scheduling.schedule.models import Service

        try:
            service = Service.objects.get(pk=pk, is_active=True)
        except Service.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Service not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        photos = []
        if hasattr(service, 'photos') and service.photos:
            photos = [p.url for p in service.photos.all()] if hasattr(service.photos, 'all') else []

        data = {
            'id': service.id,
            'name': service.name,
            'description': service.description,
            'duration': service.duration,
            'price': service.price,
            'photos': photos,
            'is_active': service.is_active,
        }

        return Response(data)


@extend_schema_view(
    list=extend_schema(
        summary="List resources",
        description="Get all active bookable resources (staff, rooms, equipment).",
        parameters=[
            OpenApiParameter(
                name='type',
                type=str,
                location=OpenApiParameter.QUERY,
                description="Filter by resource type",
                required=False,
            ),
        ],
        responses={200: PublicResourceSerializer(many=True)},
        tags=['Resources'],
    ),
    retrieve=extend_schema(
        summary="Get resource details",
        description="Get detailed information about a specific resource.",
        responses={
            200: PublicResourceSerializer,
            404: ErrorSerializer,
        },
        tags=['Resources'],
    ),
)
class PublicResourceViewSet(PublicAPIViewMixin, viewsets.ViewSet):
    """
    ViewSet for listing and retrieving resources.

    **Required scope:** `resources:read`
    """
    permission_classes = [HasAPIToken, CanReadResources]

    def list(self, request):
        """List all active resources."""
        from smoothschedule.scheduling.schedule.models import Resource

        queryset = Resource.objects.filter(is_active=True).select_related('resource_type')

        # Filter by type if specified
        resource_type = request.query_params.get('type')
        if resource_type:
            queryset = queryset.filter(resource_type__name__iexact=resource_type)

        data = []
        for resource in queryset.order_by('name'):
            data.append({
                'id': resource.id,
                'name': resource.name,
                'description': getattr(resource, 'description', None),
                'resource_type': {
                    'id': resource.resource_type.id,
                    'name': resource.resource_type.name,
                    'category': resource.resource_type.category,
                } if resource.resource_type else None,
                'photo_url': resource.photo.url if resource.photo else None,
                'is_active': resource.is_active,
            })

        return Response(data)

    def retrieve(self, request, pk=None):
        """Get a specific resource."""
        from smoothschedule.scheduling.schedule.models import Resource

        try:
            resource = Resource.objects.select_related('resource_type').get(pk=pk, is_active=True)
        except Resource.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Resource not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        data = {
            'id': resource.id,
            'name': resource.name,
            'description': getattr(resource, 'description', None),
            'resource_type': {
                'id': resource.resource_type.id,
                'name': resource.resource_type.name,
                'category': resource.resource_type.category,
            } if resource.resource_type else None,
            'photo_url': resource.photo.url if resource.photo else None,
            'is_active': resource.is_active,
        }

        return Response(data)


@extend_schema(
    summary="Check availability",
    description=(
        "Get available time slots for booking a service. "
        "Returns slots for the specified date range (up to 30 days)."
    ),
    parameters=[
        OpenApiParameter(
            name='service_id',
            type=OpenApiTypes.UUID,
            location=OpenApiParameter.QUERY,
            description="Service ID to check availability for",
            required=True,
        ),
        OpenApiParameter(
            name='resource_id',
            type=OpenApiTypes.UUID,
            location=OpenApiParameter.QUERY,
            description="Optional: specific resource to check",
            required=False,
        ),
        OpenApiParameter(
            name='date',
            type=OpenApiTypes.DATE,
            location=OpenApiParameter.QUERY,
            description="Start date (YYYY-MM-DD)",
            required=True,
        ),
        OpenApiParameter(
            name='days',
            type=OpenApiTypes.INT,
            location=OpenApiParameter.QUERY,
            description="Number of days to check (1-30, default: 7)",
            required=False,
        ),
    ],
    responses={
        200: AvailabilityResponseSerializer,
        400: ErrorSerializer,
        404: ErrorSerializer,
    },
    tags=['Availability'],
)
class AvailabilityView(PublicAPIViewMixin, APIView):
    """
    Check availability for booking a service.

    Returns available time slots within the specified date range.
    You can optionally filter by a specific resource.

    **Required scope:** `availability:read`
    """
    permission_classes = [HasAPIToken, CanReadAvailability]

    def get(self, request):
        serializer = AvailabilityRequestSerializer(data=request.query_params)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid parameters', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        from smoothschedule.scheduling.schedule.models import Service, Resource, Event

        # Get the service
        service_id = serializer.validated_data['service_id']
        try:
            service = Service.objects.get(pk=service_id, is_active=True)
        except Service.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Service not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        # Get optional resource filter
        resource_id = serializer.validated_data.get('resource_id')
        resource = None
        if resource_id:
            try:
                resource = Resource.objects.get(pk=resource_id, is_active=True)
            except Resource.DoesNotExist:
                return Response(
                    {'error': 'not_found', 'message': 'Resource not found'},
                    status=status.HTTP_404_NOT_FOUND
                )

        # Calculate date range
        start_date = serializer.validated_data['date']
        days = serializer.validated_data.get('days', 7)
        end_date = start_date + timedelta(days=days)

        # TODO: Implement actual availability checking logic
        # This is a placeholder that returns empty slots
        # Real implementation would:
        # 1. Get working hours for the business/resource
        # 2. Get existing events in the date range
        # 3. Calculate available slots based on service duration
        # 4. Apply buffer times and business rules

        slots = []

        response_data = {
            'service': {
                'id': service.id,
                'name': service.name,
                'description': service.description,
                'duration': service.duration,
                'price': service.price,
                'photos': [],
                'is_active': service.is_active,
            },
            'date_range': {
                'start': start_date.isoformat(),
                'end': end_date.isoformat(),
            },
            'slots': slots,
        }

        return Response(response_data)


@extend_schema_view(
    list=extend_schema(
        summary="List appointments",
        description="Get appointments within a date range.",
        parameters=[
            OpenApiParameter(
                name='start_date',
                type=OpenApiTypes.DATETIME,
                location=OpenApiParameter.QUERY,
                description="Filter appointments starting from this date",
                required=False,
            ),
            OpenApiParameter(
                name='end_date',
                type=OpenApiTypes.DATETIME,
                location=OpenApiParameter.QUERY,
                description="Filter appointments ending before this date",
                required=False,
            ),
            OpenApiParameter(
                name='status',
                type=str,
                location=OpenApiParameter.QUERY,
                description="Filter by status",
                required=False,
            ),
            OpenApiParameter(
                name='customer_id',
                type=OpenApiTypes.UUID,
                location=OpenApiParameter.QUERY,
                description="Filter by customer",
                required=False,
            ),
        ],
        responses={200: PublicAppointmentSerializer(many=True)},
        tags=['Appointments'],
    ),
    create=extend_schema(
        summary="Create appointment",
        description=(
            "Book a new appointment. Provide either customer_id for existing "
            "customer or customer_email/name/phone to create a new customer."
        ),
        request=AppointmentCreateSerializer,
        responses={
            201: PublicAppointmentSerializer,
            400: ErrorSerializer,
            409: OpenApiResponse(description="Time slot not available"),
        },
        tags=['Appointments'],
    ),
    retrieve=extend_schema(
        summary="Get appointment",
        description="Get details of a specific appointment.",
        responses={
            200: PublicAppointmentSerializer,
            404: ErrorSerializer,
        },
        tags=['Appointments'],
    ),
    partial_update=extend_schema(
        summary="Update appointment",
        description="Update or reschedule an appointment.",
        request=AppointmentUpdateSerializer,
        responses={
            200: PublicAppointmentSerializer,
            400: ErrorSerializer,
            404: ErrorSerializer,
        },
        tags=['Appointments'],
    ),
    destroy=extend_schema(
        summary="Cancel appointment",
        description="Cancel an appointment.",
        request=AppointmentCancelSerializer,
        responses={
            200: PublicAppointmentSerializer,
            400: ErrorSerializer,
            404: ErrorSerializer,
        },
        tags=['Appointments'],
    ),
)
class PublicAppointmentViewSet(PublicAPIViewMixin, viewsets.ViewSet):
    """
    ViewSet for managing appointments/bookings.

    **Required scopes:**
    - GET: `bookings:read`
    - POST/PATCH/DELETE: `bookings:write`
    """
    permission_classes = [HasAPIToken, BookingsReadWritePermission]

    def list(self, request):
        """List appointments with optional filters."""
        from smoothschedule.scheduling.schedule.models import Event

        queryset = Event.objects.all()

        # Apply filters
        start_date = request.query_params.get('start_date')
        if start_date:
            queryset = queryset.filter(start__gte=start_date)

        end_date = request.query_params.get('end_date')
        if end_date:
            queryset = queryset.filter(end__lte=end_date)

        status_filter = request.query_params.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter.upper())

        customer_id = request.query_params.get('customer_id')
        if customer_id:
            # Filter by customer participant
            queryset = queryset.filter(participants__user_id=customer_id, participants__role='CUSTOMER')

        # TODO: Serialize with related data
        data = []
        for event in queryset.order_by('-start')[:100]:
            data.append({
                'id': event.id,
                'service': None,  # TODO: Get from participants
                'resource': None,  # TODO: Get from participants
                'customer': None,  # TODO: Get from participants
                'start_time': event.start.isoformat(),
                'end_time': event.end.isoformat(),
                'status': event.status.lower(),
                'notes': getattr(event, 'notes', None),
                'created_at': event.created.isoformat() if hasattr(event, 'created') else None,
            })

        return Response(data)

    def create(self, request):
        """Create a new appointment."""
        serializer = AppointmentCreateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        # TODO: Implement appointment creation logic
        # 1. Validate service exists and is active
        # 2. Validate resource if specified
        # 3. Get or create customer
        # 4. Check availability
        # 5. Create the event
        # 6. Send confirmation notification

        return Response(
            {'error': 'not_implemented', 'message': 'Appointment creation not yet implemented'},
            status=status.HTTP_501_NOT_IMPLEMENTED
        )

    def retrieve(self, request, pk=None):
        """Get appointment details."""
        from smoothschedule.scheduling.schedule.models import Event

        try:
            event = Event.objects.get(pk=pk)
        except Event.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Appointment not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        data = {
            'id': event.id,
            'service': None,
            'resource': None,
            'customer': None,
            'start_time': event.start.isoformat(),
            'end_time': event.end.isoformat(),
            'status': event.status.lower(),
            'notes': getattr(event, 'notes', None),
            'created_at': event.created.isoformat() if hasattr(event, 'created') else None,
        }

        return Response(data)

    def partial_update(self, request, pk=None):
        """Update/reschedule an appointment."""
        serializer = AppointmentUpdateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        # TODO: Implement appointment update logic

        return Response(
            {'error': 'not_implemented', 'message': 'Appointment update not yet implemented'},
            status=status.HTTP_501_NOT_IMPLEMENTED
        )

    def destroy(self, request, pk=None):
        """Cancel an appointment."""
        from smoothschedule.scheduling.schedule.models import Event

        try:
            event = Event.objects.get(pk=pk)
        except Event.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Appointment not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        # TODO: Check cancellation policy
        # TODO: Update status to CANCELLED
        # TODO: Send cancellation notification

        return Response(
            {'error': 'not_implemented', 'message': 'Appointment cancellation not yet implemented'},
            status=status.HTTP_501_NOT_IMPLEMENTED
        )


@extend_schema_view(
    list=extend_schema(
        summary="List customers",
        description="Get all customers for the business.",
        parameters=[
            OpenApiParameter(
                name='email',
                type=str,
                location=OpenApiParameter.QUERY,
                description="Filter by email address",
                required=False,
            ),
            OpenApiParameter(
                name='search',
                type=str,
                location=OpenApiParameter.QUERY,
                description="Search by name or email",
                required=False,
            ),
        ],
        responses={200: CustomerDetailSerializer(many=True)},
        tags=['Customers'],
    ),
    create=extend_schema(
        summary="Create customer",
        description="Create a new customer record.",
        request=CustomerCreateSerializer,
        responses={
            201: CustomerDetailSerializer,
            400: ErrorSerializer,
            409: OpenApiResponse(description="Customer with this email already exists"),
        },
        tags=['Customers'],
    ),
    retrieve=extend_schema(
        summary="Get customer",
        description="Get details of a specific customer.",
        responses={
            200: CustomerDetailSerializer,
            404: ErrorSerializer,
        },
        tags=['Customers'],
    ),
    partial_update=extend_schema(
        summary="Update customer",
        description="Update customer information.",
        request=CustomerUpdateSerializer,
        responses={
            200: CustomerDetailSerializer,
            400: ErrorSerializer,
            404: ErrorSerializer,
        },
        tags=['Customers'],
    ),
)
class PublicCustomerViewSet(PublicAPIViewMixin, viewsets.ViewSet):
    """
    ViewSet for managing customers.

    **Required scopes:**
    - GET: `customers:read`
    - POST/PATCH: `customers:write`
    """
    permission_classes = [HasAPIToken, CustomersReadWritePermission]

    def list(self, request):
        """List customers with optional filters."""
        from smoothschedule.identity.users.models import User

        queryset = User.objects.filter(role='CUSTOMER')

        # Filter by sandbox mode - API tokens determine this via their is_sandbox flag
        is_sandbox = getattr(request, 'sandbox_mode', False)
        queryset = queryset.filter(is_sandbox=is_sandbox)

        # Filter by email
        email = request.query_params.get('email')
        if email:
            queryset = queryset.filter(email__iexact=email)

        # Search
        search = request.query_params.get('search')
        if search:
            from django.db.models import Q
            queryset = queryset.filter(
                Q(email__icontains=search) |
                Q(first_name__icontains=search) |
                Q(last_name__icontains=search)
            )

        data = []
        for customer in queryset.order_by('email')[:100]:
            data.append({
                'id': customer.id,
                'email': customer.email,
                'name': customer.get_full_name() or customer.username,
                'phone': getattr(customer, 'phone', None),
                'created_at': customer.date_joined.isoformat(),
                'total_appointments': 0,  # TODO: Count appointments
                'last_appointment_at': None,  # TODO: Get last appointment
            })

        return Response(data)

    def create(self, request):
        """Create a new customer."""
        serializer = CustomerCreateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        # TODO: Implement customer creation logic

        return Response(
            {'error': 'not_implemented', 'message': 'Customer creation not yet implemented'},
            status=status.HTTP_501_NOT_IMPLEMENTED
        )

    def retrieve(self, request, pk=None):
        """Get customer details."""
        from smoothschedule.identity.users.models import User

        # Filter by sandbox mode
        is_sandbox = getattr(request, 'sandbox_mode', False)

        try:
            customer = User.objects.get(pk=pk, role='CUSTOMER', is_sandbox=is_sandbox)
        except User.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Customer not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        data = {
            'id': customer.id,
            'email': customer.email,
            'name': customer.get_full_name() or customer.username,
            'phone': getattr(customer, 'phone', None),
            'created_at': customer.date_joined.isoformat(),
            'total_appointments': 0,
            'last_appointment_at': None,
        }

        return Response(data)

    def partial_update(self, request, pk=None):
        """Update customer information."""
        serializer = CustomerUpdateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        # TODO: Implement customer update logic

        return Response(
            {'error': 'not_implemented', 'message': 'Customer update not yet implemented'},
            status=status.HTTP_501_NOT_IMPLEMENTED
        )


@extend_schema_view(
    list=extend_schema(
        summary="List webhook subscriptions",
        description="Get all webhook subscriptions for the current API token.",
        responses={200: WebhookSubscriptionSerializer(many=True)},
        tags=['Webhooks'],
    ),
    create=extend_schema(
        summary="Create webhook subscription",
        description=(
            "Create a new webhook subscription. The secret for signature "
            "verification is only returned once in this response."
        ),
        request=WebhookSubscriptionCreateSerializer,
        responses={
            201: WebhookSubscriptionWithSecretSerializer,
            400: ErrorSerializer,
        },
        tags=['Webhooks'],
    ),
    retrieve=extend_schema(
        summary="Get webhook subscription",
        description="Get details of a specific webhook subscription.",
        responses={
            200: WebhookSubscriptionSerializer,
            404: ErrorSerializer,
        },
        tags=['Webhooks'],
    ),
    partial_update=extend_schema(
        summary="Update webhook subscription",
        description="Update webhook subscription settings.",
        request=WebhookSubscriptionUpdateSerializer,
        responses={
            200: WebhookSubscriptionSerializer,
            400: ErrorSerializer,
            404: ErrorSerializer,
        },
        tags=['Webhooks'],
    ),
    destroy=extend_schema(
        summary="Delete webhook subscription",
        description="Delete a webhook subscription.",
        responses={204: None},
        tags=['Webhooks'],
    ),
)
class WebhookViewSet(PublicAPIViewMixin, viewsets.ViewSet):
    """
    ViewSet for managing webhook subscriptions.

    **Required scope:** `webhooks:manage`
    """
    permission_classes = [HasAPIToken, CanManageWebhooks]

    def _check_webhooks_permission(self, request):
        """Check if tenant has permission to use webhooks."""
        from rest_framework.exceptions import PermissionDenied

        token = request.api_token
        tenant = token.tenant
        if tenant and not tenant.has_feature('can_use_webhooks'):
            raise PermissionDenied(
                "Your current plan does not include Webhooks. "
                "Please upgrade your subscription to use webhooks."
            )

    def list(self, request):
        """List webhook subscriptions for the current API token."""
        self._check_webhooks_permission(request)
        token = request.api_token
        subscriptions = WebhookSubscription.objects.filter(api_token=token)
        serializer = WebhookSubscriptionSerializer(subscriptions, many=True)
        return Response(serializer.data)

    def create(self, request):
        """Create a new webhook subscription."""
        self._check_webhooks_permission(request)

        serializer = WebhookSubscriptionCreateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        secret = WebhookSubscription.generate_secret()

        subscription = WebhookSubscription.objects.create(
            tenant=tenant,
            api_token=token,
            url=serializer.validated_data['url'],
            secret=secret,
            events=serializer.validated_data['events'],
            description=serializer.validated_data.get('description', ''),
        )

        # Return with secret (only shown once)
        response_serializer = WebhookSubscriptionWithSecretSerializer(subscription)
        return Response(response_serializer.data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk=None):
        """Get webhook subscription details."""
        self._check_webhooks_permission(request)
        token = request.api_token

        try:
            subscription = WebhookSubscription.objects.get(pk=pk, api_token=token)
        except WebhookSubscription.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Webhook subscription not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        serializer = WebhookSubscriptionSerializer(subscription)
        return Response(serializer.data)

    def partial_update(self, request, pk=None):
        """Update webhook subscription."""
        serializer = WebhookSubscriptionUpdateSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {'error': 'validation_error', 'message': 'Invalid request', 'details': serializer.errors},
                status=status.HTTP_400_BAD_REQUEST
            )

        token = request.api_token

        try:
            subscription = WebhookSubscription.objects.get(pk=pk, api_token=token)
        except WebhookSubscription.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Webhook subscription not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        # Update fields
        validated_data = serializer.validated_data
        if 'url' in validated_data:
            subscription.url = validated_data['url']
        if 'events' in validated_data:
            subscription.events = validated_data['events']
        if 'is_active' in validated_data:
            subscription.is_active = validated_data['is_active']
            # Reset failure count when re-enabling
            if validated_data['is_active']:
                subscription.failure_count = 0
        if 'description' in validated_data:
            subscription.description = validated_data['description']

        subscription.save()

        response_serializer = WebhookSubscriptionSerializer(subscription)
        return Response(response_serializer.data)

    def destroy(self, request, pk=None):
        """Delete webhook subscription."""
        token = request.api_token

        try:
            subscription = WebhookSubscription.objects.get(pk=pk, api_token=token)
            subscription.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
        except WebhookSubscription.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Webhook subscription not found'},
                status=status.HTTP_404_NOT_FOUND
            )

    @extend_schema(
        summary="List webhook events",
        description="Get a list of all available webhook event types.",
        responses={200: WebhookEventSerializer(many=True)},
        tags=['Webhooks'],
    )
    @action(detail=False, methods=['get'])
    def events(self, request):
        """List available webhook events."""
        events = [
            {'event': event, 'description': desc}
            for event, desc in WebhookEvent.CHOICES
        ]
        return Response(events)

    @extend_schema(
        summary="List webhook deliveries",
        description="Get delivery history for a webhook subscription.",
        responses={200: WebhookDeliverySerializer(many=True)},
        tags=['Webhooks'],
    )
    @action(detail=True, methods=['get'])
    def deliveries(self, request, pk=None):
        """List delivery history for a subscription."""
        token = request.api_token

        try:
            subscription = WebhookSubscription.objects.get(pk=pk, api_token=token)
        except WebhookSubscription.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Webhook subscription not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        deliveries = WebhookDelivery.objects.filter(subscription=subscription).order_by('-created_at')[:50]
        serializer = WebhookDeliverySerializer(deliveries, many=True)
        return Response(serializer.data)

    @extend_schema(
        summary="Send test webhook",
        description="Send a test webhook to verify your endpoint is working.",
        responses={
            200: OpenApiResponse(description="Test webhook sent"),
            404: ErrorSerializer,
        },
        tags=['Webhooks'],
    )
    @action(detail=True, methods=['post'])
    def test(self, request, pk=None):
        """Send a test webhook."""
        token = request.api_token

        try:
            subscription = WebhookSubscription.objects.get(pk=pk, api_token=token)
        except WebhookSubscription.DoesNotExist:
            return Response(
                {'error': 'not_found', 'message': 'Webhook subscription not found'},
                status=status.HTTP_404_NOT_FOUND
            )

        # TODO: Send test webhook via Celery task

        return Response({
            'message': 'Test webhook queued for delivery',
            'subscription_id': str(subscription.id),
        })
