import pandas as pd
import json, math, os, traceback
from datetime import datetime
from utils import get_cloudwatch_logger, log_exception
from scripts.blacksoil_lms.co_lending_regular_allocation import co_lending_regular_allocation

logger = get_cloudwatch_logger(stream_name="co_lending_bulk_allocation")

def co_lending_bulk_allocation_function(data, user_id=107):
    """
    Validates and processes bulk payment allocations for co-lending from a file or JSON list.
    """
    output = []
    
    # Check if data is a file path (string) or list of dictionaries
    if isinstance(data, str) and (data.endswith('.csv') or data.endswith('.xlsx')):
        try:
            if data.endswith('.csv'):
                df = pd.read_csv(data)
            else:
                df = pd.read_excel(data)
        except Exception as e:
            error_msg = f"Failed to read file: {str(e)}"
            logger.send_log_event(f"ERROR: {error_msg}")
            return [{"error": error_msg}]
    elif isinstance(data, list):
        df = pd.DataFrame(data)
    else:
        error_msg = "Input must be a valid file path or a list of dictionaries."
        logger.send_log_event(f"ERROR: {error_msg}")
        return [{"error": error_msg}]
        
    required_cols = {'loan_id', 'payment_date', 'amount'}
    if not required_cols.issubset(set(df.columns)):
        error_msg = f"Missing required columns. Expected at least: {required_cols}"
        logger.send_log_event(f"ERROR: {error_msg}")
        return [{"error": error_msg}]
        
    logger.send_log_event(f"INFO: Found {len(df)} rows to process for bulk allocation.")
    
    success_count = 0
    error_count = 0
    
    for row in df.itertuples(index=False):
        loan_id = getattr(row, 'loan_id', None)
        if pd.isna(loan_id):
            continue
            
        loan_id = str(int(float(loan_id))) if isinstance(loan_id, (int, float)) else str(loan_id)
        
        try:
            amount = float(row.amount)
            if amount <= 0:
                raise ValueError("Amount must be greater than zero.")
                
            p_date_raw = row.payment_date
            if pd.isna(p_date_raw):
                raise ValueError("payment_date is missing.")
                
            if hasattr(p_date_raw, 'strftime'):
                payment_date_str = p_date_raw.strftime("%d-%m-%Y")
            else:
                # Try parsing if string
                p_str = str(p_date_raw).strip()
                try:
                    payment_date_str = datetime.strptime(p_str, "%d-%m-%Y").strftime("%d-%m-%Y")
                except ValueError:
                    try:
                        payment_date_str = datetime.strptime(p_str, "%Y-%m-%d").strftime("%d-%m-%Y")
                    except ValueError:
                        try:
                            payment_date_str = datetime.strptime(p_str, "%m/%d/%Y").strftime("%d-%m-%Y")
                        except ValueError:
                            raise ValueError(f"Incorrect date format: {p_str}. Use DD-MM-YYYY")
                            
            payment_for = getattr(row, 'payment_for', 'EMI')
            if pd.isna(payment_for) or str(payment_for).strip().upper() == 'EMI':
                payment_for = 'EMI'
            else:
                logger.send_log_event(f"INFO: Skipping loan_id {loan_id}, payment_for '{payment_for}' is not 'EMI'.")
                continue
            
            transaction_number = getattr(row, 'transaction_number', None)
            transaction_mode = getattr(row, 'transaction_mode', None)
            utr = getattr(row, 'utr', None)
            
            payload = {
                "loan_id": loan_id,
                "dry_run": False,
                "user_id": user_id,
                "payment_list": {
                    "amount": amount,
                    "payment_date": payment_date_str,
                    "payment_for": payment_for,
                    "transaction_number": str(transaction_number) if pd.notnull(transaction_number) else None,
                    "transaction_mode": str(transaction_mode) if pd.notnull(transaction_mode) else None,
                    "utr": str(utr) if pd.notnull(utr) else None
                }
            }
            
            result = co_lending_regular_allocation(payload)
            if "error" in result:
                raise ValueError(result["error"])
                
            success_count += 1
            output.append({
                "loan_id": loan_id,
                "status": "success",
                "payment_log_id": result.get("payment_log_id")
            })
            
        except Exception as e:
            error_count += 1
            log_exception(logger, f"Error processing bulk allocation for loan_id {loan_id}: {str(e)}")
            output.append({
                "loan_id": loan_id,
                "status": "error",
                "message": str(e)
            })
            
    logger.send_log_event(f"INFO: Bulk Allocation Completed. Success: {success_count}, Errors: {error_count}")
    
    # Trigger recalculation of bounce/penal and loan metrics for successfully processed loans
    successful_loan_ids = list(set([str(item["loan_id"]) for item in output if item["status"] == "success"]))
    if successful_loan_ids:
        try:
            from scripts.blacksoil_lms.co_lending_bounce_penal import process_bounce_penal_updates
            process_bounce_penal_updates(loan_ids=successful_loan_ids)
            logger.send_log_event(f"INFO: Successfully recalculated bounce/penal and metrics for {len(successful_loan_ids)} loans.")
        except Exception as e:
            log_exception(logger, f"Error triggering metrics refresh after bulk allocation: {str(e)}")
            
    return output

if __name__ == "__main__":
    pass
