from rest_framework import serializers
from django.utils import timezone
from django.db.models import Sum
from .models import DistributorID
from apps.business.products.models import Product
from .models import AutoIDAllocation, DistributorTransferAcceptance, DistributorTransferRequest, DistributorTransferTerms, DistributorTransferHistory, DistributorRewardOwnershipLedger


def _current_mandatory_term_ids():
    now = timezone.now()
    terms = DistributorTransferTerms.objects.filter(is_active=True, mandatory=True).order_by('display_order', 'created_at')
    terms = terms.exclude(applies_from__isnull=False, applies_from__gt=now)
    terms = terms.exclude(applies_to__isnull=False, applies_to__lt=now)
    return set(str(term.id) for term in terms)


def _user_has_accepted_all_mandatory_terms(transfer_request: DistributorTransferRequest, user) -> bool:
    mandatory_term_ids = _current_mandatory_term_ids()
    if not mandatory_term_ids:
        return True

    accepted_term_ids = set(
        str(row.terms_id)
        for row in DistributorTransferAcceptance.objects.filter(
            transfer_request=transfer_request,
            accepted_by=user,
            accepted=True,
        )
    )
    return mandatory_term_ids.issubset(accepted_term_ids)

class DistributorIDSerializer(serializers.ModelSerializer):
    transfer_info = serializers.SerializerMethodField()

    class Meta:
        model = DistributorID
        fields = '__all__'

    def get_transfer_info(self, obj):
        request = self.context.get('request')
        if not request or not getattr(request, 'user', None):
            return None

        incoming_map = self.context.get('incoming_transfer_info_by_distributor') or {}
        mapped = incoming_map.get(str(obj.id))
        if mapped is not None:
            return mapped

        history = DistributorTransferHistory.objects.filter(
            distributor=obj,
            new_owner_user=request.user,
        ).select_related('old_owner_user', 'new_owner_user').order_by('-approved_at').first()
        if not history:
            return None

        boundary = history.transfer_reward_boundary_timestamp or history.approved_at
        totals = DistributorRewardOwnershipLedger.objects.filter(
            distributor=obj,
            beneficiary_user=history.old_owner_user,
            reward_timestamp__lte=boundary,
        ).aggregate(total=Sum('amount'))
        pre_transfer_total = totals.get('total')
        return {
            'is_transferred_in': True,
            'from_owner_name': f"{history.old_owner_user.first_name} {history.old_owner_user.last_name}".strip() or history.old_owner_user.email or history.old_owner_user.mobile,
            'to_owner_name': f"{history.new_owner_user.first_name} {history.new_owner_user.last_name}".strip() or history.new_owner_user.email or history.new_owner_user.mobile,
            'transferred_at': history.approved_at,
            'transfer_reward_boundary_timestamp': boundary,
            'pre_transfer_benefit_total_for_old_owner': str(pre_transfer_total or 0),
        }

    def validate(self, data):
        product = data.get('product')
        opportunity_bundle = data.get('opportunity_bundle')
        if not product:
            raise serializers.ValidationError({'product': 'Product is required.'})
        if opportunity_bundle and product.opportunity_bundle and opportunity_bundle != product.opportunity_bundle:
            raise serializers.ValidationError({'opportunity_bundle': 'opportunity_bundle must match product.opportunity_bundle.'})
        sponsor = data.get('sponsor_distributor')
        if sponsor and not DistributorID.objects.filter(id=sponsor.id).exists():
            raise serializers.ValidationError({'sponsor_distributor': 'Sponsor distributor is invalid.'})
        return data


class DistributorTransferRequestCreateSerializer(serializers.Serializer):
    distributor_id = serializers.UUIDField()
    reason = serializers.CharField(required=False, allow_blank=True, default='')
    referral_code = serializers.CharField(required=True, allow_blank=False)
    accepted_term_ids = serializers.ListField(
        child=serializers.UUIDField(),
        required=False,
        default=list,
    )


class DistributorTransferRequestUpdateSerializer(serializers.Serializer):
    reason = serializers.CharField(required=False, allow_blank=True)
    referral_code = serializers.CharField(required=False, allow_blank=False)


class DistributorTransferOldOwnerConsentSerializer(serializers.Serializer):
    accepted_term_ids = serializers.ListField(
        child=serializers.UUIDField(),
        required=False,
        default=list,
    )


class DistributorTransferTermsSerializer(serializers.ModelSerializer):
    class Meta:
        model = DistributorTransferTerms
        fields = [
            'id',
            'title',
            'body',
            'display_order',
            'mandatory',
            'applies_from',
            'applies_to',
            'is_active',
            'created_at',
            'updated_at',
        ]


class DistributorTransferRequestAdminActionSerializer(serializers.Serializer):
    action = serializers.ChoiceField(choices=['approve', 'reject'])
    admin_notes = serializers.CharField(required=False, allow_blank=True, default='')


class DistributorTransferRequestSerializer(serializers.ModelSerializer):
    target_distributor_code = serializers.CharField(source='target_distributor.distributor_code', read_only=True)
    old_owner_name = serializers.SerializerMethodField()
    new_owner_name = serializers.SerializerMethodField()
    new_owner_terms_accepted = serializers.SerializerMethodField()
    old_owner_terms_accepted = serializers.SerializerMethodField()

    class Meta:
        model = DistributorTransferRequest
        fields = [
            'id',
            'target_distributor',
            'target_distributor_code',
            'old_owner_user',
            'requested_new_owner_user',
            'old_owner_name',
            'new_owner_name',
            'new_owner_terms_accepted',
            'old_owner_terms_accepted',
            'reason',
            'referral_code',
            'status',
            'reviewed_by',
            'reviewed_at',
            'admin_notes',
            'created_at',
        ]

    def get_old_owner_name(self, obj):
        user = obj.old_owner_user
        return f"{user.first_name} {user.last_name}".strip() or user.email or user.mobile

    def get_new_owner_name(self, obj):
        user = obj.requested_new_owner_user
        return f"{user.first_name} {user.last_name}".strip() or user.email or user.mobile

    def get_new_owner_terms_accepted(self, obj):
        return _user_has_accepted_all_mandatory_terms(obj, obj.requested_new_owner_user)

    def get_old_owner_terms_accepted(self, obj):
        return _user_has_accepted_all_mandatory_terms(obj, obj.old_owner_user)


class AutoIDAllocationSerializer(serializers.ModelSerializer):
    source_distributor_code = serializers.CharField(source='source_distributor.distributor_code', read_only=True)
    eligible_product_name = serializers.CharField(source='eligible_product.name', read_only=True)

    class Meta:
        model = AutoIDAllocation
        fields = [
            'id',
            'source_distributor',
            'source_distributor_code',
            'level_number',
            'total_count',
            'consumed_count',
            'remaining_count',
            'auto_id_balance',
            'per_auto_id_value',
            'eligible_product',
            'eligible_product_name',
            'status',
            'created_at',
        ]


class AutoIDActivateSerializer(serializers.Serializer):
    allocation_id = serializers.UUIDField()
    count = serializers.IntegerField(min_value=1)
    product_id = serializers.UUIDField(required=False)
