#!/usr/bin/env python
"""
Script to automatically match and process pending M-Pesa payments
This script will retry matching payments that failed due to missing ID numbers,
allowing payments to be matched even if the ID was added after the payment was made.
"""

import os
import sys
import django

# Setup Django
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()

from loans.models import MpesaTransaction
from django.contrib.auth import get_user_model
from decimal import Decimal
import traceback

User = get_user_model()


def auto_match_pending_payments():
    """Automatically match and process all pending/failed M-Pesa payments"""
    
    print("\n" + "="*70)
    print("AUTOMATIC M-PESA PAYMENT MATCHING")
    print("="*70)
    
    # Find all transactions that need processing
    # Status: pending, confirmed, failed, or pending_approval
    # Must have bill_ref_number (ID number) but no repayment
    pending_transactions = MpesaTransaction.objects.filter(
        repayment__isnull=True
    ).exclude(
        status='processed'
    ).exclude(
        bill_ref_number__isnull=True
    ).exclude(
        bill_ref_number=''
    ).order_by('-created_at')
    
    total_count = pending_transactions.count()
    print(f"\nFound {total_count} pending transactions to process\n")
    
    if total_count == 0:
        print("✓ No pending transactions to process")
        return
    
    success_count = 0
    failed_count = 0
    skipped_count = 0
    
    for transaction in pending_transactions:
        print("\n" + "-"*70)
        print(f"Processing: {transaction.trans_id}")
        print(f"  Bill Ref (ID): {transaction.bill_ref_number}")
        print(f"  Amount: KES {transaction.amount:,.2f}")
        print(f"  Current Status: {transaction.status}")
        print(f"  Current Borrower: {transaction.borrower or 'Not matched'}")
        
        try:
            # Clear previous borrower/loan to force re-matching
            # This allows matching even if ID was added after payment
            transaction.borrower = None
            transaction.loan = None
            transaction.processing_notes = ''  # Clear old notes
            transaction.save()
            
            # Try to match borrower by ID or loan number
            print(f"  → Attempting to match by ID/Loan Number: {transaction.bill_ref_number}")
            borrower = transaction.match_borrower()
            
            if not borrower:
                print(f"  ✗ No borrower found with ID/Loan Number: {transaction.bill_ref_number}")
                print(f"     (Tried: ID number and loan number matching)")
                
                # Check if it might be a loan number
                from loans.models import Loan
                loan_check = Loan.active_objects.filter(loan_number=transaction.bill_ref_number).first()
                if not loan_check:
                    # Try normalized
                    loans = Loan.active_objects.all()
                    bill_ref_normalized = ''.join(transaction.bill_ref_number.strip().split()).upper()
                    for l in loans:
                        if l.loan_number:
                            loan_num_norm = ''.join(l.loan_number.strip().split()).upper()
                            if loan_num_norm == bill_ref_normalized:
                                loan_check = l
                                break
                
                if loan_check:
                    print(f"     ⚠ Found loan {loan_check.loan_number} but borrower matching failed")
                else:
                    print(f"     💡 Suggestion: Add client with ID '{transaction.bill_ref_number}' or ensure loan '{transaction.bill_ref_number}' exists")
                
                transaction.status = 'failed'
                transaction.processing_notes = f"No borrower found with ID number or loan number: {transaction.bill_ref_number}"
                transaction.save()
                failed_count += 1
                continue
            
            print(f"  ✓ Matched borrower: {borrower.get_full_name()} (ID: {borrower.id_number})")
            
            # Check if borrower has active loans
            from loans.models import Loan
            active_loans = Loan.active_objects.filter(
                borrower=borrower,
                status='active'
            )
            
            if not active_loans.exists():
                print(f"  ✗ Borrower has no active loans")
                transaction.status = 'failed'
                transaction.processing_notes = f"Borrower matched but has no active loans"
                transaction.save()
                failed_count += 1
                continue
            
            print(f"  → Found {active_loans.count()} active loan(s)")
            
            # Process the payment
            print(f"  → Processing payment...")
            success = transaction.process_payment()
            transaction.refresh_from_db()
            
            if success and transaction.repayment:
                print(f"  ✓ SUCCESS! Payment processed")
                print(f"    Repayment: {transaction.repayment.receipt_number}")
                print(f"    Loan: {transaction.loan.loan_number if transaction.loan else 'N/A'}")
                print(f"    Status: {transaction.status}")
                success_count += 1
            else:
                print(f"  ✗ Payment processing failed")
                print(f"    Status: {transaction.status}")
                if transaction.processing_notes:
                    print(f"    Notes: {transaction.processing_notes}")
                failed_count += 1
                
        except Exception as e:
            print(f"  ✗ ERROR: {str(e)}")
            traceback.print_exc()
            transaction.status = 'failed'
            transaction.processing_notes = f"Error during processing: {str(e)}"
            transaction.save()
            failed_count += 1
    
    # Summary
    print("\n" + "="*70)
    print("SUMMARY")
    print("="*70)
    print(f"Total Transactions: {total_count}")
    print(f"✓ Successfully Processed: {success_count}")
    print(f"✗ Failed: {failed_count}")
    print(f"⊘ Skipped: {skipped_count}")
    print("="*70 + "\n")
    
    if success_count > 0:
        print(f"✓ {success_count} payment(s) successfully matched and processed!")
    if failed_count > 0:
        print(f"⚠ {failed_count} payment(s) could not be processed")
        print("  Reasons may include:")
        print("  - ID number not found in system")
        print("  - Borrower has no active loans")
        print("  - Other processing errors")


if __name__ == '__main__':
    auto_match_pending_payments()

