import logging
from django.db.models import Count, Prefetch, OuterRef, Subquery, Exists
from rest_framework import status
from rest_framework.response import Response

from apps.core.views.base import BaseViewSet
from apps.users.models import User
from apps.profiles.models import Profile, GlobalRank, ProfileRank
from .serializers import EmptySerializer

# Logger setup
logger = logging.getLogger(__name__)

class LeaderboardViewSet(BaseViewSet):
    queryset = User.objects.all()
    serializer_class = EmptySerializer  
    permission_app_name = 'leaderboard' 
    permission_model_name = 'leaderboard'  
    view_permissions = ['list']

    def list(self, request, *args, **kwargs):
        try:
            # Get current user
            current_user = request.user
            
            # Subquery to check if user has active rank claims (for NFT badge)
            has_global_rank = Exists(
                GlobalRank.objects.filter(profile__user=OuterRef('pk'))
            )
            
            has_active_category_rank = Exists(
                ProfileRank.objects.filter(
                    profile__user=OuterRef('pk'),
                    is_active=True
                )
            )
            
            # Annotate users with agent count and rank claim status
            users_queryset = User.objects.filter(is_superuser=False).annotate(
                agent_count=Count('referred_profiles_set', distinct=True),
                has_global_rank=has_global_rank,
                has_active_category_rank=has_active_category_rank
            ).prefetch_related(
                Prefetch(
                    'profile__global_rank',
                    queryset=GlobalRank.objects.all(),
                    to_attr='global_rank_info'
                ),
                Prefetch(
                    'profile__profile_ranks',
                    queryset=ProfileRank.objects.filter(is_active=True).select_related('rank_category'),
                    to_attr='active_category_ranks'
                )
            ).order_by('-agent_count', 'id')

            queryset = self.filter_queryset(users_queryset)

            page = self.paginate_queryset(queryset)

            if page is not None:
                page_size = getattr(self.pagination_class, 'page_size', 10)
                try:
                    current_page_number = int(request.query_params.get('page', 1))
                except ValueError:
                    current_page_number = 1
                
                start_rank = ((current_page_number - 1) * page_size) + 1
                leaderboard_data = self._prepare_leaderboard_list(page, start_rank, current_user)
                return self.get_paginated_response(leaderboard_data)

            leaderboard_data = self._prepare_leaderboard_list(queryset, 1, current_user)
            
            return Response({
                "success": True,
                "message": "Leaderboard data fetched successfully",
                "data": leaderboard_data
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"Leaderboard List Error: {str(e)}")
            return Response({
                "success": False,
                "message": "An error occurred while fetching leaderboard",
                "error_code": "500"
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def _prepare_leaderboard_list(self, users, start_rank, current_user):
        """
        লিডারবোর্ড ডাটা ফরম্যাট করার হেল্পার ফাংশন।
        NFT badge true হবে যদি user-এর GlobalRank থাকে অথবা active ProfileRank থাকে।
        """
        leaderboard_data = []
        try:
            for idx, user in enumerate(users, start=start_rank):
                agent_count = getattr(user, 'agent_count', 0)
                
                # Check if user has NFT badge (Global Rank or Active Category Rank)
                has_nft = False
                current_ranks = []
                
                # Check Global Rank
                if hasattr(user, 'has_global_rank') and user.has_global_rank:
                    has_nft = True
                    if hasattr(user, 'global_rank_info') and user.global_rank_info:
                        for global_rank in user.global_rank_info:
                            current_ranks.append({
                                "type": "global",
                                "rank": global_rank.global_rank,
                                "total_spending": float(global_rank.total_spending),
                                "is_active": True
                            })
                
                # Check Active Category Ranks
                if hasattr(user, 'has_active_category_rank') and user.has_active_category_rank:
                    has_nft = True
                    if hasattr(user, 'active_category_ranks') and user.active_category_ranks:
                        for profile_rank in user.active_category_ranks:
                            current_ranks.append({
                                "type": "category",
                                "category": profile_rank.rank_category.name if profile_rank.rank_category else None,
                                "category_rank": profile_rank.category_rank,
                                "claimed_at": profile_rank.claimed_at.isoformat() if profile_rank.claimed_at else None,
                                "is_active": profile_rank.is_active
                            })
                
                leaderboard_data.append({
                    "rank": idx,
                    "user": {
                        "id": str(user.id),
                        "name": user.name or user.email,
                        "email": user.email
                    },
                    "badge_name": self.badge_by_agent(agent_count),
                    "referral_users": agent_count,
                    "is_current_user": user.id == current_user.id,
                    "nft_badge": has_nft,  # True if user has any rank claim
                    "current_ranks": current_ranks  # Include rank details
                })
        except Exception as e:
            logger.error(f"Error preparing leaderboard list formatting: {str(e)}")
            raise e
            
        return leaderboard_data

    @staticmethod
    def badge_by_agent(count: int) -> str:
        if count >= 5000: return "Ambassador"
        elif count >= 2500: return "Director"
        elif count >= 1000: return "Manager"
        elif count >= 400: return "Senior Executive"
        elif count >= 100: return "Executive"
        elif count >= 20: return "Team Leader"
        return "Member"