import pandas as pd
import numpy_financial as npf
from datetime import datetime
from dateutil.relativedelta import relativedelta
from utils import get_cloudwatch_logger
logger = get_cloudwatch_logger(stream_name="bpi_rps_generation_stream")

async def function1(data):
    
    logger.send_log_event(f"INFO: In 5th_emi_date(bpi rps) function - Request received: \n{data}")

    loan_principal = data["loan_principal"]
    annualised_interest = data["annualised_interest"]
    annualised_irr = data["annualised_irr"]
    remaining_emi = data["remaining_emi"]
    disbursal_date_str = data["disbursal_date_str"]
    first_emi_date_str = data["first_emi_date_str"]
    morat_months = data["morat_months"]
    morat_start_date_str = data["morat_start_date_str"]

    annualised_interest = (annualised_interest/100)
    annualised_irr = (annualised_irr/100)
    if annualised_interest == 0:
        emi_amount = loan_principal/remaining_emi
    else:
        emi_amount = npf.pmt(annualised_interest/12,remaining_emi,-loan_principal,0)
    disbursal_date = datetime.strptime(disbursal_date_str,'%d-%m-%Y').date()
    first_emi_date = datetime.strptime(first_emi_date_str,'%d-%m-%Y').date()

    # If morat months mentioned then assign morat date, else random morat date
    if morat_months > 0: 
        morat_start_date = datetime.strptime(morat_start_date_str,'%d-%m-%Y').date()
    else:
        morat_start_date = datetime.strptime('05-11-2016','%d-%m-%Y').date()

    # Logic to calculate pre_emi_date & add extra month if pre_emi present
    pre_emi_month = 0
    scenario = 0
    if disbursal_date.day > 5:
        scenario = 2
        pre_emi_date = first_emi_date - relativedelta(months=1)
        pre_emi_month = 1
    elif disbursal_date.day < 5:
        scenario = 3
        pre_emi_date = first_emi_date - relativedelta(months=1)
        pre_emi_month = 0
    else:
        scenario = 1
        pre_emi_date = first_emi_date
        pre_emi_month = 0

    # Logic to calculate pre_emi_days
    pre_emi_days = 0
    if disbursal_date.day == 5:
        pre_emi_days = 0
    else:
        pre_emi_days = (pre_emi_date - disbursal_date).days

    # calculate final tenure
    extended_tenure = remaining_emi + morat_months + pre_emi_month

    morat_start_date_array = []
    current_date = morat_start_date
    for i in range(morat_months):
        morat_start_date_array.append(current_date)
        current_date = current_date + relativedelta(months=1)

    # RPS Generation
    if scenario == 1: # disbursal on 5th
        amort_array = []
        emi_date = first_emi_date
        pos = loan_principal
        emi = emi_amount
        emi_dates = []
        morat_interest_comp = 0
        bpi_interest_comp = 0
        
        for period in range(1,extended_tenure+1):
            emi_dates.append(emi_date)
            if emi_date not in morat_start_date_array:
                emi = emi_amount
                interest_comp = pos * 30 * annualised_interest/360
                principal_comp = emi - interest_comp
                pos = pos - principal_comp 
                morat_interest_comp = 0
            else:
                morat_interest_comp = pos * 30 * annualised_irr/360
                interest_comp = 0
                principal_comp = 0
                pos = pos - principal_comp
                emi = interest_comp + principal_comp

            amort_array.append({
            'installment_number':period,
            'emi_date': emi_date,
            'emi_amount': emi,
            'bpi_interest': bpi_interest_comp,
            'morat_interest': morat_interest_comp,
            'interest_comp': interest_comp,
            'principal_comp': principal_comp,
            'principal_outstanding': pos,
            'foreclosure_amount': bpi_interest_comp + morat_interest_comp + interest_comp + principal_comp
        })
            emi_date = emi_date + relativedelta(months=1)

    if scenario == 2: # disbursal 6th - 31st
        amort_array = []
        emi_date = pre_emi_date
        pos = loan_principal
        emi = emi_amount
        emi_dates = []
        morat_interest_comp = 0
        bpi_interest_comp = 0
        
        for period in range(1,extended_tenure+1):
            emi_dates.append(emi_date)

            if emi_date not in morat_start_date_array:
                morat_interest_comp = 0
                if period == 1:
                    bpi_interest_comp = loan_principal * pre_emi_days * annualised_irr/360
                    interest_comp = 0
                    principal_comp = 0
                    pos = pos - principal_comp
                    emi = 0
                    
                else:
                    bpi_interest_comp = 0
                    emi = emi_amount
                    interest_comp = pos * 30 * annualised_interest/360
                    principal_comp = emi - interest_comp
                    pos = pos - principal_comp
            else:
                interest_comp = 0
                bpi_interest_comp = 0
                morat_interest_comp = pos * 30 * annualised_irr/360
                principal_comp = 0
                pos = pos - principal_comp
                emi = interest_comp + principal_comp
                    
            amort_array.append({
            'installment_number':period,
            'emi_date': emi_date,
            'emi_amount': emi,
            'bpi_interest': bpi_interest_comp,
            'morat_interest': morat_interest_comp,
            'interest_comp': interest_comp,
            'principal_comp': principal_comp,
            'principal_outstanding': pos,
            'foreclosure_amount': bpi_interest_comp + morat_interest_comp + interest_comp + principal_comp
            })
            emi_date = emi_date + relativedelta(months=1)

    if scenario == 3: # # disbursal 1th - 4th
        amort_array = []
        emi_date = first_emi_date
        pos = loan_principal
        emi = emi_amount
        emi_dates = []
        morat_interest_comp = 0
        bpi_interest_comp = 0
        
        for period in range(1,extended_tenure+1):
            emi_dates.append(emi_date)

            if emi_date not in morat_start_date_array:
                morat_interest_comp = 0
                if period == 1:
                    emi = emi_amount
                    bpi_interest_comp = loan_principal * pre_emi_days * annualised_irr/360
                    interest_comp = (pos * 30 * annualised_interest/360)
                    principal_comp = emi - interest_comp
                    pos = pos - principal_comp
                    
                else:
                    emi = emi_amount
                    bpi_interest_comp = 0
                    interest_comp = pos * 30 * annualised_interest/360
                    principal_comp = emi - interest_comp
                    pos = pos - principal_comp
            else:
                if period == 1:
                    bpi_interest_comp = loan_principal * pre_emi_days * annualised_irr/360
                    morat_interest_comp = pos * 30 * annualised_irr/360
                    interest_comp = 0
                    principal_comp = 0
                    pos = pos - principal_comp
                    emi = interest_comp + principal_comp
                else:
                    bpi_interest_comp = 0
                    morat_interest_comp = pos * 30 * annualised_irr/360
                    interest_comp = 0
                    principal_comp = 0
                    pos = pos - principal_comp
                    emi = interest_comp + principal_comp
                    
            amort_array.append({
            'installment_number':period,
            'emi_date': emi_date,
            'emi_amount': emi,
            'bpi_interest': bpi_interest_comp,
            'morat_interest': morat_interest_comp,
            'interest_comp': interest_comp,
            'principal_comp': principal_comp,
            'principal_outstanding': pos,
            'foreclosure_amount': bpi_interest_comp + morat_interest_comp + interest_comp + principal_comp
            })
            emi_date = emi_date + relativedelta(months=1)


    df_amort = pd.DataFrame(amort_array)


    # Last EMI Calculation
    all_emi_sum = df_amort['emi_amount'].sum()
    all_emi_sum_excl_last = df_amort['emi_amount'].iloc[:-1].round().sum()
    last_emi_value = all_emi_sum - all_emi_sum_excl_last
    df_amort.at[df_amort.index[-1],'emi_amount'] = last_emi_value


    # recalculate principal comp to match emi amount = principal_comp + interest_comp
    df_amort['principal_comp'] = df_amort['emi_amount'] - df_amort['interest_comp']


    # Round off values
    df_amort['bpi_interest'] = df_amort['bpi_interest'].round()
    df_amort['emi_amount'] = df_amort['emi_amount'].round()
    df_amort['morat_interest'] = df_amort['morat_interest'].round()


    df_amort['total_payable'] = df_amort[['bpi_interest', 'morat_interest', 'interest_comp', 'principal_comp']].sum(axis=1).round()
    df_amort['due_date'] = df_amort['emi_date'].apply(lambda x: x + relativedelta(days=1) if x.weekday() == 6 else x) # if emi_date on sunday, add 1 day 
    df_amort['installment_number'] = (df_amort['interest_comp'] != 0).cumsum()
    df_amort['foreclosure_amount'] = df_amort['principal_outstanding'] + df_amort['interest_comp'].shift(-1).fillna(0)
    df_amort.at[len(df_amort)-1, 'foreclosure_amount'] = 0
    

    df_amort = df_amort[['installment_number','emi_date','due_date','bpi_interest','morat_interest','interest_comp','principal_comp','emi_amount','total_payable','principal_outstanding','foreclosure_amount']]
    #apr = (npf.rate(remaining_emi,emi_amount,-(loan_principal-processing_fee-subvention-insurance_amount),0)*12) * 100
    result = {
    "repayable": df_amort['total_payable'].sum(),
    "principal_amount": df_amort['principal_comp'].sum(),
    "subvention": 0,
    "total_interest": df_amort['interest_comp'].sum(),
    "total_subvention": 0,
    "interest_rate": 0,
    "annualized_interest_rate": annualised_interest,
    "rps_json": df_amort.to_dict(orient='records')
    }
    logger.send_log_event(f"INFO: Response generated successfully.")
    return result
