#!/usr/bin/env python
"""
Non-interactive script to fix CustomUser client creation issue on cPanel production
Fixes: "CustomUser() got unexpected keyword arguments" error

This script:
1. Verifies the fix is applied in users/views.py
2. Tests client creation with filtering
3. Provides rollback instructions if needed
"""
import os
import sys
import subprocess
import traceback
from pathlib import Path

# Color codes for terminal output
class Colors:
    RED = '\033[91m'
    GREEN = '\033[92m'
    YELLOW = '\033[93m'
    BLUE = '\033[94m'
    RESET = '\033[0m'
    BOLD = '\033[1m'

def print_error(message, error=None):
    """Print error message"""
    print(f"\n{Colors.RED}{Colors.BOLD}ERROR: {message}{Colors.RESET}")
    if error:
        print(f"{Colors.RED}Details: {str(error)}{Colors.RESET}")
    sys.exit(1)

def print_success(message):
    """Print success message"""
    print(f"{Colors.GREEN}✓ {message}{Colors.RESET}")

def print_info(message):
    """Print info message"""
    print(f"{Colors.BLUE}→ {message}{Colors.RESET}")

def print_warning(message):
    """Print warning message"""
    print(f"{Colors.YELLOW}⚠ {message}{Colors.RESET}")

def find_manage_py():
    """Find manage.py file"""
    current_dir = Path.cwd()
    manage_py = current_dir / 'manage.py'
    
    if not manage_py.exists():
        # Try parent directory
        parent = current_dir.parent
        manage_py = parent / 'manage.py'
        if manage_py.exists():
            os.chdir(parent)
            return manage_py
    
    if not manage_py.exists():
        print_error("manage.py not found. Please run this script from your Django project directory.")
    
    return manage_py

def get_python_path():
    """Get Python executable path"""
    python_paths = [
        '/usr/bin/python3',
        '/usr/local/bin/python3',
        'python3',
        'python',
        sys.executable
    ]
    
    for path in python_paths:
        try:
            result = subprocess.run([path, '--version'], capture_output=True, text=True)
            if result.returncode == 0:
                print_success(f"Using Python: {path} ({result.stdout.strip()})")
                return path
        except:
            continue
    
    print_error("Python executable not found")

def check_fix_applied(views_file):
    """Check if the fix is applied in users/views.py"""
    print_info("Checking if fix is applied in users/views.py...")
    
    if not views_file.exists():
        print_error(f"File not found: {views_file}")
    
    try:
        with open(views_file, 'r', encoding='utf-8') as f:
            content = f.read()
        
        # Check for key indicators of the fix
        checks = {
            'filter_valid_fields function': 'def filter_valid_fields' in content,
            'valid_fields set': 'valid_fields = {' in content and 'get_fields()' in content,
            'filtered_user_data': 'filtered_user_data = filter_valid_fields' in content,
            'filtered dictionaries': 'filtered_business_data = filter_valid_fields' in content,
            'address mapping': "'address' in user_data" in content and "physical_address" in content,
        }
        
        all_passed = all(checks.values())
        
        if all_passed:
            print_success("Fix is properly applied in users/views.py")
            return True
        else:
            print_warning("Fix may not be fully applied. Missing components:")
            for check_name, passed in checks.items():
                if not passed:
                    print_warning(f"  - {check_name}")
            return False
            
    except Exception as e:
        print_error(f"Error reading {views_file}", e)

def test_client_creation(python_path, manage_py):
    """Test client creation with a dry run"""
    print_info("Testing client creation logic...")
    
    test_script = """
import os
import sys
import django

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

from users.models import CustomUser
from django.contrib.auth import get_user_model

# Get valid fields from CustomUser model
valid_fields = {f.name for f in CustomUser._meta.get_fields()}

# Test data with invalid fields (the ones causing the error)
test_data = {
    'username': 'test_phone',
    'email': 'test@example.com',
    'phone_number': '+254712345678',
    'first_name': 'Test',
    'last_name': 'User',
    'role': 'borrower',
    'status': 'pending_approval',
    # These fields don't exist on CustomUser and should be filtered out
    'address': 'Test Address',
    'kra_pin': 'TEST123',
    'emergency_contact_name': 'Emergency Contact',
    'emergency_contact_phone': '+254798765432',
    'emergency_contact_relationship': 'Parent',
    'next_of_kin_name': 'Next of Kin',
    'next_of_kin_phone': '+254798765433',
    'next_of_kin_relationship': 'Sibling',
    'next_of_kin_id_number': '12345678',
    'bank_name': 'Test Bank',
    'bank_branch': 'Test Branch',
    'account_number': '1234567890',
    'account_name': 'Test Account',
    'mpesa_number': '+254712345678',
}

# Filter function (same as in the fix)
def filter_valid_fields(data_dict):
    return {k: v for k, v in data_dict.items() if k in valid_fields and v is not None and v != ''}

# Test filtering
filtered_data = filter_valid_fields(test_data)

# Check that invalid fields are removed
invalid_fields = ['address', 'kra_pin', 'emergency_contact_name', 'emergency_contact_phone',
                  'emergency_contact_relationship', 'next_of_kin_name', 'next_of_kin_phone',
                  'next_of_kin_relationship', 'next_of_kin_id_number', 'bank_name', 'bank_branch',
                  'account_number', 'account_name', 'mpesa_number']

removed_fields = [field for field in invalid_fields if field not in filtered_data]

if removed_fields:
    print(f"SUCCESS: Invalid fields filtered out: {', '.join(removed_fields)}")
else:
    print("WARNING: Some invalid fields may not have been filtered")

# Check that valid fields remain
valid_keys = ['username', 'email', 'phone_number', 'first_name', 'last_name', 'role', 'status']
present_keys = [key for key in valid_keys if key in filtered_data]

if len(present_keys) == len(valid_keys):
    print(f"SUCCESS: All valid fields preserved: {', '.join(present_keys)}")
else:
    print(f"WARNING: Some valid fields missing. Present: {', '.join(present_keys)}")

print("Test completed successfully!")
"""
    
    try:
        result = subprocess.run(
            [python_path, '-c', test_script],
            capture_output=True,
            text=True,
            cwd=manage_py.parent,
            timeout=30
        )
        
        if result.returncode == 0:
            print_success("Client creation test passed")
            if result.stdout:
                print(result.stdout)
            return True
        else:
            error_output = result.stderr or result.stdout
            print_warning("Test encountered issues (this may be normal if database is not accessible):")
            print(error_output[:500])
            return False
            
    except subprocess.TimeoutExpired:
        print_warning("Test timed out (this may be normal)")
        return False
    except Exception as e:
        print_warning(f"Test failed (this may be normal): {str(e)}")
        return False

def verify_file_backup(views_file):
    """Check if backup exists or create one"""
    backup_file = views_file.parent / f"{views_file.name}.backup"
    
    if backup_file.exists():
        print_success(f"Backup file exists: {backup_file}")
        return True
    else:
        print_warning(f"Backup file not found: {backup_file}")
        print_info("Creating backup before making changes...")
        try:
            import shutil
            shutil.copy2(views_file, backup_file)
            print_success(f"Backup created: {backup_file}")
            return True
        except Exception as e:
            print_warning(f"Could not create backup: {str(e)}")
            return False

def main():
    """Main function"""
    print(f"{Colors.BOLD}{Colors.BLUE}")
    print("=" * 70)
    print("  Client Creation Fix Verification Script")
    print("  Fixes: CustomUser() unexpected keyword arguments error")
    print("=" * 70)
    print(Colors.RESET)
    
    # Step 1: Find project
    print_info("Step 1: Locating Django project...")
    manage_py = find_manage_py()
    project_dir = manage_py.parent
    print_success(f"Project directory: {project_dir}")
    
    # Step 2: Get Python path
    print_info("Step 2: Finding Python executable...")
    python_path = get_python_path()
    
    # Step 3: Check fix in users/views.py
    print_info("Step 3: Verifying fix in users/views.py...")
    views_file = project_dir / 'users' / 'views.py'
    
    if not views_file.exists():
        print_error(f"users/views.py not found at: {views_file}")
    
    fix_applied = check_fix_applied(views_file)
    
    if not fix_applied:
        print_error(
            "Fix is not properly applied in users/views.py",
            "Please ensure the client_create view includes the field filtering logic"
        )
    
    # Step 4: Verify backup
    print_info("Step 4: Checking for backup file...")
    verify_file_backup(views_file)
    
    # Step 5: Test client creation logic
    print_info("Step 5: Testing client creation logic...")
    test_client_creation(python_path, manage_py)
    
    # Final summary
    print(f"\n{Colors.BOLD}{Colors.GREEN}")
    print("=" * 70)
    print("  Fix Verification Completed!")
    print("=" * 70)
    print(Colors.RESET)
    
    print("\nSUMMARY:")
    print("✓ Fix is applied in users/views.py")
    print("✓ Field filtering logic is in place")
    print("✓ Invalid fields will be filtered during client creation")
    
    print(f"\n{Colors.BOLD}WHAT WAS FIXED:{Colors.RESET}")
    print("The client_create view now filters out fields that don't exist on")
    print("the CustomUser model before calling create_user(). This prevents")
    print("the 'unexpected keyword arguments' error.")
    
    print(f"\n{Colors.BOLD}FIELDS THAT ARE FILTERED OUT:{Colors.RESET}")
    print("  - address (mapped to physical_address)")
    print("  - kra_pin")
    print("  - emergency_contact_name, emergency_contact_phone, emergency_contact_relationship")
    print("  - next_of_kin_name, next_of_kin_phone, next_of_kin_relationship, next_of_kin_id_number")
    print("  - bank_name, bank_branch, account_number, account_name, mpesa_number")
    
    print(f"\n{Colors.BOLD}NEXT STEPS:{Colors.RESET}")
    print("1. Restart your Django application in cPanel")
    print("2. Test client creation through the web interface")
    print("3. If issues persist, check the backup file for rollback")
    
    print(f"\n{Colors.YELLOW}NOTE:{Colors.RESET}")
    print("If you need to rollback, restore from: users/views.py.backup")
    print("\n")

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print(f"\n{Colors.YELLOW}Script cancelled by user{Colors.RESET}")
        sys.exit(1)
    except Exception as e:
        print_error("Unexpected error", e)

