from rest_framework import viewsets, status, filters
from rest_framework.decorators import action

from rest_framework.response import Response
from django.db.models import Count, Q, Max, OuterRef, Subquery, Avg
from django.utils import timezone
from collections import defaultdict

from apps.calls.constants import TRANSFER_STATUS, SENTIMENT
from .models import Customer
from .serializers import CustomerSerializer, CustomerHistorySerializer
from apps.calls.models import Call
from utils.paginations import OurLimitOffsetPagination
from django_filters.rest_framework import DjangoFilterBackend


class CustomerViewSet(viewsets.ModelViewSet):
    queryset = Customer.objects.all()
    serializer_class = CustomerSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    search_fields = ['name', 'phone']

    @action(detail=False, methods=['get'], url_path='customer-stats',
            pagination_class=OurLimitOffsetPagination,
            filter_backends=[DjangoFilterBackend, filters.SearchFilter]
            )
    def customer_stats(self, request):
        customers_queryset = Customer.objects.all()
        for backend in list(self.filter_backends):
            customers_queryset = backend().filter_queryset(request, customers_queryset, self)

        user = request.user

        if not user.is_superuser and user.active_company:
            customers_queryset = customers_queryset.filter(company=user.active_company)
        elif not user.is_superuser:
            return Response({
                'message': 'No active company found',
                'data': []
            }, status=status.HTTP_200_OK)

        last_call_subquery = Call.objects.filter(
            from_number=OuterRef('phone')
        ).order_by('-created_at').values('created_at')[:1]

        customers_with_stats = customers_queryset.annotate(
            last_call_time=Subquery(last_call_subquery)
        ).order_by('-last_call_time')

        paginator = OurLimitOffsetPagination()
        paginated_customers = paginator.paginate_queryset(customers_with_stats, request, view=self)

        result = []
        for customer in paginated_customers:
            customer_calls = Call.objects.filter(from_number=customer.phone, company=customer.company)
            total_calls = customer_calls.count()
            not_transferred_calls = customer_calls.filter(transfer_status=TRANSFER_STATUS.NOT_TRANSFERRED.value).count()
            missed_calls = customer_calls.filter(transfer_status=TRANSFER_STATUS.FAILED.value).count()
            received_calls = customer_calls.filter(transfer_status=TRANSFER_STATUS.SUCCESSFUL.value).count()

            result.append({
                "customer_id": customer.id,
                "customer_name": customer.name if customer.name != "Unknown" else "Unknown",
                "phone_number": customer.phone,
                "total_calls": total_calls,
                "missed_calls": missed_calls,
                "received_calls": received_calls,
                "not_transferred_calls": not_transferred_calls,
                "last_call_time": customer.last_call_time.isoformat() if customer.last_call_time else None
            })

        return paginator.get_paginated_response(result)

    @action(detail=False, methods=['get'], url_path='customer-history', pagination_class=OurLimitOffsetPagination)
    def customer_history(self, request):
        serializer = CustomerHistorySerializer(data=request.query_params)
        serializer.is_valid(raise_exception=True)
        validated = serializer.validated_data

        customer_id = validated['customer_id']
        start_date = validated['start_date'].date()
        end_date = validated['end_date'].date()

        user = request.user

        try:
            customer = Customer.objects.get(id=customer_id)
            if not user.is_superuser and user.active_company and customer.company != user.active_company:
                return Response({
                    'message': 'Customer not found in your company',
                }, status=status.HTTP_404_NOT_FOUND)
        except Customer.DoesNotExist:
            return Response({
                'message': 'Customer not found',
            }, status=status.HTTP_404_NOT_FOUND)

        dates_queryset = Call.objects.filter(
            from_number=customer.phone,
            created_at__date__range=[start_date, end_date]
        ).values_list('created_at__date', flat=True).distinct().order_by('-created_at__date')

        paginator = OurLimitOffsetPagination()
        paginated_dates = paginator.paginate_queryset(dates_queryset, request, view=self)

        history = []
        for date in paginated_dates:
            calls_for_date = Call.objects.filter(
                from_number=customer.phone,
                created_at__date=date
            ).order_by('-created_at')

            calls_data = []
            for call in calls_for_date:

                advisor_name = None
                if call.transfer_user and call.transfer_user.profile:
                    advisor_name = f"{call.transfer_user.profile.first_name} {call.transfer_user.profile.last_name}"

                calls_data.append({
                    "id": call.id,
                    "twilio_call_id": call.twilio_call_sid,
                    "sentiment": call.sentiment,
                    "advisor_name": advisor_name,
                    "summary": call.summary,
                    "duration": float(call.duration),
                    "time": call.created_at.isoformat(),
                    "transcript": call.transcript,
                    "call_id": call.call_id
                })

            history.append({
                "date": date.isoformat(),
                "calls": calls_data
            })

        total_calls = Call.objects.filter(
            from_number=customer.phone,
            created_at__date__range=[start_date, end_date]
        ).count()

        return Response({
            "count": paginator.count,
            "next": paginator.get_next_link(),
            "previous": paginator.get_previous_link(),
            "customer_name": customer.name,
            "customer_phone": customer.phone,
            "total_calls": total_calls,
            "history": history
        })

    @action(detail=True, methods=['get'], url_path='recent-calls')
    def recent_calls(self, request, pk=None):
        user = request.user

        try:
            customer = self.get_object()
            if not user.is_superuser and user.active_company and customer.company != user.active_company:
                return Response({
                    'message': 'Customer not found in your company',
                }, status=status.HTTP_404_NOT_FOUND)
        except Customer.DoesNotExist:
            return Response({
                'message': 'Customer not found',
            }, status=status.HTTP_404_NOT_FOUND)

        all_calls = Call.objects.filter(
            from_number=customer.phone,
            company=customer.company
        )

        recent_calls = all_calls.order_by('-created_at')[:10]

        sentiment_avg = all_calls.exclude(sentiment__isnull=True).aggregate(
            avg_sentiment=Avg('sentiment')
        )['avg_sentiment']

        recent_call_datetime = None
        if recent_calls:
            recent_call_datetime = recent_calls[0].created_at

        call_records = []
        for call in recent_calls:
            advisor_name = None
            if call.transfer_status == TRANSFER_STATUS.SUCCESSFUL.value and call.transfer_user:
                if hasattr(call.transfer_user, 'profile') and call.transfer_user.profile:
                    advisor_name = f"{call.transfer_user.profile.first_name} {call.transfer_user.profile.last_name}".strip()
                else:
                    advisor_name = call.transfer_user.username

            call_records.append({
                "id": call.id,
                "call_id": call.call_id,
                "twilio_call_id": call.twilio_call_sid,
                "customer_name": customer.name,
                "timestamp": call.created_at.isoformat(),
                "duration_seconds": call.duration,
                "transcript": call.transcript,
                "sentiment_score": call.sentiment,
                "summary": call.summary,
                "advisor_name": advisor_name
            })

        response_data = {
            "customer_name": customer.name,
            "phone": customer.phone,
            "recent_call_datetime": recent_call_datetime.isoformat() if recent_call_datetime else None,
            "avg_sentiment": sentiment_avg,
            "call_records": call_records
        }

        return Response(response_data)
