from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.shortcuts import get_object_or_404
from django.utils import timezone
import logging

logger = logging.getLogger(__name__)

from .models import Call, CallLog, CallPrompt, VapiAssistant, UserAssistantPreference
from .serializers import (
    CallSerializer, CallLogSerializer, CallPromptSerializer, CallPromptListSerializer,
    VapiAssistantSerializer, UserAssistantPreferenceSerializer
)
from .tasks import initiate_call_task, process_vapi_webhook_task
from seniors.models import Senior
from conversations.models import Conversation


class VapiAssistantViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for viewing VAPI assistants.
    
    Provides read-only access to active VAPI assistants for user selection.
    """
    
    permission_classes = []  # Remove authentication requirement for testing
    serializer_class = VapiAssistantSerializer
    
    def get_queryset(self):
        """Return all active assistants"""
        return VapiAssistant.objects.filter(is_active=True)


class CallPromptViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for viewing call prompts.
    
    Provides read-only access to prompt templates.
    """
    
    permission_classes = []  # Remove authentication requirement for testing
    
    def get_queryset(self):
        """Return all active prompts"""
        queryset = CallPrompt.objects.filter(is_active=True)
        return queryset
    
    def get_serializer_class(self):
        if self.action == 'list':
            return CallPromptListSerializer
        return CallPromptSerializer


class CallViewSet(viewsets.ReadOnlyModelViewSet):
    """
    ViewSet for viewing call information.
    
    Provides read-only access to call data and webhook endpoints.
    """
    
    permission_classes = []  # Remove authentication requirement for testing
    
    def get_queryset(self):
        """Return all calls for testing"""
        return Call.objects.all().select_related('senior')
    
    def get_serializer_class(self):
        return CallSerializer
    
    @action(detail=True, methods=['get'])
    def logs(self, request, pk=None):
        """
        Get logs for a specific call.
        
        GET /api/calls/{id}/logs/
        """
        call = self.get_object()
        logs = call.logs.all().order_by('-created_at')
        
        serializer = CallLogSerializer(logs, many=True)
        return Response({
            'call_id': call.id,
            'logs': serializer.data,
        })
    
    @action(detail=False, methods=['post'])
    def twilio_webhook(self, request):
        """
        Handle Twilio webhook events.
        
        POST /api/calls/twilio_webhook/
        """
        # This endpoint will be called by Twilio for call status updates
        call_sid = request.data.get('CallSid')
        call_status = request.data.get('CallStatus')
        
        if not call_sid:
            return Response({'error': 'CallSid is required'}, 
                          status=status.HTTP_400_BAD_REQUEST)
        
        try:
            call = Call.objects.get(twilio_sid=call_sid)
            
            # Update call status
            call.twilio_status = call_status.lower()
            
            # Update timing information
            if call_status.lower() == 'completed':
                call.call_end_time = timezone.now()
                if call.call_start_time:
                    duration = (call.call_end_time - call.call_start_time).total_seconds()
                    call.duration = int(duration)
            elif call_status.lower() == 'answered':
                call.call_start_time = timezone.now()
            
            call.save()
            
            # Log the webhook event
            CallLog.objects.create(
                call=call,
                event_type='webhook_received',
                message=f'Twilio webhook received: {call_status}',
                data=request.data
            )
            
            return Response({'status': 'success'})
            
        except Call.DoesNotExist:
            return Response({'error': 'Call not found'}, 
                          status=status.HTTP_404_NOT_FOUND)
    
    @action(detail=False, methods=['post'])
    def vapi_webhook(self, request):
        """
        Handle Vapi.ai webhook events.
        
        POST /api/calls/vapi_webhook/
        """
        # Process Vapi webhook asynchronously
        task = process_vapi_webhook_task.delay(request.data)
        
        return Response({
            'status': 'webhook_received',
            'task_id': task.id
        })
    
    @action(detail=False, methods=['post'])
    def update_statuses(self, request):
        """
        Update call statuses by checking Vapi.ai API.
        
        POST /api/calls/update_statuses/
        """
        from .tasks import check_and_update_call_statuses
        
        # Run the status update task
        task = check_and_update_call_statuses.delay()
        
        return Response({
            'message': 'Call status update initiated',
            'task_id': task.id
        })
    
    @action(detail=False, methods=['post'])
    def clear_active(self, request):
        """
        Clear all active calls by updating their status to completed.
        
        POST /api/calls/clear_active/
        Body: {"dry_run": true} (optional)
        """
        from django.utils import timezone
        
        dry_run = request.data.get('dry_run', False)
        
        # Find all active calls
        active_calls = Call.objects.filter(
            twilio_status__in=['initiated', 'ringing', 'in-progress']
        )
        
        if not active_calls.exists():
            return Response({
                'message': 'No active calls found to clear.',
                'cleared_count': 0
            })
        
        call_details = []
        for call in active_calls:
            call_details.append({
                'id': call.id,
                'senior_name': call.senior.name,
                'status': call.twilio_status,
                'created_at': call.created_at.isoformat()
            })
        
        if dry_run:
            return Response({
                'message': f'Found {active_calls.count()} active calls (dry run)',
                'calls': call_details,
                'cleared_count': 0,
                'dry_run': True
            })
        
        # Clear the calls
        cleared_count = 0
        for call in active_calls:
            call.twilio_status = 'completed'
            call.vapi_status = 'ended'
            call.save()
            cleared_count += 1
            
            # Log the clearing action
            CallLog.objects.create(
                call=call,
                event_type='cleared_by_admin',
                message=f'Call cleared by admin API',
                data={'cleared_at': timezone.now().isoformat()}
            )
        
        return Response({
            'message': f'Successfully cleared {cleared_count} active calls.',
            'cleared_count': cleared_count,
            'calls_cleared': call_details
        })

    @action(detail=False, methods=['get'])
    def stats(self, request):
        """
        Get call statistics for the authenticated user.
        
        GET /api/calls/stats/
        """
        user_calls = self.get_queryset()
        
        # Calculate statistics
        total_calls = user_calls.count()
        completed_calls = user_calls.filter(twilio_status='completed').count()
        failed_calls = user_calls.filter(twilio_status='failed').count()
        
        # Calculate average duration
        completed_calls_with_duration = user_calls.filter(
            twilio_status='completed',
            duration__isnull=False
        )
        avg_duration = 0
        if completed_calls_with_duration.exists():
            total_duration = sum(call.duration for call in completed_calls_with_duration)
            avg_duration = total_duration / completed_calls_with_duration.count()
        
        # Get recent calls
        recent_calls = user_calls.order_by('-created_at')[:5]
        recent_calls_data = CallSerializer(recent_calls, many=True).data
        
        return Response({
            'total_calls': total_calls,
            'completed_calls': completed_calls,
            'failed_calls': failed_calls,
            'success_rate': (completed_calls / total_calls * 100) if total_calls > 0 else 0,
            'average_duration_seconds': avg_duration,
            'recent_calls': recent_calls_data,
        })
    
    @action(detail=False, methods=['get'])
    def get_user_preference(self, request):
        """
        Get the current user's assistant preference.
        
        GET /api/calls/get_user_preference/
        """
        from django.contrib.auth.models import User
        
        # For testing, use a default test user
        test_user, created = User.objects.get_or_create(
            username='testuser',
            defaults={'email': 'test@example.com'}
        )
        
        try:
            preference = UserAssistantPreference.objects.get(user=test_user)
            serializer = UserAssistantPreferenceSerializer(preference)
            return Response(serializer.data)
        except UserAssistantPreference.DoesNotExist:
            return Response({
                'message': 'No assistant preference set',
                'has_preference': False
            }, status=status.HTTP_404_NOT_FOUND)
    
    @action(detail=False, methods=['post'])
    def set_user_preference(self, request):
        """
        Set or update the current user's assistant preference.
        
        POST /api/calls/set_user_preference/
        Body: {"assistant_id": 1}
        """
        from django.contrib.auth.models import User
        
        # For testing, use a default test user
        test_user, created = User.objects.get_or_create(
            username='testuser',
            defaults={'email': 'test@example.com'}
        )
        
        assistant_id = request.data.get('assistant_id')
        
        if not assistant_id:
            return Response({
                'error': 'assistant_id is required'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        # Validate assistant exists and is active
        try:
            assistant = VapiAssistant.objects.get(id=assistant_id, is_active=True)
        except VapiAssistant.DoesNotExist:
            return Response({
                'error': 'Assistant not found or inactive'
            }, status=status.HTTP_404_NOT_FOUND)
        
        # Create or update preference
        preference, created = UserAssistantPreference.objects.update_or_create(
            user=test_user,
            defaults={'assistant': assistant}
        )
        
        serializer = UserAssistantPreferenceSerializer(preference)
        return Response({
            'message': 'Assistant preference updated successfully',
            'preference': serializer.data,
            'created': created
        })
    
    @action(detail=False, methods=['post'])
    def get_last_conversation(self, request):
        """
        Get last conversation context for a phone number.
        This endpoint is called by Vapi.ai Server URL/Function Calling.
        
        POST /api/calls/get_last_conversation/
        Body: {
            "phone_number": "+49123456789"
        }
        
        Returns conversation context in format Vapi can use.
        """
        phone_number = request.data.get('phone_number') or request.data.get('phoneNumber')
        
        if not phone_number:
            return Response({
                'error': 'phone_number is required',
                'context': 'This is the first conversation with this person.'
            }, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            # Find senior by phone number
            try:
                senior = Senior.objects.get(phone_number=phone_number)
            except Senior.DoesNotExist:
                return Response({
                    'context': 'This is the first conversation with this person.',
                    'has_previous_conversation': False
                })
            
            # Get last completed call for this senior
            last_call = Call.objects.filter(
                senior=senior,
                twilio_status='completed'
            ).order_by('-created_at').first()
            
            if not last_call:
                return Response({
                    'context': 'This is the first conversation with this person.',
                    'has_previous_conversation': False
                })
            
            # Get conversation for this call
            try:
                conversation = Conversation.objects.get(call=last_call)
            except Conversation.DoesNotExist:
                return Response({
                    'context': 'This is the first conversation with this person.',
                    'has_previous_conversation': False
                })
            
            # Build context string
            context_parts = []
            
            if conversation.summary:
                context_parts.append(f"Summary of last conversation: {conversation.summary}")
            
            if conversation.topics_discussed:
                topics = ', '.join(conversation.topics_discussed) if isinstance(conversation.topics_discussed, list) else str(conversation.topics_discussed)
                context_parts.append(f"Topics discussed: {topics}")
            
            if conversation.emotions_detected:
                emotions = ', '.join(conversation.emotions_detected) if isinstance(conversation.emotions_detected, list) else str(conversation.emotions_detected)
                context_parts.append(f"Emotions observed: {emotions}")
            
            if conversation.follow_up_topics:
                follow_ups = ', '.join(conversation.follow_up_topics) if isinstance(conversation.follow_up_topics, list) else str(conversation.follow_up_topics)
                context_parts.append(f"Topics to follow up on: {follow_ups}")
            
            if conversation.follow_up_questions:
                questions = conversation.follow_up_questions[:3] if isinstance(conversation.follow_up_questions, list) else []
                if questions:
                    questions_str = ', '.join(questions)
                    context_parts.append(f"Questions to ask: {questions_str}")
            
            context = "\n".join(context_parts) if context_parts else "This is the first conversation with this person."
            
            # Add instructions for using the context
            if context_parts:
                context += "\n\nIMPORTANT: Use this previous conversation context naturally and empathetically. You can:"
                context += "\n- Reference topics they mentioned before if it comes up naturally"
                context += "\n- Ask follow-up questions about things they discussed"
                context += "\n- Check on any concerns or interests they had"
                context += "\n- Acknowledge their previous conversation warmly if they remember it"
                context += "\n\nRemember: Don't force connections - only mention previous conversations if relevant and natural to the current discussion."
            
            return Response({
                'context': context,
                'has_previous_conversation': True,
                'last_conversation_date': conversation.created_at.isoformat(),
                'summary': conversation.summary,
                'topics': conversation.topics_discussed,
                'emotions': conversation.emotions_detected
            })
            
        except Exception as e:
            logger.error(f"Error getting last conversation for {phone_number}: {str(e)}")
            return Response({
                'error': 'An error occurred while retrieving conversation context',
                'context': 'This is the first conversation with this person.',
                'has_previous_conversation': False
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)