from mobileapp.serializers import *
from loans.models import *
from customers.serializers import *
from mobileapp.serializers import *
from loans.serializers import *
from loans.helper import *


def mm_generate_loan_schedules(request, loan_id = None, loan_type = 'new', loan_data=None):
    loan_schedules = []
    if loan_id:
        loan_details = VslaLoans.objects.get(pk=loan_id)
        if loan_details:
            # end of validation
            loan_interest_method = loan_details.int_method
            if loan_interest_method == 'flat':
                loan_schedules = mm_calculate_flat_loan_schedule(request, loan_id, loan_type)
                
            if loan_interest_method == 'declining':
                loan_schedules = mm_calculate_flat_loan_schedule(request, loan_id, loan_type)

    return loan_schedules



def mm_calculate_flat_loan_schedule(request, loan_id =None , loan_type = 'new', loan_data = None):
    # Calculate termly interest rate
    if loan_id:
        loan_details = VslaLoans.objects.filter(pk=loan_id).first()
        # customer = Customer.objects.filter(Q(member_number = member_number) | Q(old_member_number = member_number)).first()
        product = VslaLoanSettings.objects.filter(id=loan_details.loan_product).first()

        period_type = product.period_type
        loan_period = product.loan_period
        loan_amount = loan_details.amount
        interest_rate = product.int_rate
        frequency = 1
        grace_period = 0
        grace_period_type = 'pay_none'
        loan_start_date = loan_details.record_date

    num_of_payments = mm_calculate_num_of_payments(loan_period, frequency)

    # Calculate the termly interest rate
    interest, principal, total = loan_payment(request, loan_id, loan_type, loan_data)
    termly_rate = int_for_term(period_type, interest_rate)
    termly_interest_rate = termly_rate / 100

    # new loan period with repayment intervals
    original_loan_period = loan_period
    loan_period = num_of_payments
    
    # Calculate the monthly payment, including the interest charged on the original principal
    termly_payment = (loan_amount + (loan_amount * termly_interest_rate * original_loan_period)) / loan_period
    
    # Initialize the remaining balance to the principal
    toal_loan_start_balance = loan_amount + interest
    
    # Initialize an empty list to store the repayment schedule
    schedules = []

    # refine amounts
    refine_termly_payment_sup = 0
    refine_pay_interest_sup = 0
    
    # Loop through each termly of the loan
    for i in range(loan_period):
        # Calculate the interest for the month, based on the original principal
        interest_paid = loan_amount * termly_interest_rate * frequency
        
        # Calculate the principal for the term
        principal_paid = termly_payment - interest_paid
        
        # refine termly_payment amount
        refine_termly_payment, sup_termly_payment = refine_amount(request, principal_paid)
        refine_termly_payment_sup += sup_termly_payment

        # refine termly_payment amount
        refine_pay_interest, sup_pay_interest = refine_amount(request, interest_paid)
        refine_pay_interest_sup += sup_pay_interest

        # balance refine
        refine_loan_start_balance = round_off_amount(request, toal_loan_start_balance)

        if i == loan_period - 1:
            refine_termly_payment = round_off_amount(request, refine_termly_payment + refine_termly_payment_sup)
            refine_pay_interest = round_off_amount(request, refine_pay_interest + refine_pay_interest_sup)
        

        # Add the month's repayment details to the schedule
        total_schedule = refine_termly_payment + refine_pay_interest
        toal_loan_end_balance = refine_loan_start_balance - total_schedule 

        months = (i + 1) * freq_for_term(period_type, frequency) // 30
        delta = relativedelta(months=months)
        if period_type == 'w':
            weeks = (i + 1) * freq_for_term(period_type, frequency) // 7
            delta = relativedelta(weeks=weeks)
        elif period_type == 'bw':
            biweeks = (i + 1) * freq_for_term(period_type, frequency) // 14
            delta = relativedelta(weeks=biweeks)

        elif period_type == 'q':
            quartely = (i + 1) * freq_for_term(period_type, frequency) // 30
            delta = relativedelta(months=quartely)
        
        elif period_type == 'y':
            annually = (i + 1) * freq_for_term(period_type, frequency) // 365
            delta = relativedelta(years=annually)

        elif period_type == 'd':
            days = (i + 1) * freq_for_term(period_type, frequency)
            delta = relativedelta(days=days)

        eat_timezone = pytz.timezone("Africa/Nairobi")
        loan_start_date = loan_start_date.astimezone(eat_timezone)
        loan_start_date = datetime.strptime(loan_start_date_is_last_date(loan_start_date.strftime("%Y-%m-%d")), "%Y-%m-%d")
        schedules.append({
            'expected_date': loan_start_date + delta,
            'starting_balance':refine_loan_start_balance,
            'principal_expected': refine_termly_payment,
            'interest_expected': refine_pay_interest,
            'total_payment': total_schedule,
            'ending_balance': toal_loan_end_balance
        })
        toal_loan_start_balance = toal_loan_end_balance
    
    # calculate with grace period
    loan_schedules = schedules
    if grace_period > 0 and grace_period_type in ['pay_none', 'pay_i', 'pay_p']:
        loan_schedules = []

        # reset refine amounts
        refine_termly_payment_sup = 0
        refine_pay_interest_sup = 0

        # Calculate the schedule for each term
        grace_period_interest_bal = 0
        grace_period_principal_bal = 0
        grace_period_total_payment = 0

        toal_loan_start_balance = loan_amount + interest
        for i in range(0, loan_period):
            interest_paid = 0
            principal_paid = 0
            if i < grace_period:
                if grace_period_type == 'pay_none':
                    grace_period_interest_bal += schedules[i]['interest_expected']
                    grace_period_principal_bal += schedules[i]['principal_expected']
                    grace_period_total_payment += schedules[i]['total_payment']
                
                if grace_period_type == 'pay_i':
                    grace_period_principal_bal += schedules[i]['principal_expected']
                    grace_period_total_payment += schedules[i]['principal_expected']
                    grace_period_interest_bal = 0

                    interest_paid = schedules[i]['interest_expected']
                
                if grace_period_type == 'pay_p':
                    grace_period_interest_bal += schedules[i]['interest_expected']
                    grace_period_total_payment += schedules[i]['interest_expected']
                    grace_period_principal_bal = 0

                    principal_paid = schedules[i]['principal_expected']
            else:
                new_grace_period_interest_bal = grace_period_interest_bal / (loan_period - grace_period)
                new_grace_period_principal_bal = grace_period_principal_bal / (loan_period - grace_period)

                interest_paid = new_grace_period_interest_bal + schedules[i]['interest_expected']
                principal_paid = new_grace_period_principal_bal + schedules[i]['principal_expected']

            # refine termly_payment amount
            refine_termly_payment, sup_termly_payment = principal_paid
            refine_termly_payment_sup += sup_termly_payment

            # refine termly_payment amount
            refine_pay_interest, sup_pay_interest = interest_paid
            refine_pay_interest_sup += sup_pay_interest

            # balance refine
            refine_loan_start_balance = round_off_amount(request, toal_loan_start_balance)

            if i == loan_period - 1:
                refine_termly_payment = round_off_amount(request, refine_termly_payment + refine_termly_payment_sup)
                refine_pay_interest = round_off_amount(request, refine_pay_interest + refine_pay_interest_sup)

            total_schedule = refine_termly_payment + refine_pay_interest
            toal_loan_end_balance = refine_loan_start_balance - total_schedule 
            loan_schedules.append({
                'expected_date': schedules[i]['expected_date'],
                'starting_balance': refine_loan_start_balance,
                'principal_expected': refine_termly_payment,
                'interest_expected': refine_pay_interest,
                'total_payment': total_schedule,
                'ending_balance': toal_loan_end_balance
            })    
            toal_loan_start_balance = toal_loan_end_balance

    return loan_schedules


def mm_calculate_num_of_payments(num_terms, repayment_interval):
    num_payments = num_terms // repayment_interval
    if num_terms % repayment_interval != 0:
        num_payments += 1
    return num_payments