import pytz
from datetime import datetime, timedelta

from dateutil.relativedelta import relativedelta
from django.db.models import Count, Q, Avg, Sum
from django.db.models.functions import Extract, Round
from django.utils import timezone
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status

from apps.calls.constants import TRANSFER_STATUS, BotType
import logging


logger = logging.getLogger(__name__)


class MonthlyStatsMixin:
    """
    Provides monthly call statistics for the current year.
    """

    @action(detail=False, methods=["get"], url_path="monthly-stats")
    def monthly_stats(self, request):
        qs = self.filter_queryset(self.get_queryset())
        user = request.user

        company_tz = self._get_company_timezone(user)

        now = timezone.now().astimezone(company_tz)

        start_date = (
            now.replace(day=1)
            - relativedelta(months=11)
        ).replace(hour=0, minute=0, second=0, microsecond=0)

        monthly_agg = (
            qs.filter(created_at__gte=start_date)
            .annotate(
                year=Extract("created_at", "year", tzinfo=company_tz),
                month=Extract("created_at", "month", tzinfo=company_tz),
            )
            .values("year", "month")
            .annotate(
                total_calls=Count("id"),
                total_service_calls=Count(
                    "id", filter=Q(bot_type=BotType.SERVICE_BOT)
                ),
                total_sales_calls=Count(
                    "id", filter=Q(bot_type=BotType.SALES_BOT)
                ),
                not_transferred_calls=Count(
                    "id", filter=Q(transfer_status=TRANSFER_STATUS.NOT_TRANSFERRED.value)
                ),
                received_calls=Count(
                    "id", filter=Q(transfer_status=TRANSFER_STATUS.SUCCESSFUL.value)
                ),
                missed_calls=Count(
                    "id", filter=Q(transfer_status=TRANSFER_STATUS.FAILED.value)
                ),
                avg_call_time=Round(Avg("duration")),
                tot_call_time=Sum("duration"),
            )
            .order_by("year", "month")
        )

        return Response(
            self._format_monthly_response(monthly_agg, company_tz),
            status=status.HTTP_200_OK,
        )

    def _get_company_timezone(self, user):
        if getattr(user, "active_company", None) and getattr(user.active_company, "timezone", None):
            try:
                return pytz.timezone(user.active_company.timezone)
            except Exception as exc:
                logger.warning(exc)
                pass
        return timezone.get_default_timezone()

    def _format_monthly_response(self, rows, tz):
        month_names = {
            1: "January", 2: "February", 3: "March", 4: "April",
            5: "May", 6: "June", 7: "July", 8: "August",
            9: "September", 10: "October", 11: "November", 12: "December"
        }

        result = []

        for row in rows:
            year = int(row["year"])
            month = int(row["month"])

            start = timezone.make_aware(datetime(year, month, 1), tz)
            end = start + relativedelta(months=1) - timedelta(microseconds=1)

            result.append({
                "month": month_names.get(month),
                "year": year,
                "start_date": start,
                "end_date": end,
                "tot_calls": row["total_calls"] or 0,
                "total_service_calls": row["total_service_calls"] or 0,
                "total_sales_calls": row["total_sales_calls"] or 0,
                "not_transferred_calls": row["not_transferred_calls"] or 0,
                "missed_calls": row["missed_calls"] or 0,
                "received_calls": row["received_calls"] or 0,
                "avg_call_time": row["avg_call_time"] or 0,
                "tot_call_time": row["tot_call_time"] or 0,
            })

        return result
