from django.core.cache import cache
from django.db.models import Count, Q
from django.utils import timezone
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.administrations.models import (
    CarBooking,
    DocumentRequest,
    PaymentRequest,
    Reimbursement,
)
from apps.asset_management.models import AssetTicket
from apps.chat.models import ConversationParticipant, Message as ChatMessage
from apps.events.models import Event
from apps.hr.models import Recruitment
from apps.notifications.models import Notification
from apps.projects.models import Project
from apps.procurements.models import (
    Approval as ProcurementApproval,
    GoodsReceipt,
    Invoice,
    Payment,
    PurchaseOrder,
    Requisition,
    RFQRFP,
)
from apps.tasks.models import Approval as TaskApproval, Task


class SidebarBadgesView(APIView):
    permission_classes = [IsAuthenticated]
    CACHE_TTL = 10  # seconds — sidebar polled often; staleness up to 10s acceptable
    GLOBAL_CACHE_TTL = 30  # org-wide counts shared by every user; staler is fine

    @staticmethod
    def _global_counts():
        """Counts identical for all users — computed once per TTL org-wide
        instead of once per user per cache miss (7 queries saved per miss)."""
        cached = cache.get("sidebar_badges:global")
        if cached is not None:
            return cached
        data = {
            "procurement_rfq_open": RFQRFP.objects.filter(status="published").count(),
            "procurement_po_open": PurchaseOrder.objects.filter(
                status__in=["draft", "sent", "acknowledged"]
            ).count(),
            "procurement_gr_pending": GoodsReceipt.objects.filter(
                status__in=["pending", "partial"]
            ).count(),
            "procurement_invoices_unpaid": Invoice.objects.filter(
                status__in=["pending", "overdue"]
            ).count(),
            "procurement_payments_pending": Payment.objects.filter(status="pending").count(),
            # Helpdesk requests are now Tasks tagged source="helpdesk".
            "helpdesk_pending": Task.objects.filter(
                source="helpdesk", status__in=["todo", "in_progress", "review"]
            ).count(),
            "hr_recruitment_open": Recruitment.objects.filter(status="open").count(),
        }
        cache.set("sidebar_badges:global", data, SidebarBadgesView.GLOBAL_CACHE_TTL)
        return data

    @extend_schema(description="Sidebar badge counts for current user")
    def get(self, request):
        user = request.user
        cache_key = f"sidebar_badges:{user.id}"
        cached = cache.get(cache_key)
        if cached is not None:
            return Response(cached)

        now = timezone.now()
        global_counts = self._global_counts()

        tasks_assigned = (
            Task.objects.filter(assignee=user)
            .exclude(status__in=["done", "cancelled"])
            .count()
        )

        # Combine 2 TaskApproval counts into one aggregate
        ta = TaskApproval.objects.filter(status="pending").aggregate(
            approver=Count("id", filter=Q(approver=user)),
            requester=Count("id", filter=Q(requester=user)),
        )

        procurement_approvals_pending = ProcurementApproval.objects.filter(
            approver=user, status="pending"
        ).count()
        procurement_my_requests = Requisition.objects.filter(
            requested_by=user, status="pending"
        ).count()

        car_booking_my_requests = CarBooking.objects.filter(
            requester=user, status="pending"
        ).count()
        reimbursement_my_requests = Reimbursement.objects.filter(
            requester=user, status="pending"
        ).count()
        payment_request_my_requests = PaymentRequest.objects.filter(
            requester=user, status="pending"
        ).count()
        document_request_my_requests = DocumentRequest.objects.filter(
            requester=user, status="pending"
        ).count()
        administration_my_requests = (
            car_booking_my_requests
            + reimbursement_my_requests
            + payment_request_my_requests
            + document_request_my_requests
        )

        events_upcoming = (
            Event.objects.filter(
                Q(organizer=user) | Q(teams__user=user),
                start_date__gte=now,
            )
            .distinct()
            .count()
        )

        # Inline subquery — 1 query instead of 2
        convo_ids = ConversationParticipant.objects.filter(user=user).values("conversation_id")
        messages = (
            ChatMessage.objects.filter(conversation_id__in=convo_ids, is_read=False)
            .exclude(sender=user)
            .count()
        )

        notifications = Notification.objects.filter(
            user=user, is_read=False, is_deleted=False
        ).count()

        project_active = (
            Project.objects.filter(
                Q(lead__user=user) | Q(team_members__user=user),
                status__in=["planning", "active"],
            )
            .distinct()
            .count()
        )
        asset_tickets_assigned = AssetTicket.objects.filter(
            assigned_to=user, status__in=["open", "in_progress"]
        ).count()

        payload = {
            **global_counts,
            "tasks_assigned": tasks_assigned,
            "task_approvals_pending": ta["approver"],
            "task_my_approval_requests": ta["requester"],
            "procurement_approvals_pending": procurement_approvals_pending,
            "procurement_my_requests": procurement_my_requests,
            "administration_my_requests": administration_my_requests,
            "car_booking_my_requests": car_booking_my_requests,
            "reimbursement_my_requests": reimbursement_my_requests,
            "payment_request_my_requests": payment_request_my_requests,
            "document_request_my_requests": document_request_my_requests,
            "events_upcoming": events_upcoming,
            "project_active": project_active,
            "asset_tickets_assigned": asset_tickets_assigned,
            "messages": messages,
            "notifications": notifications,
        }
        cache.set(cache_key, payload, self.CACHE_TTL)
        return Response(payload)
