from rest_framework import viewsets, status
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from .models import *
from .serializers import *
from questbanker_api.utils import get_current_user
from exservices.models import OrganisationSmsSubscription,MemberSmsSubscription
from exservices.exservices_helper import send_customer_sms,send_mm_pin
from mmbanking.models import MobileBankingSubscription
from .helper import get_customer_custom_fields_meta,get_customer_next_member_number
from savings.savings_helper import generate_saving_account_code, get_savings_account_initial_state, save_sender_transactions, save_reciever_transactions
from savings.savings_bal_helper import get_account_balance
from ledgers.models import InterBranchTransactions
from savings.models import SavingsProduct, TransferTransactions, FixedDeposit, SavingsBlockedAmount, SchoolFeesIntegrations
from general.helper import date_time_zone_convert
import json
from django.http import Http404
from django.db.models import Q, Count
import random
from users.audit_log_helper import add_system_audit_trail
from notifications.notifications_helper import *
from datetime import datetime

class CustomerTypesViewSet(viewsets.ModelViewSet):
    '''
    List all customer types
    '''
    serializer_class = CustomerTypeSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['customer_type', ]
    search_fields = ('customer_type', )
    ordering_fields = ['customer_type', ]

    def perform_create(self, serializer):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        organisation = Organisation.objects.filter(id=organisation_id).first()
        instance = serializer.save(customer_type_added_by=self.request.user, organisation=organisation)

    def get_queryset(self):
        
        organisation_id = get_current_user(self.request, 'organisation_id', None)

        return CustomerType.objects.filter(organisation__id=organisation_id).order_by('id')

class GroupCategoriesViewSet(viewsets.ModelViewSet):
    '''
    List all group categories
    '''
    serializer_class = GroupCategorySerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['category_name', ]
    search_fields = ('category_name', )
    ordering_fields = ['category_name', ]

    def perform_create(self, serializer):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        organisation = Organisation.objects.filter(id=organisation_id).first()
        serializer.save(group_category_added_by=self.request.user, organisation=organisation)

    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return GroupCategory.objects.filter(organisation__id=organisation_id).order_by('id')

class CustomerRegistrationFieldsViewSet(viewsets.ModelViewSet):
    '''
    List all customer registration fields
    POST
    {
    "customer_reg_field_option": [{"field_option_label":"Male","field_option_value":"M"},{"field_option_label":"Female","field_option_value":"F"}],
    "field_label": "Gender",
    "field_type": "radio",
    "field_abbreviation": "Gender"
    }
    '''
    serializer_class = CustomerRegFieldSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['field_label', ]
    search_fields = ('field_label', )
    ordering_fields = ['field_label', ]
    # queryset = YourModel.objects.all()
    # pagination_class = None

    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', 1)
        filter_by = self.request.GET.get('customer_type_field', None)
        customer_type = self.request.GET.get('customer_type', None)
        
        if filter_by and filter_by == 'false':
            # filter for the fields not assigned to the current organisation customer type
            return CustomerRegField.objects.exclude(pk__in=[x.customer_reg_field.pk for x in CustomerTypeField.objects.filter(customer_type_field=customer_type,organisation__id=organisation_id)])
        return CustomerRegField.objects.all()
    
    def perform_create(self, serializer):
        request_data = self.request.data
        fields_options_data = request_data.get('customer_reg_field_option', None)
        registered_by =self.request.user
        new_field  = serializer.save(customer_reg_field_added_by=registered_by)
        if fields_options_data:
            for field_option in fields_options_data:
                fields_option = {
                    "field_option_label":field_option['field_option_label'],
                    "field_option_value":field_option['field_option_value']
                }
                CustomerRegFieldOption.objects.create(customer_reg_field_option=new_field, **fields_option, customer_reg_field_option_added_by=registered_by)
        return Response({'message': 'Saving product interest successfully created'}, status=status.HTTP_200_OK)

    def perform_update(self, serializer):
        request_data = self.request.data
        id = request_data.get('id', None)
        action = request_data.get('action', None)
        fields_options_data = request_data.get('customer_reg_field_option', None)
        if action == 'delete':
            CustomerRegField.objects.get(pk=id).delete()
        else:
            registered_by =self.request.user
            updated_options = []
            custom_reg_field = serializer.save()
            if fields_options_data:
                for fields_option_data in fields_options_data:
                    if int(fields_option_data['id']) > 0:
                        option_instance =  CustomerRegFieldOption.objects.get(pk=int(fields_option_data['id']))
                        if option_instance:
                            option_instance.field_option_label = fields_option_data['field_option_label']
                            option_instance.field_option_value = fields_option_data['field_option_value']
                            option_instance.save() 
                            updated_options.append(fields_option_data['id'])

                    if int(fields_option_data['id']) == 0:
                        fields_option = {
                            "field_option_label":fields_option_data['field_option_label'],
                            "field_option_value":fields_option_data['field_option_value']
                        }
                        option_instance = CustomerRegFieldOption.objects.create(customer_reg_field_option=custom_reg_field, **fields_option, customer_reg_field_option_added_by=registered_by)
                        updated_options.append(option_instance.id)

            if len(updated_options) > 0:
                option_instances =  CustomerRegFieldOption.objects.filter(customer_reg_field_option=custom_reg_field).exclude(id__in=updated_options)
                if option_instances:
                    for option_instance in option_instances:
                        option_instance.delete()


class CustomerTypeRegFieldsViewSet(viewsets.ModelViewSet):
    '''
    List all customer type registration fields
    '''
    queryset = CustomerTypeField.objects.all()
    serializer_class = CustomerTypeRegFieldSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['org_field_label', ]
    search_fields = ('org_field_label', )
    ordering_fields = ['org_field_label', ]

    def perform_create(self, serializer):
        instance = serializer.save(
            customer_type_field_added_by=self.request.user)


class CustomersViewSet(viewsets.ModelViewSet):
    '''
    List all customers
    POST
    {
        "customer": [{"customer_field":1,"value":"123456"}],
        "name": "Demo Test",
        "member_number": "123456",
        "old_member_number": "",
        "status": "",
        "customer_branch": 1
    }
    '''
    
    serializer_class = CustomerSerializer
    filter_backends  = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['member_number','name', 'old_member_number', 'branch_customer_type','customer_branch', 'group_category']
    search_fields    = ['member_number','name', 'old_member_number']
    ordering_fields  = ['name', 'member_number']
  
    
    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None) 
        search = self.request.GET.get('search', None)
        finwise_only = self.request.GET.get('finwise_only', 'false')
        source_customer_type_id = self.request.GET.get('source_customer_type_id', None)
        old_member_number = self.request.GET.get('old_member_number', None)
        has_members = self.request.GET.get('has_members', None)
        date_added = self.request.GET.get('date_added', None)
        start_date = self.request.GET.get('start_date', None)
        customer_filter = {"customer_branch__branch_organisation":Organisation.objects.get(pk=organisation_id),"is_deleted":False}
        filter = self.request.GET.get('filter',None)

        if filter and filter == 'all':
            return Customer.objects.filter(customer_branch__branch_organisation = organisation_id, is_deleted=False)
        if old_member_number:
            return Customer.objects.filter(**{"customer_branch__branch_organisation":Organisation.objects.get(pk=organisation_id),"old_member_number":old_member_number})
        
        # get customers of customer types [groups] whose customer source is customer_type_id  
        if source_customer_type_id:
            customer_filter['branch_customer_type__source_client_type'] = source_customer_type_id
        
        if has_members:
            customer_filter['branch_customer_type__has_members'] = has_members
        
        if date_added:
            customer_filter['date_added__date__lte'] = date_added
            
        if start_date:
            customer_filter['date_added__date__gte'] = start_date

        qs = Customer.objects.filter(**customer_filter)

        # Optional explicit Finwise-only flag (by organisation name)
        if finwise_only and finwise_only.lower() == 'true':
            qs = qs.filter(customer_branch__branch_organisation__name__icontains='finwise')

        # Search over name(full_name) and member_number(account_number)
        if search:
            qs = qs.filter(Q(name__icontains=search) | Q(member_number__icontains=search))

        return qs.order_by('member_number')

    def list(self, request, *args, **kwargs):
        # Support page_size=all by bypassing pagination with an upper cap
        page_size = request.GET.get('page_size')
        queryset = self.filter_queryset(self.get_queryset())

        if page_size and page_size.lower() == 'all':
            queryset = queryset[:1000]
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)

        return super().list(request, *args, **kwargs)
      
    
       
    def perform_create(self, serializer):
        request_data    = self.request.data
        savings_product = request_data.get('savings_product', None)
        send_sms        = request_data.get('send_sms',False)
        subscribe       = request_data.get('subscribe',False)
        customer_metas  = request_data.get('customer',False)
        branch_id       = get_current_user(self.request, 'organisation_branch_id', None)
        branch          = OrganisationBranch.objects.get(pk=branch_id)
        nin = request_data.get('nin', None)


        
        nationality = request_data.get('nationality') or "Ugandan"
        organisation_branch_id = get_current_user(self.request, 'organisation_branch_id', 1) 
        
        organisation_branch    = OrganisationBranch.objects.get(pk=organisation_branch_id)
        saved_customer = serializer.save(customer_branch=organisation_branch, nationality=nationality, nin=nin)

        if saved_customer:
          if customer_metas:
            for customer_meta in customer_metas:
                customer_meta = {"customer":saved_customer,"customer_field_id":customer_meta["customer_field"],"value":customer_meta["value"],"customer_field_added_by":self.request.user}
                save_meta_data = CustomerFieldMeta.objects.create(**customer_meta) 
                if save_meta_data:
                    if save_meta_data.customer_field.customer_reg_field.id == 82:
                        data = {"school_code":save_meta_data.value, "school_name":save_meta_data.customer.name, "school_organisation":organisation_branch.branch_organisation, "customer":save_meta_data.customer}
                        SchoolFeesIntegrations.objects.create(**data)
        
            self.update_customer_location(saved_customer,request_data,branch)
            self.create_default_savings_account(saved_customer,savings_product,organisation_branch,self.request.user)
            if subscribe:
                self.auto_subscribe_to_sms_banking(saved_customer,organisation_branch,self.request.user)
            if send_sms:
                self.send_customer_welcome_sms(saved_customer,organisation_branch,self.request.user)
                self.send_customer_mmbanking_sms(saved_customer)
           
    def perform_update(self, serializer):
        print("**************************************************** Where are you 1. ")
        request_data = self.request.data
        is_deleted   = request_data.get('is_deleted', False)
        is_change    = request_data.get('is_change', False)
        branch_customer_type = request_data.get('branch_customer_type_id', None)
        branch_id   = get_current_user(self.request, 'organisation_branch_id', None)
        branch      = OrganisationBranch.objects.get(pk=branch_id)
        customer_id = self.kwargs.get('pk',self.kwargs.get('id'))
        print("**************************************************** Where are you 1. ")
        customer    = Customer.objects.get(pk=customer_id)
        # customer = Customer.objects.filter(pk=customer_id).order_by('id').first()
        old_details = CustomerSerializer(customer,read_only=True).data
        reason      = ''
        action_perform = ''
        saved_customer = serializer.save()
        
        if is_change == True:
            saved_customer.branch_customer_type_id = branch_customer_type
            saved_customer.save()

        if is_deleted == True:
            saved_customer.is_deleted = is_deleted
            saved_customer.save()
            message = f'Deleted customer details for: {saved_customer.name} ({saved_customer.member_number})'
            add_system_audit_trail('customer_management','delete_customer',message,'',old_details,{},self.request.user,branch)
            self.delete_customer_accounts(saved_customer,branch)

        if is_change == False and is_deleted == False:
            saved_customer.name   = re.sub(r'\s+', ' ',request_data.get('name'))
            saved_customer.status   = re.sub(r'\s+', ' ',request_data.get('status'))
            saved_customer.old_member_number = re.sub(r'\s+', ' ',request_data.get('old_member_number'))
            saved_customer.save()

            self.update_customer_meta_fields(saved_customer,request_data,self.request.user,branch)
            action_perform = 'update_customer'
            message = f'Updated customer for: {saved_customer.name} ({saved_customer.member_number})'
            new_details = CustomerSerializer(Customer.objects.get(pk=customer_id),read_only=True).data
            add_system_audit_trail('customer_management',action_perform,message,reason,old_details,new_details,self.request.user,branch)
        
    def auto_subscribe_to_sms_banking(self,customer,organisation_branch,user):
        if customer:
            org_subs = OrganisationSmsSubscription.objects.filter(organisation__id=organisation_branch.branch_organisation.id, is_subscribed=True)
            if org_subs:
                for org_sub in org_subs:
                    member_sms_sub = MemberSmsSubscription.objects.filter(
                        org_subscription=org_sub, customer=customer).first()
                    if member_sms_sub:
                        member_sms_sub.is_subscribed = True
                        member_sms_sub.save()
                    if not member_sms_sub:
                        data = {"customer": customer, "org_subscription": org_sub, "sub_added_by":user,
                                "sub_last_updated_by":user, "is_subscribed": True}
                        MemberSmsSubscription.objects.create(**data)

    def send_customer_mmbanking_sms(self,customer):
        # Generate pin of length 4
        pin = random.randint(pow(10, 3), pow(10, 4) - 1)
        data = {"customer": customer, "telephone_no": customer.telephone,"pin":pin,"active":True,"added_by":customer.customer_added_by}
        subscription = MobileBankingSubscription.objects.create(**data)
        if subscription:
            sms_text = "Dear "+subscription.customer.name.capitalize()+", Welcome to "+subscription.customer.customer_branch.branch_organisation.name.upper() + \
                " mobile banking\n Dial *284*55#. Access MEM NO: " + \
                subscription.customer.member_number+" PIN: "+str(pin)
            send_mm_pin(subscription, sms_text,self.request.user)

    
    def send_customer_welcome_sms(self,customer,organisation_branch,user):
        if customer:
            org_sub = OrganisationSmsSubscription.objects.filter(
                sms_type__sms_type_key='welcome_sms', organisation__id=organisation_branch.branch_organisation.id, is_subscribed=True).first()
            if org_sub:
                member_sms_sub = MemberSmsSubscription.objects.filter(
                    org_subscription=org_sub, customer=customer).first()
                if not member_sms_sub:
                    data = {"customer": customer, "org_subscription": org_sub, "sub_added_by":user,
                            "sub_last_updated_by":user, "is_subscribed": True}
                    MemberSmsSubscription.objects.create(**data)
                sms_msg = 'Dear '+customer.name.capitalize() +', Welcome to '+organisation_branch.branch_organisation.short_name+ ',\n your account has been successfully registered'
                data    = {"sms_key":"welcome_sms","customer":customer,"user":user,"branch_id":organisation_branch.id,"sms_msg":sms_msg}
                send_customer_sms(data)


    def create_default_savings_account(self,customer,savings_product,organisation_branch,user):
        if customer:
           # Create customer savings Account
            if savings_product and int(savings_product) > 0:
                account_product = SavingsProduct.objects.get(pk=savings_product)
                initial_state = get_savings_account_initial_state(account_product)
                SavingAccount.objects.create(
                    account_no=generate_saving_account_code(organisation_branch.id),
                    account_customer=customer,
                    account_product=account_product,
                    customer_branch=organisation_branch,
                    status=initial_state['status'],
                    is_active=initial_state['is_active'],
                    saving_account_added_by=user,
                    opened_by=user.user_staff,
                    saving_account_last_updated_by=user
                )
            else:
                # Get default savings product
                savings_product = OrganisationSetting.objects.filter(org_setting__id = organisation_branch.branch_organisation.id,setting_key ="savings_product").first()
                if savings_product:
                    if len(savings_product.setting_value) > 0:
                        account_product = SavingsProduct.objects.get(pk=savings_product.setting_value)
                        initial_state = get_savings_account_initial_state(account_product)
                        SavingAccount.objects.create(
                            account_no=generate_saving_account_code(organisation_branch.id),
                            account_customer=customer,
                            account_product=account_product,
                            customer_branch=organisation_branch,
                            status=initial_state['status'],
                            is_active=initial_state['is_active'],
                            saving_account_added_by=user,
                            opened_by=user.user_staff,
                            saving_account_last_updated_by=user
                        )


    def update_customer_meta_fields(self,updated_customer,request_data,user,branch):
        print("**************************************************** Where are you 2. ")
        old_details = {}
        new_details = {}
        if updated_customer:
            customer_meta_datas   = request_data.get('customer')
            if customer_meta_datas:
                for customer_meta_data in customer_meta_datas:
                    customer_field = CustomerFieldMeta.objects.filter(customer_field__id=customer_meta_data['customer_field'], customer=updated_customer).first()
                    if customer_field:
                        old_details[customer_field.customer_field.org_field_label] = customer_field.value
                        customer_field.value  = customer_meta_data['value']
                        customer_field.save()
                        new_field = CustomerFieldMeta.objects.get(pk=customer_field.id)
                        new_details[new_field.customer_field.org_field_label] = new_field.value

                        if new_field.customer_field.customer_reg_field.id == 82:
                            school_fees_integration = SchoolFeesIntegrations.objects.filter(customer=new_field.customer, school_organisation=new_field.customer.customer_branch.branch_organisation).first()
                            if school_fees_integration:
                                school_fees_integration.school_code = new_field.value
                                school_fees_integration.school_name = new_field.customer.name
                                school_fees_integration.save()
                    else:
                        new_field = CustomerFieldMeta.objects.create(customer_field=CustomerTypeField.objects.get(pk=customer_meta_data['customer_field']),value = customer_meta_data['value'], customer=updated_customer, customer_field_added_by=user)
                        if new_field:
                            school_fees_integration = SchoolFeesIntegrations.objects.filter(customer=new_field.customer, school_organisation=new_field.customer.customer_branch.branch_organisation).first()
                            if school_fees_integration:
                                school_fees_integration.school_code = new_field.value
                                school_fees_integration.school_name = new_field.customer.name
                                school_fees_integration.save()
                            else:
                                data = {"school_code":new_field.value, "school_name":new_field.customer.name, "school_organisation":new_field.customer.customer_branch.branch_organisation, "customer":new_field.customer}
                                SchoolFeesIntegrations.objects.create(**data)
        if old_details:
            message = f'Updated customer details for: {updated_customer.name} ({updated_customer.member_number})'
            add_system_audit_trail('customer_management','update_customer',message,'',old_details,new_details,self.request.user,branch)
    
    def delete_customer_accounts(self,instance,branch):
            accounts = SavingAccount.objects.filter(account_customer = instance)
            for account in accounts:
                old_details = CustomerSavingAccountsSerializer(account,read_only=True).data
                message = f'Deleted Saving Account: {account.account_no} For Customer: {account.account_customer.name}'
                add_system_audit_trail('savings','delete_savings_account',message,'',old_details,{},self.request.user,branch)
                account.deleted = True
                account.save()
    

    def update_customer_location(self,instance,request_data,branch):
        print("**************************************************** Where are you 3. ")
        updated_addr = request_data.get('updated_address',None)
        if updated_addr:
            village_id    = updated_addr['village']
            villagename   = updated_addr['villagename']
            parish_id     = updated_addr['parish']
            parishname    = updated_addr['parishname']
            subcounty_id  = updated_addr['subcounty']
            subcountyname = updated_addr['subcountyname']
            county_id     = updated_addr['county']
            county_name   = updated_addr['countyname']
            district_id   = updated_addr['district']
            district_name = updated_addr['districtname']
            village       = None
            physical_address = updated_addr['physical_address']

            if district_id == None and district_name:
                saved_district = District.objects.create(districtname = district_name)
                if saved_district:
                    district_id = saved_district.id

            if district_id:
                if county_id == None and county_name:
                    saved_county = County.objects.create(district=District.objects.get(pk=district_id),countyname = county_name)
                    if saved_county:
                        county_id = saved_county.id

            if county_id:
                if subcounty_id == None and subcountyname:
                    saved_subcounty= SubCounty.objects.create(
                        county   = County.objects.get(pk=county_id),
                        subcountyname = subcountyname,
                        is_verified = False      
                    )
                    if saved_subcounty:
                        subcounty_id = saved_subcounty.id

            if parish_id == None and subcounty_id and parishname:
                saved_parish = Parish.objects.create(
                    subcounty   = SubCounty.objects.get(pk=subcounty_id),
                    parishname  = parishname,
                    is_verified = False      
                )
                if saved_parish:
                    parish_id = saved_parish.id

            if village_id == None and parish_id and villagename:
                saved_village = Village.objects.create(
                    parish  = Parish.objects.get(pk=parish_id),
                    villagename = villagename,
                    is_verified = False     
                )
                if saved_village:
                    village_id = saved_village.id

            if village_id:
                village = Village.objects.filter(id=village_id).first()
                
            # customer_address = CustomerAddress.objects.filter(customer=instance).first()
            customer_address = CustomerAddress.objects.filter(customer=instance).order_by("id").first()

            if customer_address:
                old_details = CustomerAddressSerializer(customer_address,read_only=True).data
                customer_address.village = village
                customer_address.parish = parish_id
                customer_address.subcounty = subcounty_id
                customer_address.county   = county_id
                customer_address.district = district_id
                customer_address.physical_address = physical_address
                customer_address.address_added_by = self.request.user
                customer_address.save()
                new_details = CustomerAddressSerializer(CustomerAddress.objects.get(pk=customer_address.id),read_only=True).data
                message = f'Updated Location For Customer: {instance.name}'
                add_system_audit_trail('customer_management','update_customer_location',message,'',old_details,new_details,self.request.user,branch)
            else:
                CustomerAddress.objects.create(customer=instance,village=village,parish=parish_id,subcounty=subcounty_id,county = county_id,district = district_id,address_added_by=self.request.user,physical_address=physical_address)

class GroupOrgCustomerRegFieldsViewSet(APIView):
    ''' For grouping organisation customer registration fiels'''

    def get(self, request, format=None):
        # filter by organisation
        response = []
        organisation_id = get_current_user(self.request, 'organisation_id', None)   
        organisation = Organisation.objects.get(pk=organisation_id)  
        customer_types = CustomerType.objects.filter(organisation=organisation).order_by('id')
        for customer_type in customer_types:
            fields_obj = []
            customer_type_fields = CustomerTypeField.objects.filter(
                customer_type_field=customer_type, organisation=organisation).order_by('id')
            for customer_type_field in customer_type_fields:
                fields_obj.append(
                    {
                        "id": customer_type_field.id,
                        "org_field_label": customer_type_field.org_field_label,
                        "org_field_abbreviation": customer_type_field.org_field_abbreviation,
                        "required": customer_type_field.required,
                        "order": customer_type_field.order,
                        "section": customer_type_field.section,
                        "field_label":customer_type_field.customer_reg_field.field_label,
                        "field_abbreviation":customer_type_field.customer_reg_field.field_abbreviation,
                        "is_active":customer_type_field.is_active
                    })
            response.append({"customer_type": customer_type.customer_type,
                            "id": customer_type.id,
                            "has_members":customer_type.has_members,
                            "source_client_type":customer_type.source_client_type,
                            "fields": fields_obj,
                            })

        return Response({"results": response, "count": len(response)})


class CustomerRegFieldOptionsViewSet(viewsets.ModelViewSet):
    '''
    Customer reg field Options
    '''
    queryset = CustomerRegFieldOption.objects.all()
    serializer_class = CustomerRegFieldOptionSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['field_option_label', ]
    search_fields = ('field_option_label', )
    ordering_fields = ['field_option_label', ]

    def perform_create(self, serializer):
        customer_reg_field = self.request.GET.get('customer_reg_field_id', None)
        if customer_reg_field:
            field = CustomerRegField.objects.filter(id= customer_reg_field).first()
            if field:
                instance = serializer.save(customer_reg_field_option=field,
                    customer_reg_field_option_added_by=self.request.user)
                
                return instance
        raise Http404

class GroupMembersViewSet(viewsets.ModelViewSet):
    serializer_class = CustomerMembershipSerializer
    http_method_names = ['get', 'post', 'patch']

    def get_queryset(self):
        member   = self.request.GET.get('member', None)
        group_id = self.request.GET.get('group', None)
        search   = self.request.GET.get('search', None)
        active   = self.request.GET.get('active', None)

        query_filter = {}
        if active:
           query_filter['active'] = active 
        if group_id:
           query_filter['group__id'] = group_id
        if member:
            query_filter['member__id'] = member
        
        if search:
            return GroupMembership.objects.filter(Q(member__name__icontains=search) | Q(member__member_number__icontains=search)| Q(member__old_member_number__icontains=search),**query_filter)
        else:
            return GroupMembership.objects.filter(**query_filter)
    

    def perform_create(self, serializer):
        group = self.request.data.get('group')
        members = self.request.data.get('members')

        if members:
            members = json.loads(members)
            
            for member in members:
                role = member['role']
                member_id = member['id']
                exists = GroupMembership.objects.filter(group_id=group, member_id=member_id)
                if len(exists) > 0:
                    member = exists[0]
                    member.role = role
                    member.active = True
                    member.added_by_id = self.request.user.id
                else:
                    member= GroupMembership.objects.filter(member_id=member_id).first()
                    if member:
                        member.role = role
                        member.active = True
                        member.group = Customer.objects.get(pk = group)
                    else: 
                        if member_id != group:
                            member = GroupMembership(group_id=group, member_id=member_id, role=role, added_by_id=self.request.user.id)
                
                # Save membership
                member.save()


class GroupCategoryMembersViewSet(viewsets.ModelViewSet):
    serializer_class = GroupCategoryMemberSerializer
    http_method_names = ['get', 'post', 'patch']

    def _base_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return Customer.objects.filter(
            customer_branch__branch_organisation__id=organisation_id,
            is_deleted=False,
        ).select_related('group_category', 'branch_customer_type', 'customer_branch')

    def _is_truthy(self, value):
        return str(value).strip().lower() in ['1', 'true', 'yes', 'y', 'on']

    def _extract_group_category_id(self, request_data):
        group_category = request_data.get('group_category', None)

        if group_category is None and 'group_category_id' in request_data:
            group_category = request_data.get('group_category_id')

        if group_category in [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 _extract_customer_ids(self, request_data):
        members = request_data.get('members', None)

        if members in [None, '']:
            members = request_data.get('customers', None)
        if members in [None, '']:
            members = request_data.get('member', None)
        if members in [None, '']:
            members = request_data.get('customer', None)

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

        if isinstance(members, str):
            try:
                members = json.loads(members)
            except (TypeError, ValueError):
                members = [members]

        if not isinstance(members, list):
            members = [members]

        customer_ids = []
        for member in members:
            customer_id = member
            if isinstance(member, dict):
                customer_id = member.get('id') or member.get('customer') or member.get('customer_id') or member.get('member') or member.get('member_id') or member.get('value')

            if customer_id in [None, '', {}]:
                continue

            customer_ids.append(str(customer_id).strip())

        return list(dict.fromkeys(customer_ids))

    def _get_group_category(self, group_category_id):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return GroupCategory.objects.filter(id=group_category_id, organisation__id=organisation_id).first()

    def _should_clear_assignment(self, request_data):
        action = str(request_data.get('action', '')).strip().lower()
        remove = request_data.get('remove', None)

        if action in ['remove', 'delete', 'clear', 'unassign']:
            return True

        if remove is not None and self._is_truthy(remove):
            return True

        if ('group_category' in request_data or 'group_category_id' in request_data) and self._extract_group_category_id(request_data) is None:
            return True

        return False

    def get_queryset(self):
        customer_id = self.request.GET.get('customer', None) or self.request.GET.get('member', None)
        group_category_id = self.request.GET.get('group_category', None) or self.request.GET.get('group_category_id', None)
        search = self.request.GET.get('search', None)
        assigned = self.request.GET.get('assigned', None)

        queryset = self._base_queryset()

        if customer_id:
            queryset = queryset.filter(id=customer_id)

        if group_category_id:
            queryset = queryset.filter(group_category__id=group_category_id)

        if assigned is not None:
            queryset = queryset.filter(group_category__isnull=not self._is_truthy(assigned))
        elif not customer_id and not group_category_id:
            queryset = queryset.filter(group_category__isnull=False)

        if search:
            queryset = queryset.filter(
                Q(name__icontains=search) |
                Q(member_number__icontains=search) |
                Q(old_member_number__icontains=search) |
                Q(group_category__category_name__icontains=search)
            )

        return queryset.order_by('name', 'member_number')

    def get_object(self):
        customer_id = self.kwargs.get(self.lookup_field)
        customer = self._base_queryset().filter(pk=customer_id).first()

        if not customer:
            raise Http404

        self.check_object_permissions(self.request, customer)
        return customer

    def create(self, request, *args, **kwargs):
        group_category_id = self._extract_group_category_id(request.data)
        if not group_category_id:
            return Response(
                {"message": "group_category or group_category_id is required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        group_category = self._get_group_category(group_category_id)
        if not group_category:
            return Response(
                {"message": "Selected group category is invalid for the current organisation."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        customer_ids = self._extract_customer_ids(request.data)
        if not customer_ids:
            return Response(
                {"message": "At least one customer is required. Send members/customers or member/customer."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        customers = self._base_queryset().filter(id__in=customer_ids)
        existing_customer_ids = {str(customer_id) for customer_id in customers.values_list('id', flat=True)}
        invalid_customer_ids = [customer_id for customer_id in customer_ids if customer_id not in existing_customer_ids]

        if invalid_customer_ids:
            return Response(
                {
                    "message": "Some customers were not found for the current organisation.",
                    "invalid_customers": invalid_customer_ids,
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        customers.update(group_category=group_category)
        updated_customers = self._base_queryset().filter(id__in=customer_ids).order_by('name', 'member_number')

        return Response(
            {
                "message": "Group category assigned successfully.",
                "count": updated_customers.count(),
                "results": self.get_serializer(updated_customers, many=True).data,
            },
            status=status.HTTP_200_OK,
        )

    def partial_update(self, request, *args, **kwargs):
        customer = self.get_object()

        if self._should_clear_assignment(request.data):
            customer.group_category = None
            customer.save(update_fields=['group_category'])
            return Response(
                {
                    "message": "Group category assignment removed successfully.",
                    "result": self.get_serializer(customer).data,
                },
                status=status.HTTP_200_OK,
            )

        group_category_id = self._extract_group_category_id(request.data)
        if not group_category_id:
            return Response(
                {"message": "group_category or group_category_id is required. Send null or action=remove to unassign."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        group_category = self._get_group_category(group_category_id)
        if not group_category:
            return Response(
                {"message": "Selected group category is invalid for the current organisation."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        customer.group_category = group_category
        customer.save(update_fields=['group_category'])

        return Response(
            {
                "message": "Group category assignment updated successfully.",
                "result": self.get_serializer(customer).data,
            },
            status=status.HTTP_200_OK,
        )


class CustomerFilesViewSet(viewsets.ModelViewSet):
    '''
    List all customer files
    '''
    queryset = CustomerFiles.objects.filter(is_current=True).order_by('id')
    serializer_class = CustomerFilesSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['id', ]
    search_fields = ('id', )
    ordering_fields = ['id', ]

    def perform_create(self, serializer):
        instance = serializer.save(added_by=self.request.user)
        customer_files = CustomerFiles.objects.filter(file_type=instance.file_type, customer= instance.customer).all()
        for customer_file in customer_files:
            if customer_file.id != instance.id:
                customer_file.is_current = False
                customer_file.save()

    def perform_destroy(self, instance):
        instance.is_current = False
        instance.save(update_fields=['is_current'])


class CustomerRegFieldsMetaDataViewSet(APIView):
    ''' Get customer custom fields with data'''

    def get(self, request, format=None):
        customer = request.GET.get('customer', None)
        if not customer:
            return  Response({"message":"No customer sent"})
        
        customer_obj = Customer.objects.filter(id=customer).first()
        if not customer_obj:
            return  Response({"message":"No customer found"})
        
        data = get_customer_custom_fields_meta(customer_obj)
        return Response({"results":data, "count":len(data)})


class CustomerAccountsTransferViewSet(APIView):
    ''' Manage customer accounts transfer'''

    def post(self, request, format=None):
        print("********************** staring to transfer 1. ***********************")
        transfer_mode = request.data.get("transferMode", 'info')
        customers = request.data.get("customers", [])
        destination_branch = request.data.get("destinationBranch", None)
        source_branch = request.data.get("sourceBranch", None)
        organisation_id = get_current_user(self.request, 'organisation_id', None)

        # validate source branch
        if not source_branch:
            return  Response({"message":"No source branch found"})

        branch = OrganisationBranch.objects.filter(id=source_branch).first()
        if not branch:
            return  Response({"message":"No source branch found with this id"})
        
        if int(branch.branch_organisation.id) != int(organisation_id):
            return  Response({"message":"Source Branch doesnot belong to your organisation"})
            
        # validate destination branch
        if not destination_branch:
            return  Response({"message":"No destination branch found"})

        branch = OrganisationBranch.objects.filter(id=destination_branch).first()
        if not branch:
            return  Response({"message":"No destination branch found with this id"})

        if int(branch.branch_organisation.id) != int(organisation_id):
            return  Response({"message":"Destination Branch doesnot belong to your organisation"})

        if transfer_mode == 'info_only':
            Customer.objects.filter(id__in=customers).update(customer_branch=branch)
            print("********************** staring to transfer 2. ***********************")

        else:
            for customer_id in customers:
                print("********************** staring to transfer 3. ***********************")
                Customer.objects.filter(id=customer_id).update(customer_branch=branch)
                savingaccounts = SavingAccount.objects.filter(account_customer__id=customer_id, deleted=False, is_active=True, customer_branch__id=source_branch).order_by('id')
                for savingaccount in savingaccounts:
                    transfer_to_account = None
                    print("********************** staring to transfer 4. ***********************")

                    # account balance
                    today = timezone.now()
                    # acc_bal = get_account_balance(savingaccount, today.strftime('%Y-%m-%d'))['balance_actual']balance_raw
                    acc_bal = get_account_balance(savingaccount, today.strftime('%Y-%m-%d'))['balance_raw']
                    existing_accounts =  SavingAccount.objects.filter(account_customer__id=customer_id, deleted=False, is_active=True, account_product=savingaccount.account_product, customer_branch= branch).first()
                    print("********************** staring to transfer 5. ***********************")
                    if existing_accounts:
                        transfer_to_account = existing_accounts
                        print("********************** staring to transfer 6. ***********************")
                    else:
                        # create new account
                        print("********************** staring to transfer 7. ***********************")
                        customer = Customer.objects.get(pk=customer_id)
                        transfer_to_account = SavingAccount.objects.create(
                            account_no=generate_saving_account_code(destination_branch),
                            account_customer=customer,
                            deleted=False,
                            is_active=savingaccount.is_active,
                            status=savingaccount.status,
                            open_date=savingaccount.open_date,
                            dormancy_date=savingaccount.dormancy_date,
                            account_product=savingaccount.account_product,
                            customer_branch=branch,
                            saving_account_added_by=request.user,
                            opened_by=savingaccount.opened_by,
                            saving_account_last_updated_by=request.user,
                        )

                    if acc_bal > 0:
                        print("********************** staring to transfer 8. ***********************")
                        # print("************************ Account Balance: "+ acc_bal)
                        print("************************ Account Balance: " + str(acc_bal))
                        # make a transfer
                        reciever = {"id":transfer_to_account.id, "amount":acc_bal, "date": date_time_zone_convert(timezone.now()), "charge":0 }
                        print("********************* getting receiver ************")
                        extra_data = {"send_sms": False, "sender_id": savingaccount.id, "description":"Customer Branch Transfer" }
                        print("********************* getting extra_data ************")
                        saved_transaction = save_sender_transactions(request.user, request, reciever, extra_data)
                        print("********************* getting saved_transaction ************")
                        sender_account   = SavingAccount.objects.get(pk=savingaccount.id)
                        reciever_account = SavingAccount.objects.get(pk=transfer_to_account.id)
                        print(saved_transaction)
                        print("****************** going to 9 *******************************")
                        if saved_transaction:
                            print("********************** staring to transfer 9. ***********************")
                            # Save reciever transactions details
                            saved_reciever = save_reciever_transactions(request.user, request, reciever, extra_data)
                            if saved_reciever:
                                print("********************** staring to transfer 10. ***********************")
                                # Reconcile inter-branch transactions
                                if sender_account.customer_branch != reciever_account.customer_branch:
                                    print("********************** staring to transfer 11. ***********************")
                                    inter_branch_trans_field = {
                                        "source_transaction":saved_transaction.transaction,
                                        "destination_transaction":saved_reciever.transaction,
                                        "added_by":request.user,
                                    }
                                    InterBranchTransactions.objects.create(**inter_branch_trans_field)
                                
                                # Save transfer transactions details mapping
                                transfer_fields = {
                                    "sender_transaction": saved_transaction,
                                    "reciever_transaction": saved_reciever
                                }
                                TransferTransactions.objects.create(**transfer_fields)

                                # other actions --- deactivate branch account
                                savingaccount.is_active = False
                                savingaccount.status = 'inactive'
                                savingaccount.deleted = True
                                savingaccount.save()
                                print("********************** staring to transfer 12. ***********************")
                                # Update payment fixed deposits
                                FixedDeposit.objects.filter(saving_account=savingaccount, status__in=['pending', 'in-progress']).update(saving_account=transfer_to_account)
                                SavingsBlockedAmount.objects.filter(customer_account=savingaccount, status='active').update(customer_account=transfer_to_account)

        return  Response({"message":"Transfer Made successfully"})


class CustomerCardView(APIView):

    def post(self, request, format=None):
        response_status = status.HTTP_200_OK
        message = {
            'status': 'failed',
            'message': 'Invalid Data'
        }
        id = self.request.data.get('id')
        card_id = self.request.data.get('card_id')
        is_biometric = self.request.data.get('is_biometric')
        customer_obj = {
             "card_id":card_id,
             "is_biometric":is_biometric
                }
        
        settings = Customer.objects.filter(Q(id=id)).update(**customer_obj)   
        if settings:
            customer    = Customer.objects.get(pk=id)
            
            message = {
                'status': 'success',
                'customer': CustomerSerializer(customer).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)


class CustomerCardProfileView(APIView):

    def post(self, request, format=None):
        response_status = status.HTTP_200_OK
        message = {
            'status': 'failed',
            'message': 'Invalid Data'
        }

        card_id = self.request.data.get('card_id')
        customer_obj = Customer.objects.filter(card_id=card_id).first()
        if customer_obj:
            message = {
                'status': 'success',
                'customer': CustomerSerializer(customer_obj).data
            }
            response_status = status.HTTP_200_OK

        return Response(message, response_status)

class MMCustomersViewSet(viewsets.ModelViewSet):
    '''
    List all customers
    POST
    {
        "customer": [{"customer_field":1,"value":"123456"}],
        "name": "Demo Test",
        "member_number": "123456",
        "old_member_number": "",
        "status": "",
        "customer_branch": 1
    }
    '''
    serializer_class = CustomerSerializer
    filter_backends  = (SearchFilter, OrderingFilter, DjangoFilterBackend, )
    filterset_fields = ['member_number','name', 'old_member_number', 'branch_customer_type','customer_branch', 'group_category']
    search_fields    = ['member_number','name', 'old_member_number']
    ordering_fields  = ['name', 'member_number']

    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return Customer.objects.filter(customer_branch__branch_organisation__id=organisation_id, is_deleted=False).order_by('member_number')

    def perform_create(self, serializer):
        request_data    = self.request.data
        savings_product = request_data.get('savings_product', None)
        send_sms        = request_data.get('send_sms',False)
        subscribe       = request_data.get('subscribe',False)
        customer_metas  = request_data.get('customer',False)
        branch_id       = get_current_user(self.request, 'organisation_branch_id', None)
        branch          = OrganisationBranch.objects.get(pk=branch_id)
        organisation_branch_id = get_current_user(self.request, 'organisation_branch_id', 1) 
        old_member_number = generate_member_number(organisation_branch_id)
        organisation_branch    = OrganisationBranch.objects.get(pk=organisation_branch_id)
        nin = request_data.get('nin', None)

        saved_customer = serializer.save(customer_branch=organisation_branch, member_number=old_member_number, nin=nin)

        if saved_customer:

            if customer_metas:
                for customer_meta in customer_metas:
                    customer_meta = {"customer":saved_customer,"customer_field_id":customer_meta["customer_field"],"value":customer_meta["value"],"customer_field_added_by":self.request.user}
                    save_meta_data = CustomerFieldMeta.objects.create(**customer_meta) 

            self.update_customer_location(saved_customer,request_data,branch)
            self.create_default_savings_account(saved_customer,savings_product,organisation_branch,self.request.user)
            if subscribe:
                self.auto_subscribe_to_sms_banking(saved_customer,organisation_branch,self.request.user)
            if send_sms:
                self.send_customer_welcome_sms(saved_customer,organisation_branch,self.request.user)
                self.send_customer_mmbanking_sms(saved_customer)

    # def perform_create(self, serializer):
    #     request_data    = self.request.data
    #     savings_product = request_data.get('savings_product', None)
    #     send_sms        = request_data.get('send_sms',False)
    #     subscribe       = request_data.get('subscribe',False)
    #     branch_id       = get_current_user(self.request, 'organisation_branch_id', None)
    #     branch          = OrganisationBranch.objects.get(pk=branch_id)
    #     organisation_branch_id = get_current_user(self.request, 'organisation_branch_id', 1)
    #     organisation_branch    = OrganisationBranch.objects.get(pk=organisation_branch_id)
    #     saved_customer = serializer.save(customer_branch=organisation_branch)
    #     if saved_customer:
    #         self.update_customer_location(saved_customer,request_data,branch)
    #         self.create_default_savings_account(saved_customer,savings_product,organisation_branch,self.request.user)
    #         if subscribe:
    #             self.auto_subscribe_to_sms_banking(saved_customer,organisation_branch,self.request.user)
            #if send_sms:
               # self.send_customer_welcome_sms(saved_customer,organisation_branch,self.request.user)
                #self.send_customer_mmbanking_sms(saved_customer)

    def auto_subscribe_to_sms_banking(self,customer,organisation_branch,user):
        if customer:
            org_subs = OrganisationSmsSubscription.objects.filter(organisation__id=organisation_branch.branch_organisation.id, is_subscribed=True)
            if org_subs:
                for org_sub in org_subs:
                    member_sms_sub = MemberSmsSubscription.objects.filter(
                        org_subscription=org_sub, customer=customer).first()
                    if member_sms_sub:
                        member_sms_sub.is_subscribed = True
                        member_sms_sub.save()
                    if not member_sms_sub:
                        data = {"customer": customer, "org_subscription": org_sub, "sub_added_by":user,
                                "sub_last_updated_by":user, "is_subscribed": True}
                        MemberSmsSubscription.objects.create(**data)
    
    def send_customer_mmbanking_sms(self,customer):
        # Generate pin of length 4
        pin = random.randint(pow(10, 3), pow(10, 4) - 1)
        data = {"customer": customer, "telephone_no": customer.telephone,"pin":pin,"active":True,"added_by":customer.customer_added_by}
        subscription = MobileBankingSubscription.objects.create(**data)
        if subscription:
            sms_text = "Dear "+subscription.customer.name.capitalize()+", Welcome to "+subscription.customer.customer_branch.branch_organisation.name.upper() + \
                " mobile banking\n Dial *284*55#. Access MEM NO: " + \
                subscription.customer.member_number+" PIN: "+str(pin)
            send_mm_pin(subscription, sms_text,self.request.user)
    
    def send_customer_welcome_sms(self,customer,organisation_branch,user):
        if customer:
            org_sub = OrganisationSmsSubscription.objects.filter(
                sms_type__sms_type_key='welcome_sms', organisation__id=organisation_branch.branch_organisation.id, is_subscribed=True).first()
            if org_sub:
                member_sms_sub = MemberSmsSubscription.objects.filter(
                    org_subscription=org_sub, customer=customer).first()
                if not member_sms_sub:
                    data = {"customer": customer, "org_subscription": org_sub, "sub_added_by":user,
                            "sub_last_updated_by":user, "is_subscribed": True}
                    MemberSmsSubscription.objects.create(**data)
                sms_msg = 'Dear '+customer.name.capitalize() +', Welcome to '+organisation_branch.branch_organisation.short_name+ ',\n your account has been successfully registered'
                data    = {"sms_key":"welcome_sms","customer":customer,"user":user,"branch_id":organisation_branch.id,"sms_msg":sms_msg}
                send_customer_sms(data)

    def create_default_savings_account(self,customer,savings_product,organisation_branch,user):
        if customer:
           # Create customer savings Account
            if savings_product and int(savings_product) > 0:
                account_product = SavingsProduct.objects.get(pk=savings_product)
                initial_state = get_savings_account_initial_state(account_product)
                SavingAccount.objects.create(
                    account_no=generate_saving_account_code(organisation_branch.id),
                    account_customer=customer,
                    account_product=account_product,
                    customer_branch=organisation_branch,
                    status=initial_state['status'],
                    is_active=initial_state['is_active'],
                    saving_account_added_by=user,
                    opened_by=user.user_staff,
                    saving_account_last_updated_by=user
                )
            else:
                # Get default savings product
                savings_product = OrganisationSetting.objects.filter(org_setting__id = organisation_branch.branch_organisation.id,setting_key ="savings_product").first()
                if savings_product:
                    if len(savings_product.setting_value) > 0:
                        account_product = SavingsProduct.objects.get(pk=savings_product.setting_value)
                        initial_state = get_savings_account_initial_state(account_product)
                        SavingAccount.objects.create(
                            account_no=generate_saving_account_code(organisation_branch.id),
                            account_customer=customer,
                            account_product=account_product,
                            customer_branch=organisation_branch,
                            status=initial_state['status'],
                            is_active=initial_state['is_active'],
                            saving_account_added_by=user,
                            opened_by=user.user_staff,
                            saving_account_last_updated_by=user
                        )
    def update_customer_location(self,instance,request_data,branch):
        updated_addr = request_data.get('updated_address',None)
        if updated_addr:
            village_id    = updated_addr['village']
            villagename   = updated_addr['villagename']
            parish_id     = updated_addr['parish']
            parishname    = updated_addr['parishname']
            subcounty_id  = updated_addr['subcounty']
            subcountyname = updated_addr['subcountyname']
            county_id     = updated_addr['county']
            county_name   = updated_addr['countyname']
            district_id   = updated_addr['district']
            district_name = updated_addr['districtname']
            village       = None
            physical_address = updated_addr['physical_address']
            if district_id == None and district_name:
                saved_district = District.objects.create(districtname = district_name)
                if saved_district:
                    district_id = saved_district.id
            if district_id:
                if county_id == None and county_name:
                    saved_county = County.objects.create(district=District.objects.get(pk=district_id),countyname = county_name)
                    if saved_county:
                        county_id = saved_county.id
            if county_id:
                if subcounty_id == None and subcountyname:
                    saved_subcounty= SubCounty.objects.create(
                        county   = County.objects.get(pk=county_id),
                        subcountyname = subcountyname,
                        is_verified = False
                    )
                    if saved_subcounty:
                        subcounty_id = saved_subcounty.id
            if parish_id == None and subcounty_id and parishname:
                saved_parish = Parish.objects.create(
                    subcounty   = SubCounty.objects.get(pk=subcounty_id),
                    parishname  = parishname,
                    is_verified = False
                )
                if saved_parish:
                    parish_id = saved_parish.id
            if village_id == None and parish_id and villagename:
                saved_village = Village.objects.create(
                    parish  = Parish.objects.get(pk=parish_id),
                    villagename = villagename,
                    is_verified = False
                )
                if saved_village:
                    village_id = saved_village.id
            if village_id:
                village = Village.objects.filter(id=village_id).first()
            customer_address = CustomerAddress.objects.filter(customer=instance).first()
            if customer_address:
                old_details = CustomerAddressSerializer(customer_address,read_only=True).data
                customer_address.village = village
                customer_address.parish = parish_id
                customer_address.subcounty = subcounty_id
                customer_address.county   = county_id
                customer_address.district = district_id
                customer_address.physical_address = physical_address
                customer_address.address_added_by = self.request.user
                customer_address.save()
                new_details = CustomerAddressSerializer(CustomerAddress.objects.get(pk=customer_address.id),read_only=True).data
                message = f'Updated Location For Customer: {instance.name}'
                add_system_audit_trail('customer_management','update_customer_location',message,'',old_details,new_details,self.request.user,branch)
            else:
                CustomerAddress.objects.create(customer=instance,village=village,parish=parish_id,subcounty=subcounty_id,county = county_id,district = district_id,address_added_by=self.request.user,physical_address=physical_address)


class CropsViewSet(viewsets.ModelViewSet):
    serializer_class = CropSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend,)
    search_fields = ('name',)
    ordering_fields = ['name']

    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return Crop.objects.filter(
            organisation__id=organisation_id, is_active=True
        ).prefetch_related('varieties').order_by('name')

    def create(self, request, *args, **kwargs):
        organisation_id = get_current_user(request, 'organisation_id', None)
        organisation = Organisation.objects.get(pk=organisation_id)
        name = request.data.get('name', '').strip()
        existing = Crop.objects.filter(name__iexact=name, organisation=organisation).first()
        if existing:
            if not existing.is_active:
                existing.is_active = True
                existing.save()
                from rest_framework import status as drf_status
                from rest_framework.response import Response
                return Response(CropSerializer(existing).data, status=drf_status.HTTP_200_OK)
            from rest_framework.exceptions import ValidationError
            raise ValidationError({'name': f'A crop named "{existing.name}" already exists for this organisation.'})
        return super().create(request, *args, **kwargs)

    def perform_create(self, serializer):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        organisation = Organisation.objects.get(pk=organisation_id)
        serializer.save(organisation=organisation, added_by=self.request.user)

    def perform_destroy(self, instance):
        instance.is_active = False
        instance.save()


class CropVarietiesViewSet(viewsets.ModelViewSet):
    serializer_class = CropVarietySerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend,)
    filterset_fields = ['crop']
    search_fields = ('name',)
    ordering_fields = ['name']

    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return CropVariety.objects.filter(
            crop__organisation__id=organisation_id, is_active=True
        ).order_by('name')

    def perform_create(self, serializer):
        crop_id = self.request.data.get('crop')
        crop = Crop.objects.get(pk=crop_id)
        serializer.save(crop=crop, added_by=self.request.user)

    def perform_destroy(self, instance):
        instance.is_active = False
        instance.save()


class FarmingHistoryViewSet(viewsets.ModelViewSet):
    serializer_class = FarmingHistorySerializer
    filter_backends = (SearchFilter, DjangoFilterBackend,)
    filterset_fields = ['customer', 'year', 'season', 'activity_type']

    def get_queryset(self):
        organisation_id = get_current_user(self.request, 'organisation_id', None)
        return FarmingHistory.objects.filter(
            customer__customer_branch__branch_organisation__id=organisation_id
        ).select_related(
            'customer',
            'customer__branch_customer_type',
        )

    def perform_create(self, serializer):
        customer_id = self.request.data.get('customer')
        customer = Customer.objects.get(pk=customer_id)
        data = self.request.data.get('activity_data', {})
        financials = self._compute_financials(self.request.data.get('activity_type'), data)
        serializer.save(customer=customer, added_by=self.request.user, **financials)

    def perform_update(self, serializer):
        data = self.request.data.get('activity_data', {})
        financials = self._compute_financials(self.request.data.get('activity_type'), data)
        serializer.save(**financials)

    def _compute_financials(self, activity_type, data):
        try:
            total_sales = float(data.get('total_sales', 0) or 0)
            total_investment = float(data.get('total_investment', 0) or data.get('amount_invested', 0) or 0)
            profit = total_sales - total_investment
            roi = round((profit / total_investment * 100), 2) if total_investment > 0 else 0
            return {'total_sales': total_sales, 'total_investment': total_investment, 'profit': profit, 'roi': roi}
        except (TypeError, ValueError):
            return {'total_sales': 0, 'total_investment': 0, 'profit': 0, 'roi': 0}


class FinwiseGroupCustomersViewSet(viewsets.ReadOnlyModelViewSet):
    """
    API endpoint that returns all group customers whose organization has adminID 'finwise' (org_id=139).
    Only returns groups that have at least one active participant.
    Includes the participant count for each group.

    GET /api/finwise-group-customers/

    Response includes:
    - id: Group customer ID
    - name: Group name
    - member_number: Group member number
    - telephone: Group contact
    - customer_type_name: Type of customer (group type)
    - organisation_id: Organization ID
    - organisation_name: Organization name
    - branch_id: Branch ID
    - branch_name: Branch name
    - participant_count: Number of active participants in the group
    - date_added: Date group was created
    - status: Group status
    """
    serializer_class = FinwiseGroupCustomerSerializer
    filter_backends = (SearchFilter, OrderingFilter, DjangoFilterBackend)
    search_fields = ('name', 'member_number', 'telephone')
    filterset_fields = ['status', 'customer_branch__id', 'customer_branch__branch_organisation__id']
    ordering_fields = ['name', 'date_added', 'member_number']
    ordering = ['-date_added']

    def get_queryset(self):
        """
        Return group customers from organizations with admin_organisation_id set in settings (default: Finwise)
        that have at least one active participant
        """
        from django.db.models import Count, Q

        # Get Finwise org ID from Django settings (configurable via environment variable)
        finwise_org_id = getattr(settings, 'FINWISE_ORGANIZATION_ID', 139)

        queryset = Customer.objects.filter(
            # Filter for organizations where admin_organisation is Finwise
            customer_branch__branch_organisation__admin_organisation_id=finwise_org_id,
            # Filter for group customer types (has_members=True)
            branch_customer_type__has_members=True,
            # Not deleted
            is_deleted=False
        ).annotate(
            # Annotate with participant count
            active_participants=Count(
                'group_member',
                filter=Q(group_member__active=True)
            )
        ).filter(
            # Only include groups with at least one active participant
            active_participants__gt=0
        ).select_related(
            'branch_customer_type',
            'customer_branch',
            'customer_branch__branch_organisation'
        ).order_by('-date_added')

        return queryset
