from django.core.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from asgiref.sync import async_to_sync
from rest_framework.generics import ListAPIView
from django_filters.rest_framework import DjangoFilterBackend

from apps.calls.repositories import CatchPhraseReportRepository
from apps.calls.pagination import CatchPhrasePagination
from apps.calls.services import CatchPhraseReportService
from apps.calls.serializers import CallPhraseReportSerializer
from apps.calls.filters import CatchPhraseReportFilter
import asyncio
import logging


logger = logging.getLogger(__name__)


class CatchPhraseReportAPIView(ListAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = CallPhraseReportSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_class = CatchPhraseReportFilter
    pagination_class = CatchPhrasePagination

    def get_company_id(self):
        active_company_id = getattr(self.request.user, "active_company_id", None)
        if not active_company_id:
            raise ValidationError("User does not belong to an active company.")
        return active_company_id

    def get_queryset(self):
        company_id = self.get_company_id()
        queryset = CatchPhraseReportRepository.get_calls(company_id=company_id)
        return self.filter_queryset(queryset)

    def list(self, request, *args, **kwargs):
        company_id = self.get_company_id()
        phrases = list(CatchPhraseReportRepository.get_phrases(company_id))
        queryset = self.get_queryset()
        page = self.paginate_queryset(self.filter_queryset(queryset))

        if page is not None:
            graph_counts = async_to_sync(annotate_calls_async)(page, phrases)
            page_with_phrases = [call for call in page if getattr(call, "_cached_phrases", [])]
            serializer = self.get_serializer(page_with_phrases, many=True)
            graph_data = [
                {"phrase": phrase, "count": count}
                for phrase, count in graph_counts.items()
            ]
            return self.get_paginated_response({
                "calls": serializer.data,
                "graph_data": graph_data
            })

        graph_counts = async_to_sync(self.annotate_calls_async)(queryset, phrases)

        page_with_phrases = [call for call in queryset if getattr(call, "_cached_phrases", [])]

        serializer = self.get_serializer(page_with_phrases, many=True)
        graph_data = [
            {"phrase": phrase, "count": count} for phrase, count in graph_counts.items()
        ]
        return Response({
            "total_calls": len(queryset),
            "calls": serializer.data,
            "graph_data": graph_data
        })

async def annotate_calls_async(calls, phrases):
    tasks = [
        CatchPhraseReportService.build_call_phrase_report_async(call, phrases)
        for call in calls
    ]
    results = await asyncio.gather(*tasks)
    graph_counts = {p.phrase: 0 for p in phrases}

    for call, found_phrases in zip(calls, results):
        call._cached_phrases = found_phrases
        for phrase in found_phrases:
            graph_counts[phrase] += 1
    return graph_counts
