from rest_framework import serializers
from django.db.models import Sum, Count
from .models import *
from locations.serializers import CustomerAddressSerializer
from savings.models import SavingAccount
from savings.serializers import CustomerSavingAccountsSerializer
from locations.models import *
from .helper import get_customer_next_member_number, get_customer_next_old_member_number, generate_member_number
from questbanker_api.utils import get_current_user
from loans.models import *
import re

class CustomerRegFieldOptionSerializer(serializers.ModelSerializer):
    id = serializers.CharField()
    date_added = serializers.CharField(read_only=True)
    customer_reg_field_option = serializers.CharField(read_only=True)
    customer_reg_field_option_added_by = serializers.CharField(read_only=True)
    customer_reg_field_option = serializers.PrimaryKeyRelatedField(read_only=True, required=False)
    
    class Meta:
        model = CustomerRegFieldOption
        fields = '__all__'

class CustomerRegFieldSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    customer_reg_field_added_by = serializers.CharField(read_only=True)
    customer_reg_field_option = CustomerRegFieldOptionSerializer(many=True,read_only=True)
    
    class Meta:
        model = CustomerRegField
        fields = '__all__'

class CustomerTypeRegFieldSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    customer_type_field_added_by = serializers.CharField(read_only=True)
    customer_reg_field = CustomerRegFieldSerializer(read_only=True)
    org_field_type = serializers.CharField(read_only=True, source="customer_reg_field.field_type")
    customer_reg_field_id = serializers.CharField(write_only=True)

    def create(self, validated_data):
        customer_reg_field_id = validated_data.pop('customer_reg_field_id', None)
        new_field = CustomerTypeField.objects.create(**validated_data, customer_reg_field=CustomerRegField.objects.get(pk=customer_reg_field_id))
        return new_field

    class Meta:
        model = CustomerTypeField
        fields = '__all__'

class CustomerTypeSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    customer_type_added_by = serializers.CharField(read_only=True) 
    customer_type_field = serializers.SerializerMethodField(read_only=True) 
    organisation = serializers.CharField(read_only=True)

    class Meta:
        model = CustomerType
        fields = '__all__'
    
    def get_customer_type_field(self, customer_type):
        organisation_id = get_current_user(self.context['request'], 'organisation_id',None) 
        fields = CustomerTypeField.objects.filter(customer_type_field=customer_type, organisation__id=organisation_id).order_by('order')
        return CustomerTypeRegFieldSerializer(fields, many=True).data

class GroupCategorySerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    group_category_added_by = serializers.CharField(read_only=True)
    organisation = serializers.CharField(read_only=True)

    class Meta:
        model = GroupCategory
        fields = '__all__'

    def validate_category_name(self, value):
        category_name = re.sub(r'\s+', ' ', value).strip()
        if not category_name:
            raise serializers.ValidationError("Category name is required.")
        return category_name

    def validate(self, attrs):
        category_name = attrs.get('category_name')
        request = self.context.get('request')

        if not request or not category_name:
            return attrs

        organisation_id = get_current_user(request, 'organisation_id', None)
        queryset = GroupCategory.objects.filter(
            organisation__id=organisation_id,
            category_name=category_name,
        )

        if self.instance:
            queryset = queryset.exclude(pk=self.instance.pk)

        if queryset.exists():
            raise serializers.ValidationError({
                "category_name": "A group category with this name already exists for the current organisation."
            })

        return attrs

class CustomerFieldMetaSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    value = serializers.CharField(read_only=True)
    customer_field = serializers.CharField(read_only=True,source="customer_field.id")
    date_added = serializers.CharField(read_only=True)
    customer_field_added_by = serializers.CharField(read_only=True)
    
    class Meta:
        model = CustomerFieldMeta
        fields = ['value', 'customer_field','id','date_added','customer_field_added_by']

class CustomerFilesSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    added_by = serializers.CharField(read_only=True)

    class Meta:
        model = CustomerFiles
        fields = '__all__'

class CustomerSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    customer_added_by = serializers.CharField(read_only=True)
    customer = CustomerFieldMetaSerializer(many=True,read_only=True)
    customer_branch = serializers.CharField(read_only=True)
    customer_branch_id = serializers.CharField(read_only=True,source="customer_branch.id")
    customer_organisation_id = serializers.CharField(read_only=True,source="customer_branch.branch_organisation.id")
    customer_organisation_name = serializers.CharField(read_only=True,source="customer_branch.branch_organisation.name")
    customer_type_name = serializers.CharField(read_only=True, source="branch_customer_type.customer_type")
    branch_customer_type = serializers.CharField(write_only=True,)
    group_category = serializers.JSONField(write_only=True, required=False, allow_null=True)
    customer_address = CustomerAddressSerializer(many=True, read_only=True)
    customer_type_id = serializers.CharField(read_only=True, source="branch_customer_type.id")
    group_category_id = serializers.CharField(read_only=True, source="group_category.id")
    group_category_name = serializers.CharField(read_only=True, source="group_category.category_name")
    savings_accounts = serializers.SerializerMethodField(read_only=True)
    has_members = serializers.CharField(read_only=True, source="branch_customer_type.has_members")
    customer_files = serializers.SerializerMethodField(read_only=True)
    assigned_group = serializers.SerializerMethodField(read_only=True)
    loans_details = serializers.SerializerMethodField(read_only=True)
    nin = serializers.CharField(required=False, allow_null=True, allow_blank=True, max_length=50)
    # Dropdown compatibility fields for Finwise UI
    full_name = serializers.CharField(read_only=True, source="name")
    account_number = serializers.CharField(read_only=True, source="member_number")
    # Dropdown compatibility fields for Finwise UI
    full_name = serializers.CharField(read_only=True, source="name")
    account_number = serializers.CharField(read_only=True, source="member_number")
    
    class Meta:
        model = Customer
        fields = '__all__'

    def _extract_group_category_id(self):
        group_category = self.initial_data.get('group_category', serializers.empty)

        if group_category is serializers.empty and 'group_category_id' in self.initial_data:
            group_category = self.initial_data.get('group_category_id')

        if group_category in [serializers.empty, None, '', {}]:
            return None

        if isinstance(group_category, dict):
            group_category = group_category.get('id') or group_category.get('group_category_id') or group_category.get('value')

        if group_category in [None, '']:
            return None

        return str(group_category).strip()

    def validate(self, attrs):
        group_category_id = self._extract_group_category_id()

        if group_category_id is None:
            if 'group_category' in self.initial_data or 'group_category_id' in self.initial_data:
                attrs['group_category'] = None
            return attrs

        organisation_id = get_current_user(self.context['request'], 'organisation_id', None)
        group_category = GroupCategory.objects.filter(id=group_category_id, organisation__id=organisation_id).first()

        if not group_category:
            raise serializers.ValidationError({
                "group_category": "Selected group category is invalid for the current organisation."
            })

        attrs['group_category'] = group_category
        return attrs

    def get_assigned_group(self, customer):
        membership = GroupMembership.objects.filter(member=customer).first()
        if membership:
           return {"id":membership.id,"group_id":membership.group.id,"group_name":membership.group.name}
        else:
            return {}
        
    def get_customer_address(self, customer):
        customer_address = CustomerAddress.objects.filter(customer=customer)
        return CustomerAddressSerializer(customer_address ,many=True).data
    
    def get_customer_files(self, customer):
        customer_files = CustomerFiles.objects.filter(customer=customer, is_current=True).all()
        return CustomerFilesSerializer(customer_files, many=True).data

    def get_savings_accounts(self, customer):
        from savings.savings_helper import update_savings_account_statuses
        update_savings_account_statuses(customer_id=customer.id)
        accounts = SavingAccount.objects.filter(account_customer = customer, deleted=False)
        return CustomerSavingAccountsSerializer(accounts, many=True).data
    
    def get_loans_details(self, customer):
        count = LoanApplication.objects.filter(customer=customer, status__in=['disbursed', 'cleared_off','written_off']).count()
        sum_amount = LoanApplication.objects.filter(customer=customer, status__in=['disbursed', 'cleared_off','written_off']).aggregate(total=Sum('loan_amount'))['total']
        
        return {"loan_cysles":count, "total_amount_cycles":sum_amount if sum_amount else 0}

    def create(self, validated_data): 
        registered_by = self.context['request'].user
        customer_type = validated_data.pop('branch_customer_type', None)
        name = re.sub(r'\s+', ' ',validated_data.pop('name'))
        old_member_number = validated_data.pop('member_number', None)
        organisation_branch_id = get_current_user(self.context['request'], 'organisation_branch_id',None) 
        nin = validated_data.pop('nin', None)

        if old_member_number == 'AUTO_GENERATE':
            # generate old member number
            old_member_number = generate_member_number(organisation_branch_id)
        
        member_number = old_member_number
        member_number = re.sub(r'\s+', '', member_number)
        old_member_number = re.sub(r'\s+', '', old_member_number)

        new_customer = Customer.objects.create(**validated_data,name=name, member_number=member_number, old_member_number=old_member_number,  branch_customer_type=CustomerType.objects.get(pk=customer_type), nin=nin, customer_added_by=registered_by)
        new_customer.save()
        return new_customer
    
class CropVarietySerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    crop = serializers.PrimaryKeyRelatedField(read_only=True)
    farmers_count = serializers.IntegerField(read_only=True, default=0)

    class Meta:
        model = CropVariety
        fields = ['id', 'name', 'crop', 'is_active', 'date_added', 'farmers_count']
        validators = []


class CropSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    organisation = serializers.CharField(read_only=True)
    farmers_count = serializers.IntegerField(read_only=True, default=0)
    varieties = serializers.SerializerMethodField()

    class Meta:
        model = Crop
        fields = ['id', 'name', 'organisation', 'is_active', 'date_added', 'varieties', 'farmers_count']
        validators = []

    def get_varieties(self, obj):
        varieties = CropVariety.objects.filter(crop=obj, is_active=True)
        return CropVarietySerializer(varieties, many=True).data


class FarmingHistorySerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    customer = serializers.PrimaryKeyRelatedField(read_only=True)
    customer_name = serializers.CharField(read_only=True, source='customer.name')
    customer_member_number = serializers.CharField(read_only=True, source='customer.member_number')
    is_group = serializers.BooleanField(read_only=True, source='customer.branch_customer_type.has_members')
    activity_type_display = serializers.CharField(read_only=True, source='get_activity_type_display')
    group_member_count = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = FarmingHistory
        fields = ['id', 'customer', 'customer_name', 'customer_member_number', 'is_group',
                  'group_member_count', 'year', 'season', 'activity_type', 'activity_type_display',
                  'activity_data', 'total_sales', 'total_investment', 'profit', 'roi', 'date_added']

    def get_group_member_count(self, obj):
        if obj.customer.branch_customer_type.has_members:
            return GroupMembership.objects.filter(group=obj.customer, active=True).count()
        return None


class CustomerMembershipSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    group_name = serializers.CharField(read_only=True, source="group.name")
    group = serializers.PrimaryKeyRelatedField(read_only=True, required=False)
    member = CustomerSerializer(read_only=True)

    class Meta:
        model = GroupMembership
        fields = '__all__'


class GroupCategoryMemberSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    customer_type_id = serializers.CharField(read_only=True, source="branch_customer_type.id")
    customer_type_name = serializers.CharField(read_only=True, source="branch_customer_type.customer_type")
    customer_branch_id = serializers.CharField(read_only=True, source="customer_branch.id")
    group_category = GroupCategorySerializer(read_only=True)
    group_category_id = serializers.CharField(read_only=True, source="group_category.id")
    group_category_name = serializers.CharField(read_only=True, source="group_category.category_name")

    class Meta:
        model = Customer
        fields = [
            'id',
            'name',
            'member_number',
            'old_member_number',
            'telephone',
            'status',
            'date_added',
            'customer_branch_id',
            'customer_type_id',
            'customer_type_name',
            'group_category',
            'group_category_id',
            'group_category_name',
        ]


class FinwiseGroupCustomerSerializer(serializers.ModelSerializer):
    """
    Serializer for Finwise group customers with participant count
    Returns only group customers whose organization has adminID = 'finwise' (org_id=139)
    """
    id = serializers.CharField(read_only=True)
    name = serializers.CharField(read_only=True)
    member_number = serializers.CharField(read_only=True)
    telephone = serializers.CharField(read_only=True)
    customer_type_name = serializers.CharField(read_only=True, source="branch_customer_type.customer_type")
    organisation_id = serializers.CharField(read_only=True, source="customer_branch.branch_organisation.id")
    organisation_name = serializers.CharField(read_only=True, source="customer_branch.branch_organisation.name")
    branch_id = serializers.CharField(read_only=True, source="customer_branch.id")
    branch_name = serializers.CharField(read_only=True, source="customer_branch.name")
    participant_count = serializers.SerializerMethodField(read_only=True)
    date_added = serializers.CharField(read_only=True)

    class Meta:
        model = Customer
        fields = [
            'id', 'name', 'member_number', 'telephone', 'customer_type_name',
            'organisation_id', 'organisation_name', 'branch_id', 'branch_name',
            'participant_count', 'date_added', 'status'
        ]

    def get_participant_count(self, obj):
        """Return the count of active participants in this group"""
        return GroupMembership.objects.filter(group=obj, active=True).count()
