#!/usr/bin/env python
"""
Fix transactions marked as 'processed' but don't have repayments
This script will:
1. Find all transactions with status='processed' but no repayment
2. Reset their status and reprocess them
3. Fix callbacks that are marked processed but transactions aren't fully processed
"""
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 fix_transactions():
    """Find and fix transactions marked processed but without repayments"""
    from loans.models import MpesaTransaction
    from payments.models import MpesaCallback
    
    print("\n" + "="*70)
    print("FIXING TRANSACTIONS MARKED PROCESSED WITHOUT REPAYMENTS")
    print("="*70)
    
    # Find transactions with status='processed' but no repayment
    broken_transactions = []
    
    # Method 1: Check transactions with status='processed'
    transactions = MpesaTransaction.objects.filter(status='processed')
    print(f"\nFound {transactions.count()} transactions with status='processed'")
    
    for transaction in transactions:
        try:
            # Try to access repayment - if it doesn't exist, this will raise DoesNotExist
            repayment = transaction.repayment
            if not repayment:
                broken_transactions.append(transaction)
        except Exception:
            # Repayment doesn't exist
            broken_transactions.append(transaction)
    
    print(f"Found {len(broken_transactions)} broken transactions (marked processed but no repayment)")
    
    if not broken_transactions:
        print("\n✓ No broken transactions found!")
        return
    
    # Fix each transaction
    fixed_count = 0
    failed_count = 0
    
    for transaction in broken_transactions:
        print(f"\n{'='*70}")
        print(f"Fixing transaction: {transaction.trans_id}")
        print(f"  Amount: {transaction.amount}")
        print(f"  Borrower: {transaction.borrower or 'Not matched'}")
        print(f"  Status: {transaction.status}")
        print(f"  Processing Notes: {transaction.processing_notes or 'None'}")
        
        try:
            # Reset status to allow reprocessing
            original_status = transaction.status
            transaction.status = 'confirmed'
            transaction.repayment = None  # Clear the broken link
            transaction.save()
            
            print(f"  → Reset status from '{original_status}' to 'confirmed'")
            
            # Try to reprocess
            if transaction.borrower:
                print(f"  → Reprocessing payment...")
                success = transaction.process_payment()
                transaction.refresh_from_db()
                
                if success and transaction.repayment:
                    print(f"  ✓ Payment reprocessed successfully!")
                    print(f"    Repayment: {transaction.repayment.id} ({transaction.repayment.receipt_number})")
                    print(f"    Status: {transaction.status}")
                    fixed_count += 1
                else:
                    print(f"  ✗ Payment reprocessing failed")
                    print(f"    Status: {transaction.status}")
                    print(f"    Notes: {transaction.processing_notes}")
                    failed_count += 1
            else:
                print(f"  ⚠ Cannot reprocess - borrower not matched")
                print(f"    Status: {transaction.status}")
                failed_count += 1
                
        except Exception as e:
            print(f"  ✗ Error fixing transaction: {e}")
            import traceback
            traceback.print_exc()
            failed_count += 1
    
    # Fix callbacks that are marked processed but transactions aren't fully processed
    print(f"\n{'='*70}")
    print("FIXING CALLBACKS MARKED PROCESSED BUT TRANSACTIONS NOT FULLY PROCESSED")
    print("="*70)
    
    callbacks = MpesaCallback.objects.filter(
        callback_type='confirmation',
        processed=True
    )
    
    callback_fixed_count = 0
    for callback in callbacks:
        if callback.transaction:
            transaction = callback.transaction
            try:
                # Check if repayment exists
                repayment = transaction.repayment
                if not repayment:
                    # Callback is marked processed but transaction has no repayment
                    print(f"\n  Fixing callback: {callback.id}")
                    print(f"    Transaction: {transaction.trans_id}")
                    print(f"    Status: {transaction.status}")
                    
                    # Reset callback so it can be reprocessed
                    callback.processed = False
                    callback.save()
                    callback_fixed_count += 1
                    print(f"    ✓ Reset callback processed status")
            except Exception:
                # Repayment doesn't exist
                print(f"\n  Fixing callback: {callback.id}")
                print(f"    Transaction: {transaction.trans_id}")
                print(f"    Status: {transaction.status}")
                
                # Reset callback so it can be reprocessed
                callback.processed = False
                callback.save()
                callback_fixed_count += 1
                print(f"    ✓ Reset callback processed status")
    
    print(f"\n{'='*70}")
    print("SUMMARY")
    print("="*70)
    print(f"Transactions fixed: {fixed_count}")
    print(f"Transactions failed: {failed_count}")
    print(f"Callbacks reset: {callback_fixed_count}")
    print("="*70)
    
    if fixed_count > 0:
        print("\n✓ Some transactions were successfully fixed!")
        print("  They should now appear in the repayments page.")
    
    if failed_count > 0:
        print(f"\n⚠ {failed_count} transactions could not be automatically fixed.")
        print("  They may need manual intervention (e.g., borrower matching, loan creation).")
    
    if callback_fixed_count > 0:
        print(f"\n✓ {callback_fixed_count} callbacks were reset.")
        print("  They will be reprocessed on the next callback or can be manually processed.")

def main():
    """Main function"""
    print("="*70)
    print("FIX PROCESSED TRANSACTIONS WITHOUT REPAYMENTS")
    print("="*70)
    
    if not setup_django():
        sys.exit(1)
    
    fix_transactions()
    
    print("\n" + "="*70)
    print("DONE")
    print("="*70)

if __name__ == '__main__':
    main()

