from rest_framework import serializers
import pytz
from . models import *
from users.serializers import *
from ledgers.serializers import *
from customers.models import *
from customers.serializers import *
from datetime import datetime,timedelta
from savings.savings_bal_helper import get_account_balance
from django.db.models.functions import TruncDate
from django.db.models import F


class OverDraftProductsSerializer(serializers.ModelSerializer):
    id = serializers.CharField(read_only=True)
    date_added = serializers.CharField(read_only=True)
    last_updated = serializers.CharField(read_only=True)
    over_draft_product_added_by = serializers.CharField(read_only=True)
    organisation = serializers.PrimaryKeyRelatedField(read_only=True, required=False)

    class Meta:
        model = OverDraftProducts
        fields = '__all__'

class OverDraftPaymentSerializer(serializers.ModelSerializer):
    closing_date = serializers.CharField(read_only=True)
    
    class Meta:
        model = OverDraftPayment
        fields = '__all__'
 

class OverDraftsSerializer(serializers.ModelSerializer):
    id                      = serializers.CharField(read_only=True)
    date_added              = serializers.CharField(read_only=True)
    last_updated            = serializers.CharField(read_only=True)
    over_draft_added_by     = serializers.CharField(read_only=True)
    over_draft_product      = serializers.CharField(read_only=True)
    branch                  = serializers.CharField(read_only=True)
    product_name            = serializers.CharField(source='account_product.product_name',read_only=True)
    customer_id             = serializers.CharField(source='saving_account.account_customer.id',read_only=True)
    customer_name           = serializers.CharField(source='saving_account.account_customer.name',read_only=True)
    customer_member_number  = serializers.CharField(source='saving_account.account_customer.member_number',read_only=True)
    customer_old_member_number  = serializers.CharField(source='saving_account.account_customer.old_member_number',read_only=True)
    customer_account_number = serializers.CharField(source='saving_account.account_no',read_only=True)
    telephone               = serializers.CharField(source='saving_account.account_customer.telephone',read_only=True)
    customer_type           = serializers.CharField(source='saving_account.account_customer.branch_customer_type.customer_type',read_only=True)
    saving_account          = serializers.CharField(source='saving_account.id',read_only=True)
    reference_transaction   = SystemTransactionsSerializer(read_only=True, required=False)
    over_draft_details         = serializers.SerializerMethodField()
    customer_files          = serializers.SerializerMethodField()
    customer_address_details= serializers.SerializerMethodField()

    class Meta:
        model = OverDrafts
        fields = '__all__'

    def get_over_draft_details(self,obj):
        eat_timezone = pytz.timezone("Africa/Nairobi")
        request      = self.context.get('request')
        closing_date = request.query_params.get('closing_date',None)
        maximum_draft_days =  obj.over_draft_period
        penalty_rate = obj.penalty_rate
        charge_rate  = obj.charge_rate
        penalty_type = obj.penalty_type
        charge_type  = obj.charge_type
        penalty_grace_period =  obj.penalty_grace_period
        penalty_interval =  obj.penalty_interval
        principal_balance = 0
        principal_paid  = 0
        penalty_paid   = 0
        interest_paid  = 0
        overdraft      = obj.id
        account_balance   = get_account_balance(obj.saving_account)
        interest_balance   = 0
        amount = obj.amount
        available_balance = float(account_balance['balance'].replace(',', ''))
        payment_date = 0
        transaction_date=datetime.strptime(obj.transaction_date.astimezone(eat_timezone).strftime('%Y-%m-%d'), '%Y-%m-%d')
        current_date = datetime.strptime(datetime.now().astimezone(eat_timezone).strftime('%Y-%m-%d'), '%Y-%m-%d')
        
        if closing_date:
            current_date = datetime.strptime(closing_date, '%Y-%m-%d')
        past_days = ((current_date - transaction_date).days)-1
        new_end_Date = obj.transaction_date.astimezone(eat_timezone) + timedelta(days = obj.over_draft_period)

        principal_loss = OverDraftPaymentWrittenOff.objects.filter(over_draft=overdraft).values('over_draft__id',payment_date=TruncDate('closing_date')).annotate(princ_paid_sum=Sum('transaction__amount')).values('payment_date','princ_paid_sum')
        if principal_loss:
                loss_values = principal_loss[0]
                principal_paid = float(loss_values.get('princ_paid_sum', 0))
                payment_date   = loss_values.get('payment_date',0)
        principal_balance = principal_paid

        repayments    = OverDraftPayment.objects.filter(over_draft=overdraft,transaction__transaction_type='normal').values('over_draft__id').annotate(princ_paid_sum=Sum('principal_paid'),int_paid_sum=Sum('interest_paid'),penalty_paid_sum=Sum('penalty_paid')).values('princ_paid_sum','int_paid_sum','penalty_paid_sum','over_draft__id')

        if repayments:
            repayments_values = repayments[0]
            principal_paid = float(repayments_values.get('princ_paid_sum', 0))
            interest_paid = float(repayments_values.get('int_paid_sum', 0))
            penalty_paid = float(repayments_values.get('penalty_paid_sum', 0))

        #principal balance
        principal_balance = amount - principal_paid

        #interest balance
        if obj.status != 'closed':
            if charge_type == 'flat':
                interest_charge = charge_rate
            else:
                interest_charge = (charge_rate * amount) * 0.01
            if past_days > 0:
                interest_balance =  (interest_charge * past_days) - interest_paid         
        else:
            interest_balance = 0

        #penalty balance
        before_penalty_date  = datetime.strptime(obj.transaction_date.astimezone(eat_timezone).strftime('%Y-%m-%d'), '%Y-%m-%d') + timedelta(days = (penalty_grace_period  +  obj.over_draft_period)) 
        arear_days           = max((datetime.strptime(datetime.now().astimezone(eat_timezone).strftime('%Y-%m-%d'), '%Y-%m-%d') - before_penalty_date).days,0) 
        if closing_date:
            closing_date = datetime.strptime(closing_date, "%Y-%m-%d").date()
        
            arear_days      = max((closing_date - before_penalty_date.date()).days,0)
        penalty_days         = 0
        if penalty_interval<= 0:
            penalty_interval = 1
        penalty_days = arear_days/penalty_interval

        if obj.status != 'closed':
            if penalty_type == 'flat':
                penalty_charge = penalty_rate
            else:
                penalty_charge = (penalty_rate * principal_balance) * 0.01
            
                penalty_balance  = (penalty_days * penalty_charge) - penalty_paid
        else:
            penalty_balance = 0

        return {"penalty_rate":penalty_rate, 
                "charge_rate":charge_rate, 
                "principal_balance":principal_balance, 
                "penalty_balance":penalty_balance,
                "penalty_type":penalty_type,
                "charge_type":charge_type,
                "arrear_days":arear_days, 
                "maximum_draft_days":maximum_draft_days,
                "principal_paid":principal_paid,
                "penalty_paid":penalty_paid,
                "interest_paid":interest_paid,
                "available_balance":available_balance,
                "interest_balance":interest_balance,
                "new_end_Date":new_end_Date,
                "payment_date":payment_date
            }

      
    def get_customer_files(self, obj):
        customer_files = CustomerFiles.objects.filter(customer=obj.saving_account.account_customer).all()
        return CustomerFilesSerializer(customer_files, many=True).data
    
    def get_customer_address_details(self, obj):
        address = CustomerAddress.objects.filter(customer=obj.saving_account.account_customer).first()
        if address:
            if address.village:
                return {"village":address.village.villagename, "parish":address.village.parish.parishname, "district":address.village.parish.subcounty.county.district.districtname, "region":address.village.parish.subcounty.county.district.region.regionname}
            else:
                return {"village":address.physical_address, "parish":'', "district":'', "region":address.region}
        return {}
     