#!/usr/bin/env python
"""
Automatically process all pending M-Pesa callbacks
This will retry processing for all callbacks marked as processed=False
"""
import os
import sys
import django
from pathlib import Path

def setup_django():
    """Setup Django environment"""
    script_dir = Path(__file__).resolve().parent
    
    manage_py = script_dir / 'manage.py'
    if not manage_py.exists():
        manage_py = script_dir.parent / 'manage.py'
    
    if manage_py.exists():
        with open(manage_py, 'r') as f:
            content = f.read()
            if 'DJANGO_SETTINGS_MODULE' in content:
                import re
                match = re.search(r"os\.environ\.setdefault\(['\"]DJANGO_SETTINGS_MODULE['\"],\s*['\"]([^'\"]+)['\"]", content)
                if match:
                    os.environ.setdefault('DJANGO_SETTINGS_MODULE', match.group(1))
    
    settings_modules = [
        'config.settings',
        'settings',
        'project.settings',
        'branchsystem.settings',
        'branch_system.settings',
    ]
    
    for settings_module in settings_modules:
        try:
            os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module)
            django.setup()
            print(f"✓ Django setup successful with settings: {settings_module}")
            return True
        except Exception as e:
            continue
    
    print("✗ Error: Could not setup Django. Please set DJANGO_SETTINGS_MODULE")
    return False

def process_pending_callbacks():
    """Process all pending callbacks"""
    from loans.models import MpesaTransaction
    from payments.models import MpesaCallback
    from payments.services import PaymentProcessor
    import json
    
    print("\n" + "="*70)
    print("PROCESSING PENDING M-PESA CALLBACKS")
    print("="*70)
    
    # Find all unprocessed confirmation callbacks
    pending_callbacks = MpesaCallback.objects.filter(
        callback_type='confirmation',
        processed=False
    ).order_by('-created_at')
    
    print(f"\nFound {pending_callbacks.count()} pending callbacks")
    
    if pending_callbacks.count() == 0:
        print("✓ No pending callbacks to process")
        return
    
    processed_count = 0
    failed_count = 0
    
    for callback in pending_callbacks:
        print(f"\n{'='*70}")
        print(f"Processing callback: {callback.id}")
        
        # Get transaction ID from raw_data
        raw_data = callback.raw_data
        if isinstance(raw_data, str):
            try:
                raw_data = json.loads(raw_data)
            except:
                print(f"  ✗ Could not parse raw_data as JSON")
                failed_count += 1
                continue
        
        if not isinstance(raw_data, dict):
            print(f"  ✗ raw_data is not a dict")
            failed_count += 1
            continue
        
        trans_id = raw_data.get('TransID') or raw_data.get('TransId')
        if not trans_id:
            print(f"  ✗ No TransID in raw_data")
            failed_count += 1
            continue
        
        print(f"  TransID: {trans_id}")
        print(f"  Amount: {raw_data.get('TransAmount')}")
        print(f"  Bill Ref: {raw_data.get('BillRefNumber')}")
        
        # Check if transaction exists
        transaction = MpesaTransaction.objects.filter(trans_id=trans_id).first()
        if transaction:
            print(f"  Transaction exists: {transaction.id}")
            print(f"    Status: {transaction.status}")
            print(f"    Borrower: {transaction.borrower or 'Not matched'}")
            
            # Check if already has repayment
            try:
                repayment = transaction.repayment
                if repayment:
                    print(f"    Repayment exists: {repayment.receipt_number}")
                    # Mark callback as processed
                    callback.processed = True
                    callback.save()
                    print(f"  ✓ Callback marked as processed (repayment already exists)")
                    processed_count += 1
                    continue
            except:
                pass
            
            # Try to process if not processed
            if transaction.status != 'processed':
                print(f"  → Reprocessing transaction...")
                try:
                    success = transaction.process_payment()
                    transaction.refresh_from_db()
                    
                    if success:
                        try:
                            repayment = transaction.repayment
                            if repayment:
                                print(f"  ✓ Payment processed! Repayment: {repayment.receipt_number}")
                                callback.processed = True
                                callback.save()
                                processed_count += 1
                            else:
                                print(f"  ✗ Payment processing returned True but no repayment")
                                print(f"    Status: {transaction.status}")
                                print(f"    Notes: {transaction.processing_notes}")
                                failed_count += 1
                        except:
                            print(f"  ✗ Payment processing returned True but repayment does not exist")
                            failed_count += 1
                    else:
                        print(f"  ✗ Payment processing failed")
                        print(f"    Status: {transaction.status}")
                        print(f"    Notes: {transaction.processing_notes}")
                        failed_count += 1
                except Exception as e:
                    print(f"  ✗ Error processing: {e}")
                    import traceback
                    traceback.print_exc()
                    failed_count += 1
            else:
                print(f"  ⚠ Transaction already marked as processed but no repayment")
                failed_count += 1
        else:
            # Transaction doesn't exist - reprocess the callback
            print(f"  → Transaction not found, reprocessing callback...")
            try:
                # Reprocess the callback using PaymentProcessor
                response = PaymentProcessor.process_confirmation_callback(raw_data)
                print(f"  Response: {response}")
                
                # Check if transaction was created
                transaction = MpesaTransaction.objects.filter(trans_id=trans_id).first()
                if transaction:
                    print(f"  ✓ Transaction created: {transaction.id}")
                    try:
                        repayment = transaction.repayment
                        if repayment:
                            print(f"  ✓ Repayment created: {repayment.receipt_number}")
                            processed_count += 1
                        else:
                            print(f"  ⚠ Transaction created but no repayment")
                            failed_count += 1
                    except:
                        print(f"  ⚠ Transaction created but repayment does not exist")
                        failed_count += 1
                else:
                    print(f"  ✗ Transaction was not created")
                    failed_count += 1
            except Exception as e:
                print(f"  ✗ Error reprocessing callback: {e}")
                import traceback
                traceback.print_exc()
                failed_count += 1
    
    print(f"\n{'='*70}")
    print("SUMMARY")
    print("="*70)
    print(f"Successfully processed: {processed_count}")
    print(f"Failed: {failed_count}")
    print("="*70)

if __name__ == '__main__':
    print("="*70)
    print("AUTO-PROCESS PENDING M-PESA CALLBACKS")
    print("="*70)
    
    if not setup_django():
        sys.exit(1)
    
    process_pending_callbacks()
    
    print("\n" + "="*70)
    print("DONE")
    print("="*70)

