#!/usr/bin/env python
"""
Populate the database with comprehensive sample data
"""
import os
import sys
import django
from datetime import datetime, timedelta
from decimal import Decimal
import random

# Setup Django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'branch_system.settings')
django.setup()

from django.contrib.auth import get_user_model
from users.models import Branch, RolePermission
from loans.models import LoanProduct, Loan, LoanApplication, Repayment, MpesaTransaction
from expenses.models import Expense
from django.utils import timezone

User = get_user_model()

# Sample data
FIRST_NAMES = ['John', 'Mary', 'Peter', 'Jane', 'David', 'Sarah', 'Michael', 'Grace', 'James', 'Lucy', 
               'Daniel', 'Faith', 'Joseph', 'Ruth', 'Samuel', 'Esther', 'Benjamin', 'Rebecca', 'Joshua', 'Hannah']
LAST_NAMES = ['Kamau', 'Wanjiru', 'Ochieng', 'Akinyi', 'Mwangi', 'Njeri', 'Otieno', 'Wambui', 
              'Kipchoge', 'Chebet', 'Mutua', 'Muthoni', 'Omondi', 'Adhiambo', 'Kimani', 'Wairimu']
PHONE_PREFIXES = ['0712', '0722', '0733', '0745', '0756', '0768', '0790', '0791']
COUNTIES = ['Nairobi', 'Mombasa', 'Kisumu', 'Nakuru', 'Eldoret', 'Thika', 'Kiambu', 'Machakos']
BUSINESSES = ['Retail Shop', 'Salon', 'Restaurant', 'Hardware Store', 'Boutique', 'Grocery Store', 
              'Electronics Shop', 'Pharmacy', 'Bakery', 'Butchery', 'Cyber Cafe', 'M-Pesa Shop']

def create_branches():
    """Create multiple branches"""
    print("Creating branches...")
    branches_data = [
        {'name': 'Nairobi CBD', 'code': 'NRB-CBD', 'address': 'Nairobi, Kenya', 'phone': '0712345001'},
        {'name': 'Westlands', 'code': 'NRB-WLD', 'address': 'Westlands, Nairobi', 'phone': '0712345002'},
        {'name': 'Mombasa Road', 'code': 'NRB-MSA', 'address': 'Mombasa Road, Nairobi', 'phone': '0712345003'},
        {'name': 'Thika Town', 'code': 'THK-TWN', 'address': 'Thika, Kenya', 'phone': '0712345004'},
        {'name': 'Nakuru Branch', 'code': 'NKR-BRN', 'address': 'Nakuru, Kenya', 'phone': '0712345005'},
    ]
    
    branches = []
    for data in branches_data:
        branch, created = Branch.objects.get_or_create(
            code=data['code'],
            defaults={
                'name': data['name'],
                'address': data['address'],
                'phone_number': data['phone'],
                'email': f"{data['code'].lower()}@branchbusiness.co.ke",
                'is_active': True
            }
        )
        branches.append(branch)
        if created:
            print(f"  ✓ Created branch: {branch.name}")
    
    return branches

def create_users(branches):
    """Create various users with different roles"""
    print("\nCreating users...")
    
    # Create superuser if not exists
    if not User.objects.filter(username='admin').exists():
        admin = User.objects.create_superuser(
            username='admin',
            email='admin@branch.com',
            password='admin123',
            first_name='Admin',
            last_name='User',
            phone_number='0700000000',
            role='admin',
            branch=branches[0]
        )
        print(f"  ✓ Created superuser: {admin.email}")
    else:
        print(f"  ℹ Superuser already exists")
    
    # Create branch managers
    managers = []
    for i, branch in enumerate(branches):
        if not User.objects.filter(email=f'manager{i+1}@branch.com').exists():
            manager = User.objects.create_user(
                username=f'manager{i+1}',
                email=f'manager{i+1}@branch.com',
                password='manager123',
                first_name=random.choice(FIRST_NAMES),
                last_name=random.choice(LAST_NAMES),
                phone_number=f'070000{i+1:04d}',
                role='branch_manager',
                branch=branch
            )
            managers.append(manager)
            print(f"  ✓ Created manager: {manager.email} for {branch.name}")
    
    # Create loan officers
    officers = []
    for i in range(15):
        branch = random.choice(branches)
        if not User.objects.filter(email=f'officer{i+1}@branch.com').exists():
            officer = User.objects.create_user(
                username=f'officer{i+1}',
                email=f'officer{i+1}@branch.com',
                password='officer123',
                first_name=random.choice(FIRST_NAMES),
                last_name=random.choice(LAST_NAMES),
                phone_number=f'071000{i+1:04d}',
                role='loan_officer',
                branch=branch,
                is_staff=True
            )
            officers.append(officer)
            print(f"  ✓ Created loan officer: {officer.email}")
    
    # Create borrowers
    borrowers = []
    for i in range(100):
        branch = random.choice(branches)
        phone = f"{random.choice(PHONE_PREFIXES)}{random.randint(100000, 999999)}"
        username = f'borrower{i+1}'
        
        if not User.objects.filter(username=username).exists() and not User.objects.filter(phone_number=phone).exists():
            borrower = User.objects.create_user(
                username=username,
                email=f'borrower{i+1}@example.com',
                password='borrower123',
                first_name=random.choice(FIRST_NAMES),
                last_name=random.choice(LAST_NAMES),
                phone_number=phone,
                role='borrower',
                branch=branch,
                id_number=f'{random.randint(10000000, 99999999)}',
                county=random.choice(COUNTIES),
                business_name=random.choice(BUSINESSES),
                business_address=random.choice(COUNTIES),
                monthly_income=Decimal(random.randint(20000, 150000)),
                is_phone_verified=True,
                status='active'
            )
            borrowers.append(borrower)
            if (i + 1) % 20 == 0:
                print(f"  ✓ Created {i+1} borrowers...")
        elif User.objects.filter(username=username).exists():
            borrowers.append(User.objects.get(username=username))
    
    print(f"  ✓ Total borrowers: {len(borrowers)}")
    return managers, officers, borrowers

def create_loan_products():
    """Create loan products"""
    print("\nCreating loan products...")
    
    products_data = [
        {
            'name': 'Mwamba',
            'product_type': 'mwamba',
            'min_amount': 5000,
            'max_amount': 50000,
            'interest_rate': 20.0,
            'min_duration': 30,
            'max_duration': 30,
            'processing_fee': 10.0,
            'description': 'Short-term business loan'
        },
        {
            'name': 'Boost Plus',
            'product_type': 'boost_plus',
            'min_amount': 10000,
            'max_amount': 100000,
            'interest_rate': 15.0,
            'min_duration': 30,
            'max_duration': 90,
            'processing_fee': 8.0,
            'description': 'Medium-term growth loan',
            'available_durations': [30, 60, 90]
        },
        {
            'name': 'Boost',
            'product_type': 'boost',
            'min_amount': 20000,
            'max_amount': 200000,
            'interest_rate': 12.0,
            'min_duration': 90,
            'max_duration': 180,
            'processing_fee': 5.0,
            'description': 'Long-term business expansion'
        },
        {
            'name': 'Imara',
            'product_type': 'imara',
            'min_amount': 3000,
            'max_amount': 30000,
            'interest_rate': 25.0,
            'min_duration': 14,
            'max_duration': 30,
            'processing_fee': 12.0,
            'description': 'Emergency quick loan'
        },
    ]
    
    products = []
    for data in products_data:
        product, created = LoanProduct.objects.get_or_create(
            name=data['name'],
            defaults={
                'product_type': data['product_type'],
                'min_amount': data['min_amount'],
                'max_amount': data['max_amount'],
                'interest_rate': data['interest_rate'],
                'min_duration': data['min_duration'],
                'max_duration': data['max_duration'],
                'processing_fee': data['processing_fee'],
                'description': data['description'],
                'is_active': True,
                'available_durations': data.get('available_durations', []),
                'available_repayment_methods': ['monthly']
            }
        )
        products.append(product)
        if created:
            print(f"  ✓ Created loan product: {product.name}")
    
    return products

def create_loans(borrowers, products, officers):
    """Create loans with various statuses"""
    print("\nCreating loans...")
    
    statuses = ['pending', 'approved', 'disbursed', 'active', 'completed', 'defaulted']
    loans = []
    
    for i, borrower in enumerate(borrowers[:80]):  # 80 loans
        product = random.choice(products)
        officer = random.choice(officers)
        
        # Random loan amount within product limits
        amount = Decimal(random.randint(
            int(product.min_amount), 
            int(product.max_amount)
        ))
        
        # Random duration within product limits
        duration_days = random.randint(product.min_duration, product.max_duration)
        
        # Calculate fees
        processing_fee = amount * Decimal(product.processing_fee) / 100
        interest = amount * Decimal(product.interest_rate) / 100
        total_amount = amount + processing_fee + interest
        
        # Random date in the past
        days_ago = random.randint(1, 365)
        application_date = timezone.now() - timedelta(days=days_ago)
        
        # Determine status based on age
        if days_ago < 7:
            status = random.choice(['pending', 'approved'])
        elif days_ago < 30:
            status = random.choice(['approved', 'disbursed', 'active'])
        elif days_ago < 90:
            status = random.choice(['active', 'completed'])
        else:
            status = random.choice(['completed', 'defaulted'])
        
        loan = Loan.objects.create(
            borrower=borrower,
            loan_product=product,
            amount=amount,
            processing_fee=processing_fee,
            interest_amount=interest,
            total_amount=total_amount,
            duration_days=duration_days,
            status=status,
            loan_officer=officer,
            application_date=application_date,
            approval_date=application_date + timedelta(days=1) if status != 'pending' else None,
            disbursement_date=application_date + timedelta(days=2) if status in ['disbursed', 'active', 'completed'] else None,
            due_date=application_date + timedelta(days=duration_days + 2) if status in ['active', 'completed', 'defaulted'] else None,
        )
        
        # Add some repayments for active/completed loans
        if status in ['active', 'completed', 'defaulted']:
            create_repayments_for_loan(loan)
        
        loans.append(loan)
        
        if (i + 1) % 20 == 0:
            print(f"  ✓ Created {i+1} loans...")
    
    print(f"  ✓ Total loans created: {len(loans)}")
    return loans

def create_repayments_for_loan(loan):
    """Create repayments for a loan"""
    if loan.status == 'completed':
        # Fully paid
        Repayment.objects.create(
            loan=loan,
            amount=loan.total_amount,
            payment_date=loan.disbursement_date + timedelta(days=random.randint(1, loan.duration_days)),
            payment_method='mpesa',
            transaction_code=f'MPE{random.randint(100000, 999999)}',
            received_by=loan.loan_officer
        )
    elif loan.status in ['active', 'defaulted']:
        # Partial payments
        paid_amount = loan.total_amount * Decimal(random.uniform(0.2, 0.8))
        num_payments = random.randint(1, 4)
        payment_amount = paid_amount / num_payments
        
        for i in range(num_payments):
            Repayment.objects.create(
                loan=loan,
                amount=payment_amount,
                payment_date=loan.disbursement_date + timedelta(days=random.randint(1, loan.duration_days)),
                payment_method=random.choice(['mpesa', 'cash', 'bank']),
                transaction_code=f'TXN{random.randint(100000, 999999)}',
                received_by=loan.loan_officer
            )

def create_expenses(branches, officers):
    """Create expense records"""
    print("\nCreating expenses...")
    
    categories = ['operational', 'staff', 'marketing', 'utilities', 'office', 'transport', 'maintenance']
    payment_methods = ['cash', 'mpesa', 'bank', 'cheque']
    
    expenses = []
    for i in range(150):
        branch = random.choice(branches)
        staff = random.choice(officers)
        
        days_ago = random.randint(1, 180)
        expense_date = timezone.now().date() - timedelta(days=days_ago)
        
        expense = Expense.objects.create(
            branch=branch,
            staff=staff,
            title=f'Expense {i+1}',
            description=f'Sample expense description for {random.choice(categories)}',
            category=random.choice(categories),
            amount=Decimal(random.randint(500, 50000)),
            payment_method=random.choice(payment_methods),
            paid_to=f'Vendor {random.randint(1, 50)}',
            status=random.choice(['approved', 'approved', 'approved', 'pending']),
            expense_date=expense_date,
            reference_number=f'REF{random.randint(10000, 99999)}'
        )
        expenses.append(expense)
        
        if (i + 1) % 50 == 0:
            print(f"  ✓ Created {i+1} expenses...")
    
    print(f"  ✓ Total expenses created: {len(expenses)}")
    return expenses

def create_mpesa_transactions(loans):
    """Create M-Pesa transaction records"""
    print("\nCreating M-Pesa transactions...")
    
    transactions = []
    for i, loan in enumerate(random.sample(loans, min(50, len(loans)))):
        if loan.status in ['active', 'completed']:
            transaction = MpesaTransaction.objects.create(
                merchant_request_id=f'MR{random.randint(100000, 999999)}',
                checkout_request_id=f'CR{random.randint(100000, 999999)}',
                result_code='0',
                result_desc='Success',
                amount=Decimal(random.randint(1000, 50000)),
                mpesa_receipt_number=f'MPE{random.randint(100000, 999999)}',
                transaction_date=timezone.now() - timedelta(days=random.randint(1, 90)),
                phone_number=loan.borrower.phone_number,
                status='completed',
                loan=loan
            )
            transactions.append(transaction)
    
    print(f"  ✓ Created {len(transactions)} M-Pesa transactions")
    return transactions

def main():
    print("=" * 60)
    print("POPULATING DATABASE WITH SAMPLE DATA")
    print("=" * 60)
    
    try:
        # Create data in order
        branches = create_branches()
        managers, officers, borrowers = create_users(branches)
        products = create_loan_products()
        loans = create_loans(borrowers, products, officers)
        expenses = create_expenses(branches, officers)
        transactions = create_mpesa_transactions(loans)
        
        print("\n" + "=" * 60)
        print("SUMMARY")
        print("=" * 60)
        print(f"Branches: {Branch.objects.count()}")
        print(f"Users: {User.objects.count()}")
        print(f"  - Admins: {User.objects.filter(role='admin').count()}")
        print(f"  - Branch Managers: {User.objects.filter(role='branch_manager').count()}")
        print(f"  - Loan Officers: {User.objects.filter(role='loan_officer').count()}")
        print(f"  - Borrowers: {User.objects.filter(role='borrower').count()}")
        print(f"Loan Products: {LoanProduct.objects.count()}")
        print(f"Loans: {Loan.objects.count()}")
        print(f"  - Pending: {Loan.objects.filter(status='pending').count()}")
        print(f"  - Approved: {Loan.objects.filter(status='approved').count()}")
        print(f"  - Active: {Loan.objects.filter(status='active').count()}")
        print(f"  - Completed: {Loan.objects.filter(status='completed').count()}")
        print(f"  - Defaulted: {Loan.objects.filter(status='defaulted').count()}")
        print(f"Repayments: {Repayment.objects.count()}")
        print(f"Expenses: {Expense.objects.count()}")
        print(f"M-Pesa Transactions: {MpesaTransaction.objects.count()}")
        print("=" * 60)
        print("✓ Sample data population completed successfully!")
        print("=" * 60)
        
        print("\nLOGIN CREDENTIALS:")
        print("-" * 60)
        print("Admin: admin@branch.com / admin123")
        print("Manager: manager1@branch.com / manager123")
        print("Loan Officer: officer1@branch.com / officer123")
        print("Borrower: borrower1@example.com / borrower123")
        print("-" * 60)
        
    except Exception as e:
        print(f"\n✗ Error: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)

if __name__ == '__main__':
    main()
