#!/usr/bin/env python
"""
Diagnostic script to find root cause of payment processing issues
This script will check:
1. If callback is being received
2. If transaction is created
3. If borrower matching works
4. If repayment creation works
5. Where the process is failing
"""
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 diagnose_transaction(trans_id):
    """Diagnose a specific transaction"""
    from loans.models import MpesaTransaction
    from payments.models import MpesaCallback
    from django.contrib.auth import get_user_model
    
    User = get_user_model()
    
    print("\n" + "="*70)
    print(f"DIAGNOSING TRANSACTION: {trans_id}")
    print("="*70)
    
    # Step 1: Check callback
    print("\n[Step 1] Checking M-Pesa Callback...")
    try:
        callback = MpesaCallback.objects.filter(
            raw_data__TransID=trans_id
        ).first()
        
        if not callback:
            # Try different lookup
            callbacks = MpesaCallback.objects.filter(callback_type='confirmation')
            for cb in callbacks[:10]:
                if isinstance(cb.raw_data, dict) and cb.raw_data.get('TransID') == trans_id:
                    callback = cb
                    break
        
        if callback:
            print(f"✓ Callback found: {callback.id}")
            print(f"  Type: {callback.callback_type}")
            print(f"  Processed: {callback.processed}")
            print(f"  Created: {callback.created_at}")
            print(f"  Has transaction: {callback.transaction is not None}")
            
            if isinstance(callback.raw_data, dict):
                print(f"  TransID: {callback.raw_data.get('TransID')}")
                print(f"  Amount: {callback.raw_data.get('TransAmount')}")
                print(f"  Bill Ref: {callback.raw_data.get('BillRefNumber')}")
                print(f"  Phone: {callback.raw_data.get('MSISDN')}")
        else:
            print(f"✗ No callback found for TransID: {trans_id}")
            print("  This means the callback was never received or stored")
            return
    except Exception as e:
        print(f"✗ Error checking callback: {e}")
        import traceback
        traceback.print_exc()
        return
    
    # Step 2: Check transaction
    print("\n[Step 2] Checking M-Pesa Transaction...")
    try:
        transaction = MpesaTransaction.objects.filter(trans_id=trans_id).first()
        
        if transaction:
            print(f"✓ Transaction found: {transaction.id}")
            print(f"  Status: {transaction.status}")
            print(f"  Amount: {transaction.amount}")
            print(f"  Bill Ref (ID): {transaction.bill_ref_number}")
            print(f"  Phone: {transaction.msisdn or transaction.phone_number}")
            print(f"  Borrower: {transaction.borrower or 'Not matched'}")
            print(f"  Loan: {transaction.loan or 'Not matched'}")
            print(f"  Repayment: {transaction.repayment or 'Not created'}")
            print(f"  Processing Notes: {transaction.processing_notes or 'None'}")
            
            # Check if borrower should match
            if transaction.bill_ref_number:
                print(f"\n[Step 2a] Checking borrower matching for ID: {transaction.bill_ref_number}")
                try:
                    borrower = User.objects.get(id_number=transaction.bill_ref_number, role='borrower')
                    print(f"✓ Borrower found by ID: {borrower.get_full_name()}")
                    print(f"  Phone in system: {borrower.phone_number}")
                    print(f"  Phone from payment: {transaction.msisdn or transaction.phone_number}")
                    
                    if transaction.borrower != borrower:
                        print(f"⚠ MISMATCH: Transaction borrower is {transaction.borrower}, but borrower with ID {transaction.bill_ref_number} exists!")
                        print(f"  This suggests match_borrower() is not working correctly")
                except User.DoesNotExist:
                    print(f"✗ No borrower found with ID number: {transaction.bill_ref_number}")
                except User.MultipleObjectsReturned:
                    borrowers = User.objects.filter(id_number=transaction.bill_ref_number, role='borrower')
                    print(f"⚠ Multiple borrowers found with ID {transaction.bill_ref_number}: {borrowers.count()}")
        else:
            print(f"✗ No transaction found for TransID: {trans_id}")
            print("  This means process_confirmation_callback() did not create the transaction")
            
            # Try to manually create it from callback
            if callback and isinstance(callback.raw_data, dict):
                print("\n  Attempting to create transaction from callback...")
                try:
                    from decimal import Decimal
                    data = callback.raw_data
                    transaction = MpesaTransaction.objects.create(
                        trans_id=data.get('TransID'),
                        transaction_type=data.get('TransactionType', 'Pay Bill'),
                        amount=Decimal(str(data.get('TransAmount', 0))),
                        phone_number=data.get('MSISDN', '')[:17],
                        msisdn=data.get('MSISDN', '')[:17],
                        trans_time=data.get('TransTime'),
                        business_short_code=data.get('BusinessShortCode'),
                        bill_ref_number=data.get('BillRefNumber'),
                        invoice_number=data.get('InvoiceNumber'),
                        org_account_balance=data.get('OrgAccountBalance'),
                        third_party_trans_id=data.get('ThirdPartyTransID'),
                        first_name=data.get('FirstName'),
                        middle_name=data.get('MiddleName'),
                        last_name=data.get('LastName'),
                        raw_confirmation_data=data,
                        status='confirmed',
                        is_automatic=True,
                        payment_source='automatic'
                    )
                    print(f"✓ Created transaction: {transaction.id}")
                except Exception as e:
                    print(f"✗ Error creating transaction: {e}")
                    import traceback
                    traceback.print_exc()
                    return
    except Exception as e:
        print(f"✗ Error checking transaction: {e}")
        import traceback
        traceback.print_exc()
        return
    
    # Step 3: Test borrower matching
    if transaction and not transaction.borrower:
        print("\n[Step 3] Testing borrower matching...")
        try:
            borrower = transaction.match_borrower()
            transaction.refresh_from_db()
            
            if borrower:
                print(f"✓ match_borrower() returned borrower: {borrower.get_full_name()}")
                print(f"  Transaction borrower after match: {transaction.borrower}")
            else:
                print(f"✗ match_borrower() returned None")
                print(f"  Processing notes: {transaction.processing_notes}")
        except Exception as e:
            print(f"✗ Error in match_borrower(): {e}")
            import traceback
            traceback.print_exc()
    
    # Step 4: Test repayment creation
    if transaction and transaction.borrower and not transaction.repayment:
        print("\n[Step 4] Testing repayment creation...")
        try:
            repayment = transaction.create_repayment()
            
            if repayment:
                print(f"✓ create_repayment() returned repayment: {repayment.id}")
                print(f"  Receipt: {repayment.receipt_number}")
                print(f"  Amount: {repayment.amount}")
                transaction.refresh_from_db()
                print(f"  Transaction repayment after create: {transaction.repayment}")
            else:
                print(f"✗ create_repayment() returned None")
                transaction.refresh_from_db()
                print(f"  Status: {transaction.status}")
                print(f"  Processing notes: {transaction.processing_notes}")
        except Exception as e:
            print(f"✗ Error in create_repayment(): {e}")
            import traceback
            traceback.print_exc()
    
    # Step 5: Test full payment processing
    if transaction and transaction.status != 'processed':
        print("\n[Step 5] Testing full payment processing...")
        try:
            success = transaction.process_payment()
            transaction.refresh_from_db()
            
            if success:
                print(f"✓ process_payment() returned True")
                print(f"  Status: {transaction.status}")
                print(f"  Repayment: {transaction.repayment or 'None'}")
            else:
                print(f"✗ process_payment() returned False")
                print(f"  Status: {transaction.status}")
                print(f"  Processing notes: {transaction.processing_notes}")
        except Exception as e:
            print(f"✗ Error in process_payment(): {e}")
            import traceback
            traceback.print_exc()
    
    print("\n" + "="*70)
    print("DIAGNOSIS COMPLETE")
    print("="*70)

def main():
    """Main function"""
    print("="*70)
    print("PAYMENT PROCESSING DIAGNOSTIC TOOL")
    print("="*70)
    
    if not setup_django():
        sys.exit(1)
    
    # Check recent unprocessed transactions
    from loans.models import MpesaTransaction
    from payments.models import MpesaCallback
    
    print("\nChecking for recent callbacks...")
    recent_callbacks = MpesaCallback.objects.filter(
        callback_type='confirmation'
    ).order_by('-created_at')[:5]
    
    if recent_callbacks.exists():
        print(f"Found {recent_callbacks.count()} recent callbacks")
        for cb in recent_callbacks:
            trans_id = None
            if isinstance(cb.raw_data, dict):
                trans_id = cb.raw_data.get('TransID')
            print(f"\n  - {trans_id or 'Unknown'} - Processed: {cb.processed} - Created: {cb.created_at}")
    
    # Diagnose the specific transaction
    trans_id = "TK5019CRJZ"
    diagnose_transaction(trans_id)
    
    print("\n" + "="*70)
    print("RECOMMENDATIONS")
    print("="*70)
    print("1. Check the callback's 'processed' status - if True but no repayment, callback was marked processed too early")
    print("2. Check if transaction was created - if not, get_or_create might be failing")
    print("3. Check borrower matching - if ID matches but borrower not linked, match_borrower() has an issue")
    print("4. Check repayment creation - if borrower exists but no repayment, create_repayment() has an issue")
    print("="*70)

if __name__ == '__main__':
    main()

