from django.db.models import Q
from django.db import models
from decimal import Decimal
from datetime import timedelta
from django.utils import timezone
from uuid import uuid4

from rest_framework import generics, permissions, serializers, status
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.accounts.models import User
from apps.business.wallet.models import SuperCoinWallet, TDSLedger, TWMCoinGrant, Wallet, WalletLedger
from apps.business.wallet.serializers import TWMCoinGrantSerializer
from apps.business.wallet.services.wallet_service import WalletService


def build_user_search_query(raw_query: str) -> Q:
    q = (raw_query or '').strip()
    if not q:
        return Q()

    tokens = [token.strip() for token in q.split() if token.strip()]
    if not tokens:
        return Q()

    combined = Q()
    for token in tokens:
        token_query = (
            Q(user__mobile__icontains=token)
            | Q(user__email__icontains=token)
            | Q(user__first_name__icontains=token)
            | Q(user__last_name__icontains=token)
            | Q(user__id__icontains=token)
        )
        combined &= token_query

    return combined


class AdminWalletPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    max_page_size = 100


class AdminWalletSerializer(serializers.ModelSerializer):
    user_id = serializers.CharField(source='user.id', read_only=True)
    user_name = serializers.SerializerMethodField()
    mobile = serializers.CharField(source='user.mobile', read_only=True)
    email = serializers.CharField(source='user.email', read_only=True)
    super_coin_balance = serializers.SerializerMethodField()
    total_tds_deducted = serializers.SerializerMethodField()

    class Meta:
        model = Wallet
        fields = [
            'user_id',
            'user_name',
            'mobile',
            'email',
            'main_balance',
            'repurchase_balance',
            'voucher_balance',
            'super_coin_balance',
            'total_tds_deducted',
            'locked_amount',
        ]

    def get_user_name(self, obj):
        first = (obj.user.first_name or '').strip()
        last = (obj.user.last_name or '').strip()
        full_name = f"{first} {last}".strip()
        return full_name or obj.user.mobile or obj.user.email or f"User {obj.user_id}"

    def get_super_coin_balance(self, obj):
        wallet = SuperCoinWallet.objects.filter(user=obj.user).first()
        return str(wallet.balance if wallet else 0)

    def get_total_tds_deducted(self, obj):
        total = TDSLedger.objects.filter(user=obj.user).aggregate(total=models.Sum('tds_amount')).get('total')
        return str(total or 0)


class AdminWalletLedgerSerializer(serializers.ModelSerializer):
    user_id = serializers.CharField(source='user.id', read_only=True)
    user_name = serializers.SerializerMethodField()
    mobile = serializers.CharField(source='user.mobile', read_only=True)
    email = serializers.CharField(source='user.email', read_only=True)

    class Meta:
        model = WalletLedger
        fields = [
            'id',
            'user_id',
            'user_name',
            'mobile',
            'email',
            'transaction_type',
            'wallet_type',
            'source_type',
            'amount',
            'reference_id',
            'remarks',
            'metadata',
            'created_at',
        ]

    def get_user_name(self, obj):
        first = (obj.user.first_name or '').strip()
        last = (obj.user.last_name or '').strip()
        full_name = f"{first} {last}".strip()
        return full_name or obj.user.mobile or obj.user.email or f"User {obj.user_id}"


class AdminWalletListView(generics.ListAPIView):
    serializer_class = AdminWalletSerializer
    permission_classes = [permissions.IsAdminUser]
    pagination_class = AdminWalletPagination

    def get_queryset(self):
        queryset = Wallet.objects.select_related('user').all().order_by('-main_balance', '-repurchase_balance')

        balance_type = (self.request.query_params.get('balance_type') or '').strip().lower()
        positive_only = (self.request.query_params.get('positive_only') or '').strip().lower() in {'1', 'true', 'yes'}

        q = (self.request.query_params.get('q') or '').strip()
        if q:
            query = build_user_search_query(q)
            queryset = queryset.filter(query)

        if balance_type == 'main':
            if positive_only:
                queryset = queryset.filter(main_balance__gt=0)
            queryset = queryset.order_by('-main_balance', 'user__first_name', 'user__last_name')
        elif balance_type == 'repurchase':
            if positive_only:
                queryset = queryset.filter(repurchase_balance__gt=0)
            queryset = queryset.order_by('-repurchase_balance', 'user__first_name', 'user__last_name')
        elif balance_type == 'voucher':
            if positive_only:
                queryset = queryset.filter(voucher_balance__gt=0)
            queryset = queryset.order_by('-voucher_balance', 'user__first_name', 'user__last_name')
        elif balance_type == 'locked':
            if positive_only:
                queryset = queryset.filter(locked_amount__gt=0)
            queryset = queryset.order_by('-locked_amount', 'user__first_name', 'user__last_name')
        elif positive_only:
            queryset = queryset.filter(
                Q(main_balance__gt=0) |
                Q(repurchase_balance__gt=0) |
                Q(voucher_balance__gt=0) |
                Q(locked_amount__gt=0)
            )

        return queryset


class AdminWalletLedgerListView(generics.ListAPIView):
    serializer_class = AdminWalletLedgerSerializer
    permission_classes = [permissions.IsAdminUser]
    pagination_class = AdminWalletPagination

    def get_queryset(self):
        queryset = WalletLedger.objects.select_related('user', 'wallet').all().order_by('-created_at')

        user_id = (self.request.query_params.get('user_id') or '').strip()
        if user_id:
            queryset = queryset.filter(user_id=user_id)

        wallet_type = (self.request.query_params.get('wallet_type') or '').strip().upper()
        if wallet_type in {WalletLedger.WalletType.EARNINGS, WalletLedger.WalletType.REPURCHASE, WalletLedger.WalletType.VOUCHER}:
            queryset = queryset.filter(wallet_type=wallet_type)

        transaction_type = (self.request.query_params.get('transaction_type') or '').strip().upper()
        if transaction_type in {WalletLedger.TransactionType.CREDIT, WalletLedger.TransactionType.DEBIT}:
            queryset = queryset.filter(transaction_type=transaction_type)

        q = (self.request.query_params.get('q') or '').strip()
        if q:
            query = (
                Q(reference_id__icontains=q)
                | Q(source_type__icontains=q)
                | build_user_search_query(q)
            )
            queryset = queryset.filter(query)

        return queryset

class WalletConsistencyCheckView(APIView):
    permission_classes = [permissions.IsAdminUser]

    def get(self, request):
        user_id = request.query_params.get('user_id')
        if user_id:
            try:
                user = User.objects.get(id=user_id)
            except User.DoesNotExist:
                return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)
            result = WalletService.validate_wallet_consistency(user)
            return Response(result, status=status.HTTP_200_OK)
        else:
            # Optionally: check all users (use with caution for large datasets)
            # For now, return error if no user_id provided
            return Response({'error': 'user_id query param required'}, status=status.HTTP_400_BAD_REQUEST)


class AdminTWMCoinGrantRequestSerializer(serializers.Serializer):
    user_id = serializers.UUIDField(required=True)
    coins = serializers.DecimalField(max_digits=12, decimal_places=2, min_value=Decimal('0.01'))
    expiry_days = serializers.IntegerField(required=False, min_value=0, default=0)
    reason = serializers.CharField(max_length=500, required=True)


class AdminTWMCoinGrantCreateView(APIView):
    permission_classes = [permissions.IsAdminUser]

    def post(self, request):
        serializer = AdminTWMCoinGrantRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        payload = serializer.validated_data

        user = User.objects.filter(id=payload['user_id']).first()
        if not user:
            return Response({'success': False, 'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)

        expiry_days = int(payload.get('expiry_days') or 0)
        expires_at = timezone.now() + timedelta(days=expiry_days) if expiry_days > 0 else None
        reference_id = f"TWMGRANT-{uuid4().hex[:16].upper()}"

        grant = TWMCoinGrant.objects.create(
            user=user,
            granted_by=request.user,
            amount=payload['coins'],
            expiry_days=expiry_days,
            expires_at=expires_at,
            reason=payload['reason'].strip(),
            reference_id=reference_id,
        )

        WalletService.credit_voucher_wallet(
            user=user,
            amount=payload['coins'],
            source_type=WalletLedger.SourceType.VOUCHER_ADJUSTMENT,
            reference_id=reference_id,
            expires_at=expires_at,
            remarks=payload['reason'].strip(),
            metadata={
                'granted_by': str(request.user.id),
                'expiry_days': expiry_days,
                'grant_id': grant.id,
                'reason': payload['reason'].strip(),
            },
        )

        return Response({'success': True, 'data': TWMCoinGrantSerializer(grant).data}, status=status.HTTP_201_CREATED)


class AdminTWMCoinGrantListView(generics.ListAPIView):
    permission_classes = [permissions.IsAdminUser]
    serializer_class = TWMCoinGrantSerializer
    pagination_class = AdminWalletPagination

    def get_queryset(self):
        qs = TWMCoinGrant.objects.select_related('user', 'granted_by').all().order_by('-created_at')
        user_id = (self.request.query_params.get('user_id') or '').strip()
        if user_id:
            qs = qs.filter(user_id=user_id)
        q = (self.request.query_params.get('q') or '').strip()
        if q:
            qs = qs.filter(
                build_user_search_query(q)
                | Q(reason__icontains=q)
                | Q(reference_id__icontains=q)
            )
        return qs
