""" Survey analytics API views. Provides endpoints for accessing survey engagement metrics: - Engagement statistics - Patient survey timelines - Completion times - Abandonment analysis - Hourly activity """ from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated from .analytics import ( get_survey_engagement_stats, get_patient_survey_timeline, get_survey_completion_times, get_survey_abandonment_analysis, get_hourly_survey_activity, ) from .models import SurveyInstance, SurveyTracking from .serializers import SurveyInstanceSerializer, SurveyTrackingSerializer class SurveyAnalyticsViewSet(viewsets.ViewSet): """ Survey analytics API. Provides various metrics about survey engagement: - Engagement rates (open, completion, abandonment) - Time metrics (time to complete, time spent) - Patient timelines - Abandonment patterns - Hourly activity """ permission_classes = [IsAuthenticated] @action(detail=False, methods=['get']) def engagement_stats(self, request): """ Get overall survey engagement statistics. Query params: - survey_template_id: Filter by survey template (optional) - hospital_id: Filter by hospital (optional) - days: Number of days to look back (default: 30) """ survey_template_id = request.query_params.get('survey_template_id') hospital_id = request.query_params.get('hospital_id') days = int(request.query_params.get('days', 30)) try: stats = get_survey_engagement_stats( survey_template_id=survey_template_id, hospital_id=hospital_id, days=days ) return Response(stats) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) @action(detail=False, methods=['get']) def patient_timeline(self, request): """ Get survey timeline for a specific patient. Query params: - patient_id: Required - Patient ID """ patient_id = request.query_params.get('patient_id') if not patient_id: return Response( {'error': 'patient_id is required'}, status=status.HTTP_400_BAD_REQUEST ) try: timeline = get_patient_survey_timeline(patient_id) return Response({'timeline': timeline}) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) @action(detail=False, methods=['get']) def completion_times(self, request): """ Get individual survey completion times. Query params: - survey_template_id: Filter by survey template (optional) - hospital_id: Filter by hospital (optional) - days: Number of days to look back (default: 30) """ survey_template_id = request.query_params.get('survey_template_id') hospital_id = request.query_params.get('hospital_id') days = int(request.query_params.get('days', 30)) try: completion_times = get_survey_completion_times( survey_template_id=survey_template_id, hospital_id=hospital_id, days=days ) return Response({'completion_times': completion_times}) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) @action(detail=False, methods=['get']) def abandonment_analysis(self, request): """ Analyze abandoned surveys to identify patterns. Query params: - survey_template_id: Filter by survey template (optional) - hospital_id: Filter by hospital (optional) - days: Number of days to look back (default: 30) """ survey_template_id = request.query_params.get('survey_template_id') hospital_id = request.query_params.get('hospital_id') days = int(request.query_params.get('days', 30)) try: analysis = get_survey_abandonment_analysis( survey_template_id=survey_template_id, hospital_id=hospital_id, days=days ) return Response(analysis) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) @action(detail=False, methods=['get']) def hourly_activity(self, request): """ Get survey activity by hour. Query params: - hospital_id: Filter by hospital (optional) - days: Number of days to look back (default: 7) """ hospital_id = request.query_params.get('hospital_id') days = int(request.query_params.get('days', 7)) try: activity = get_hourly_survey_activity( hospital_id=hospital_id, days=days ) return Response({'activity': activity}) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) @action(detail=False, methods=['get']) def summary_dashboard(self, request): """ Get a comprehensive summary dashboard with all key metrics. Query params: - hospital_id: Filter by hospital (optional) - days: Number of days to look back (default: 30) """ hospital_id = request.query_params.get('hospital_id') days = int(request.query_params.get('days', 30)) try: # Get engagement stats engagement = get_survey_engagement_stats( hospital_id=hospital_id, days=days ) # Get abandonment analysis abandonment = get_survey_abandonment_analysis( hospital_id=hospital_id, days=days ) # Get top 10 fastest completions fastest_completions = get_survey_completion_times( hospital_id=hospital_id, days=days )[:10] # Get top 10 slowest completions slowest_completions = get_survey_completion_times( hospital_id=hospital_id, days=days )[-10:] if len(get_survey_completion_times(hospital_id=hospital_id, days=days)) > 10 else [] return Response({ 'engagement': engagement, 'abandonment': abandonment, 'fastest_completions': fastest_completions, 'slowest_completions': slowest_completions, }) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST ) class SurveyTrackingViewSet(viewsets.ReadOnlyModelViewSet): """ Survey tracking events API. View detailed tracking events for surveys: - Page views - Completions - Abandonments - Device/browser information """ queryset = SurveyTracking.objects.select_related( 'survey_instance', 'survey_instance__patient', 'survey_instance__survey_template' ).order_by('-created_at') serializer_class = SurveyTrackingSerializer permission_classes = [IsAuthenticated] filterset_fields = ['survey_instance', 'event_type', 'device_type', 'browser'] search_fields = ['ip_address', 'user_agent'] @action(detail=False, methods=['get']) def by_survey(self, request): """ Get tracking events for a specific survey instance. Query params: - survey_instance_id: Required - SurveyInstance ID """ survey_instance_id = request.query_params.get('survey_instance_id') if not survey_instance_id: return Response( {'error': 'survey_instance_id is required'}, status=status.HTTP_400_BAD_REQUEST ) try: tracking_events = self.queryset.filter( survey_instance_id=survey_instance_id ) # Serialize and return serializer = self.get_serializer(tracking_events, many=True) return Response(serializer.data) except Exception as e: return Response( {'error': str(e)}, status=status.HTTP_400_BAD_REQUEST )