"""
Appreciation views - API views for appreciation management
"""

from django.contrib.contenttypes.models import ContentType
from django.db.models import Count, Q, F
from django.utils import timezone
from rest_framework import generics, status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from apps.appreciation.models import (
    Appreciation,
    AppreciationBadge,
    AppreciationCategory,
    AppreciationStats,
    UserBadge,
)
from apps.appreciation.serializers import (
    AppreciationBadgeSerializer,
    AppreciationCategorySerializer,
    AppreciationCreateSerializer,
    AppreciationLeaderboardSerializer,
    AppreciationSerializer,
    AppreciationStatsSerializer,
    AppreciationSummarySerializer,
    UserBadgeSerializer,
)
from apps.accounts.permissions import IsPXAdminOrHospitalAdmin


class AppreciationCategoryViewSet(viewsets.ModelViewSet):
    """Viewset for AppreciationCategory"""

    queryset = AppreciationCategory.objects.all()
    serializer_class = AppreciationCategorySerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        """Filter categories by hospital"""
        queryset = super().get_queryset()

        # Filter by hospital if provided
        hospital_id = self.request.query_params.get("hospital_id")
        if hospital_id:
            queryset = queryset.filter(Q(hospital_id=hospital_id) | Q(hospital__isnull=True))

        # Only show active categories
        queryset = queryset.filter(is_active=True)

        return queryset.select_related("hospital")


class AppreciationViewSet(viewsets.ModelViewSet):
    """Viewset for Appreciation"""

    queryset = Appreciation.objects.all()
    serializer_class = AppreciationSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        """Filter appreciations based on user's access"""
        user = self.request.user
        queryset = super().get_queryset()

        # Filter by hospital
        hospital = getattr(self.request, "tenant_hospital", None) or user.hospital
        if hospital:
            queryset = queryset.filter(hospital=hospital)
        elif not user.is_px_admin():
            queryset = queryset.none()

        # Filter by department if user is department manager
        if user.department and user.is_department_manager():
            queryset = queryset.filter(Q(department=user.department) | Q(department__isnull=True))

        # Filter by visibility
        # Users can see:
        # - All appreciations they sent
        # - All appreciations they received
        # - Department-level appreciations if they're in the department
        # - Hospital-level appreciations if they're in the hospital
        # - Public appreciations

        from apps.appreciation.models import AppreciationVisibility

        # Get user's content type
        user_content_type = ContentType.objects.get_for_model(user)

        # Get staff if user has a staff profile
        staff = None
        if hasattr(user, "staff_profile"):
            staff = user.staff_profile
            staff_content_type = ContentType.objects.get_for_model(type(staff))

        # Build visibility filter
        visibility_filter = (
            Q(sender=user)  # Sent by user
            | Q(recipient_content_type=user_content_type, recipient_object_id=user.id)  # Received by user
        )

        if staff:
            visibility_filter |= Q(
                recipient_content_type=staff_content_type, recipient_object_id=staff.id
            )  # Received by staff

        if user.department:
            visibility_filter |= Q(visibility=AppreciationVisibility.DEPARTMENT, department=user.department)

        if hospital:
            visibility_filter |= Q(visibility=AppreciationVisibility.HOSPITAL, hospital=hospital)

        visibility_filter |= Q(visibility=AppreciationVisibility.PUBLIC)

        queryset = queryset.filter(visibility_filter)

        # Filter by recipient
        recipient_type = self.request.query_params.get("recipient_type")
        recipient_id = self.request.query_params.get("recipient_id")
        if recipient_type and recipient_id:
            if recipient_type == "user":
                content_type = ContentType.objects.get_for_model(self.request.user.__class__)
                queryset = queryset.filter(recipient_content_type=content_type, recipient_object_id=recipient_id)
            elif recipient_type == "staff":
                from apps.organizations.models import Staff

                content_type = ContentType.objects.get_for_model(Staff)
                queryset = queryset.filter(recipient_content_type=content_type, recipient_object_id=recipient_id)

        # Filter by status
        status_filter = self.request.query_params.get("status")
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        # Filter by category
        category_id = self.request.query_params.get("category_id")
        if category_id:
            queryset = queryset.filter(category_id=category_id)

        return queryset.select_related("sender", "hospital", "department", "category").prefetch_related("recipient")

    def create(self, request, *args, **kwargs):
        """Create a new appreciation"""
        serializer = AppreciationCreateSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # Get validated data
        data = serializer.validated_data

        # Get recipient
        recipient_type = data["recipient_type"]
        recipient_id = data["recipient_id"]

        if recipient_type == "user":
            from apps.accounts.models import User

            recipient = User.objects.get(id=recipient_id)
            content_type = ContentType.objects.get_for_model(User)
        else:  # staff
            from apps.organizations.models import Staff

            recipient = Staff.objects.get(id=recipient_id)
            content_type = ContentType.objects.get_for_model(Staff)

        # Get hospital
        from apps.organizations.models import Hospital

        hospital = Hospital.objects.get(id=data["hospital_id"])

        # Get department
        department = None
        if data.get("department_id"):
            from apps.organizations.models import Department

            department = Department.objects.get(id=data["department_id"])

        # Get category
        category = None
        if data.get("category_id"):
            category = AppreciationCategory.objects.get(id=data["category_id"])

        # Create appreciation
        appreciation = Appreciation.objects.create(
            sender=request.user,
            recipient_content_type=content_type,
            recipient_object_id=recipient_id,
            hospital=hospital,
            department=department,
            category=category,
            message_en=data["message_en"],
            message_ar=data.get("message_ar", ""),
            visibility=data["visibility"],
            is_anonymous=data["is_anonymous"],
        )

        # Send appreciation
        appreciation.send()

        try:
            from apps.complaints.tasks import notify_staff_new_item
            notify_staff_new_item.delay("appreciation", str(appreciation.id))
        except Exception:
            pass

        # Serialize and return
        serializer = AppreciationSerializer(appreciation)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    @action(detail=True, methods=["post"])
    def acknowledge(self, request, pk=None):
        """Acknowledge an appreciation"""
        appreciation = self.get_object()

        # Check if user is the recipient
        user_content_type = ContentType.objects.get_for_model(request.user)
        if not (
            appreciation.recipient_content_type == user_content_type
            and appreciation.recipient_object_id == request.user.id
        ):
            return Response(
                {"error": "You can only acknowledge appreciations sent to you"}, status=status.HTTP_403_FORBIDDEN
            )

        # Acknowledge
        appreciation.acknowledge()

        # Serialize and return
        serializer = AppreciationSerializer(appreciation)
        return Response(serializer.data)

    @action(detail=False, methods=["get"])
    def my_appreciations(self, request):
        """Get appreciations for the current user"""
        # Get user's appreciations
        user_content_type = ContentType.objects.get_for_model(request.user)

        # Check if user has staff profile
        staff = None
        if hasattr(request.user, "staff_profile"):
            staff = request.user.staff_profile

        # Build query
        queryset = self.get_queryset().filter(
            Q(recipient_content_type=user_content_type, recipient_object_id=request.user.id)
        )

        if staff:
            staff_content_type = ContentType.objects.get_for_model(type(staff))
            queryset |= self.get_queryset().filter(
                recipient_content_type=staff_content_type, recipient_object_id=staff.id
            )

        # Paginate
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = AppreciationSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = AppreciationSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=["get"])
    def sent_by_me(self, request):
        """Get appreciations sent by the current user"""
        queryset = self.get_queryset().filter(sender=request.user)

        # Paginate
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = AppreciationSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = AppreciationSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=["get"])
    def summary(self, request):
        """Get appreciation summary for the current user"""
        # Get user's content type
        user_content_type = ContentType.objects.get_for_model(request.user)

        # Get current year and month
        now = timezone.now()
        current_year = now.year
        current_month = now.month

        # Count total received
        total_received = Appreciation.objects.filter(
            recipient_content_type=user_content_type, recipient_object_id=request.user.id
        ).count()

        # Count total sent
        total_sent = Appreciation.objects.filter(sender=request.user).count()

        # Count this month received
        this_month_received = Appreciation.objects.filter(
            recipient_content_type=user_content_type,
            recipient_object_id=request.user.id,
            sent_at__year=current_year,
            sent_at__month=current_month,
        ).count()

        # Count this month sent
        this_month_sent = Appreciation.objects.filter(
            sender=request.user, sent_at__year=current_year, sent_at__month=current_month
        ).count()

        # Get badges earned
        badges_earned = UserBadge.objects.filter(
            recipient_content_type=user_content_type, recipient_object_id=request.user.id
        ).count()

        # Get hospital rank
        hospital_rank = None
        if request.user.hospital:
            # Get stats for this month
            stats = AppreciationStats.objects.filter(
                recipient_content_type=user_content_type,
                recipient_object_id=request.user.id,
                year=current_year,
                month=current_month,
            ).first()
            if stats:
                hospital_rank = stats.hospital_rank

        # Get top category
        top_category = None
        if total_received > 0:
            top_category_obj = (
                Appreciation.objects.filter(
                    recipient_content_type=user_content_type, recipient_object_id=request.user.id
                )
                .values("category__name_en", "category__icon", "category__color")
                .annotate(count=Count("id"))
                .order_by("-count")
                .first()
            )

            if top_category_obj and top_category_obj["category__name_en"]:
                top_category = {
                    "name": top_category_obj["category__name_en"],
                    "icon": top_category_obj["category__icon"],
                    "color": top_category_obj["category__color"],
                    "count": top_category_obj["count"],
                }

        # Build response
        summary = {
            "total_received": total_received,
            "total_sent": total_sent,
            "this_month_received": this_month_received,
            "this_month_sent": this_month_sent,
            "top_category": top_category,
            "badges_earned": badges_earned,
            "hospital_rank": hospital_rank,
        }

        serializer = AppreciationSummarySerializer(summary)
        return Response(serializer.data)


class AppreciationStatsViewSet(viewsets.ReadOnlyModelViewSet):
    """Viewset for AppreciationStats"""

    queryset = AppreciationStats.objects.all()
    serializer_class = AppreciationStatsSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        """Filter stats based on user's access"""
        user = self.request.user
        queryset = super().get_queryset()

        # Filter by hospital
        hospital = getattr(self.request, "tenant_hospital", None) or user.hospital
        if hospital:
            queryset = queryset.filter(hospital=hospital)
        elif not user.is_px_admin():
            queryset = queryset.none()

        # Filter by year and month
        year = self.request.query_params.get("year")
        if year:
            queryset = queryset.filter(year=int(year))

        month = self.request.query_params.get("month")
        if month:
            queryset = queryset.filter(month=int(month))

        return queryset.select_related("hospital", "department")


class AppreciationBadgeViewSet(viewsets.ModelViewSet):
    """Viewset for AppreciationBadge"""

    queryset = AppreciationBadge.objects.all()
    serializer_class = AppreciationBadgeSerializer
    permission_classes = [IsAuthenticated, IsPXAdminOrHospitalAdmin]

    def get_queryset(self):
        """Filter badges by hospital"""
        queryset = super().get_queryset()

        # Filter by hospital if provided
        hospital_id = self.request.query_params.get("hospital_id")
        if hospital_id:
            queryset = queryset.filter(Q(hospital_id=hospital_id) | Q(hospital__isnull=True))

        # Only show active badges
        queryset = queryset.filter(is_active=True)

        return queryset.select_related("hospital")


class UserBadgeViewSet(viewsets.ReadOnlyModelViewSet):
    """Viewset for UserBadge"""

    queryset = UserBadge.objects.all()
    serializer_class = UserBadgeSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        """Filter badges based on user's access"""
        user = self.request.user
        queryset = super().get_queryset()

        # Get user's content type
        user_content_type = ContentType.objects.get_for_model(user)

        # Filter by user or user's staff profile
        staff = None
        if hasattr(user, "staff_profile"):
            staff = user.staff_profile
            staff_content_type = ContentType.objects.get_for_model(type(staff))

        queryset = queryset.filter(Q(recipient_content_type=user_content_type, recipient_object_id=user.id))

        if staff:
            queryset |= queryset.filter(recipient_content_type=staff_content_type, recipient_object_id=staff.id)

        return queryset.select_related("badge")


class LeaderboardView(generics.ListAPIView):
    """View for appreciation leaderboard"""

    serializer_class = AppreciationLeaderboardSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        """Build leaderboard"""
        # Get filters
        year = self.request.query_params.get("year")
        month = self.request.query_params.get("month")

        # Default to current month
        if not year or not month:
            now = timezone.now()
            year = now.year
            month = now.month
        else:
            year = int(year)
            month = int(month)

        # Get hospital from request user
        user = self.request.user
        hospital = getattr(self.request, "tenant_hospital", None) or user.hospital
        if not hospital and not user.is_px_admin():
            return []

        # Get stats for the period
        stats_qs = AppreciationStats.objects.filter(year=year, month=month, received_count__gt=0)
        if hospital:
            stats_qs = stats_qs.filter(hospital=hospital)
        stats = stats_qs.order_by("-received_count")

        # Build leaderboard
        leaderboard = []
        for rank, stat in enumerate(stats, start=1):
            recipient_name = stat.get_recipient_name()
            recipient_type = stat.recipient_content_type.model if stat.recipient_content_type else "unknown"

            # Get badges for recipient
            badges = []
            user_badges = UserBadge.objects.filter(
                recipient_content_type=stat.recipient_content_type, recipient_object_id=stat.recipient_object_id
            ).select_related("badge")

            for user_badge in user_badges:
                badges.append(
                    {
                        "name": user_badge.badge.name_en,
                        "icon": user_badge.badge.icon,
                        "color": user_badge.badge.color,
                    }
                )

            leaderboard.append(
                {
                    "rank": rank,
                    "recipient_type": recipient_type,
                    "recipient_id": stat.recipient_object_id,
                    "recipient_name": recipient_name,
                    "hospital": stat.hospital.name,
                    "department": stat.department.name if stat.department else None,
                    "received_count": stat.received_count,
                    "badges": badges,
                }
            )

        return leaderboard
