#!/usr/bin/env python
"""
Script pour corriger le problème de la page admin qui ne fonctionne pas en local.
Ce script résout spécifiquement les problèmes liés à Flask-Login et à la session.
"""
import os
import sys
import shutil
from pathlib import Path

# Couleurs pour les messages console
COLORS = {
    'GREEN': '\033[92m',
    'YELLOW': '\033[93m',
    'RED': '\033[91m',
    'BOLD': '\033[1m',
    'END': '\033[0m'
}

# Fonction pour afficher des messages colorés
def print_colored(message, color):
    print(f"{COLORS[color]}{message}{COLORS['END']}")

def print_header(message):
    print("\n" + "=" * 80)
    print_colored(f" {message.upper()} ", 'BOLD')
    print("=" * 80)

def print_step(step, message):
    print(f"\n{COLORS['BOLD']}[{step}]{COLORS['END']} {message}")

def print_error(message):
    print(f"{COLORS['RED']}ERROR: {message}{COLORS['END']}")

def print_success(message):
    print(f"{COLORS['GREEN']}SUCCESS: {message}{COLORS['END']}")

def print_warning(message):
    print(f"{COLORS['YELLOW']}WARNING: {message}{COLORS['END']}")

# Vérification de l'existence du fichier .env
def check_env_file():
    print_step("1", "Vérification du fichier .env...")
    env_file = Path('.env')
    if not env_file.exists():
        print_warning("Fichier .env non trouvé. Création...")
        with open(env_file, 'w') as f:
            f.write("""
# Configuration locale pour GMPL
FLASK_ENV=development
FLASK_DEBUG=1
SESSION_SECRET=gmpl_local_development_secret_key_long_enough_for_security
DATABASE_URL=sqlite:///instance/gmpl.db
UPLOAD_FOLDER=static/uploads
MAX_CONTENT_LENGTH=8388608
IMAGE_CACHE_BUSTING=true
            """.strip())
        print_success("Fichier .env créé avec une clé de session sécurisée.")
    else:
        # Vérifier que SESSION_SECRET est bien défini dans le fichier .env
        with open(env_file, 'r') as f:
            env_content = f.read()
        if 'SESSION_SECRET' not in env_content:
            print_warning("SESSION_SECRET non trouvé dans .env. Ajout...")
            with open(env_file, 'a') as f:
                f.write("\nSESSION_SECRET=gmpl_local_development_secret_key_long_enough_for_security")
            print_success("SESSION_SECRET ajouté au fichier .env.")
        else:
            print_success("Fichier .env correctement configuré.")

# Vérification de l'initialisation de flask-login dans app.py
def check_app_py():
    print_step("2", "Vérification de la configuration Flask-Login...")
    
    # Vérifier si le fichier app.py existe
    app_file = Path('app.py')
    if not app_file.exists():
        print_error("Fichier app.py non trouvé! Impossible de corriger.")
        return False
    
    # Lire le contenu actuel du fichier
    with open(app_file, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Vérifier si login_manager est initialisé
    needs_login_manager = 'login_manager = LoginManager()' not in content
    needs_init_app = 'login_manager.init_app(app)' not in content
    needs_user_loader = '@login_manager.user_loader' not in content
    needs_import = 'from flask_login import LoginManager' not in content
    
    if not (needs_login_manager or needs_init_app or needs_user_loader or needs_import):
        print_success("Configuration de Flask-Login OK.")
        return True
    
    print_warning("Flask-Login n'est pas correctement configuré. Modification du fichier app.py...")
    
    # Créer une sauvegarde du fichier original
    backup_file = Path('app.py.bak')
    shutil.copy2(app_file, backup_file)
    print_success(f"Backup créé : {backup_file}")
    
    # Modifications à apporter
    if needs_import:
        # Trouver où injecter l'import
        if 'from flask_sqlalchemy import SQLAlchemy' in content:
            content = content.replace(
                'from flask_sqlalchemy import SQLAlchemy',
                'from flask_sqlalchemy import SQLAlchemy\nfrom flask_login import LoginManager'
            )
    
    # Initialiser login_manager après db
    if needs_login_manager:
        if 'db = SQLAlchemy(model_class=Base)' in content:
            content = content.replace(
                'db = SQLAlchemy(model_class=Base)',
                'db = SQLAlchemy(model_class=Base)\nlogin_manager = LoginManager()'
            )
    
    # Initialiser login_manager.init_app après db.init_app
    if needs_init_app:
        if 'db.init_app(app)' in content:
            content = content.replace(
                'db.init_app(app)',
                'db.init_app(app)\nlogin_manager.init_app(app)\nlogin_manager.login_view = "admin.login"'
            )
    
    # Ajouter le user_loader avant with app.app_context()
    if needs_user_loader:
        if 'with app.app_context():' in content:
            user_loader_code = '''
@login_manager.user_loader
def load_user(user_id):
    from models import User
    return User.query.get(int(user_id))
'''
            content = content.replace(
                'with app.app_context():',
                f'{user_loader_code}\nwith app.app_context():'
            )
    
    # Écrire les modifications
    with open(app_file, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print_success("Flask-Login correctement configuré dans app.py.")
    return True

# Vérification de l'initialisation de flask-login dans admin_routes.py
def check_admin_routes():
    print_step("3", "Vérification des routes admin...")
    
    admin_file = Path('admin_routes.py')
    if not admin_file.exists():
        print_error("Fichier admin_routes.py non trouvé! Impossible de corriger.")
        return False
    
    # Lire le contenu actuel du fichier
    with open(admin_file, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Vérifier les imports nécessaires
    needs_import = 'from flask_login import login_user, logout_user, login_required, current_user' not in content
    
    if not needs_import:
        print_success("Configuration des routes admin OK.")
        return True
    
    print_warning("Imports manquants dans admin_routes.py. Modification...")
    
    # Créer une sauvegarde du fichier original
    backup_file = Path('admin_routes.py.bak')
    shutil.copy2(admin_file, backup_file)
    print_success(f"Backup créé : {backup_file}")
    
    # Ajouter les imports manquants
    if 'from flask import' in content:
        content = content.replace(
            'from flask import',
            'from flask import'
        )
    
    # Ajouter les imports Flask-Login si nécessaire
    if needs_import:
        if 'import os' in content:
            content = content.replace(
                'import os',
                'import os\nfrom flask_login import login_user, logout_user, login_required, current_user'
            )
        else:
            # Ajouter au début du fichier après les docstrings
            content = content.split('\n', 1)
            if len(content) > 1:
                content = content[0] + '\n\nfrom flask_login import login_user, logout_user, login_required, current_user\n' + content[1]
            else:
                content = 'from flask_login import login_user, logout_user, login_required, current_user\n' + content[0]
    
    # Vérifier que la fonction login utilise login_user
    if 'def login():' in content and 'login_user(' not in content:
        # Chercher la fonction de login et modifier
        login_function_parts = content.split('def login():')
        if len(login_function_parts) > 1:
            # Trouver où la fonction se termine par l'indentation
            function_body = login_function_parts[1].split('\n')
            indented_lines = []
            for i, line in enumerate(function_body):
                if i > 0 and (not line.strip() or not line.startswith('    ')):
                    break
                indented_lines.append(line)
            
            # Rechercher le code qui vérifie le mot de passe
            for i, line in enumerate(indented_lines):
                if 'check_password(' in line and 'if' in line:
                    # Trouver le bloc if et ajouter login_user
                    j = i + 1
                    while j < len(indented_lines) and indented_lines[j].startswith('        '):
                        if 'session[' in indented_lines[j] and 'admin' in indented_lines[j]:
                            indented_lines.insert(j, '            login_user(user)  # Flask-Login')
                            break
                        j += 1
            
            # Reconstruire la fonction et le fichier
            new_function_body = '\n'.join(indented_lines)
            login_function_parts[1] = new_function_body + login_function_parts[1][len('\n'.join(function_body)):]
            content = 'def login():'.join(login_function_parts)
    
    # Vérifier que la fonction logout utilise logout_user
    if 'def logout():' in content and 'logout_user(' not in content:
        # Chercher la fonction de logout et modifier
        logout_function_parts = content.split('def logout():')
        if len(logout_function_parts) > 1:
            # Ajouter logout_user() au début de la fonction
            function_body = logout_function_parts[1].split('\n')
            for i, line in enumerate(function_body):
                if i > 0 and line.strip() and line.startswith('    '):
                    function_body.insert(i, '    logout_user()  # Flask-Login')
                    break
            
            # Reconstruire la fonction et le fichier
            new_function_body = '\n'.join(function_body)
            logout_function_parts[1] = new_function_body
            content = 'def logout():'.join(logout_function_parts)
    
    # Ajout du décorateur login_required aux fonctions qui en ont besoin
    for route in ['dashboard', 'categories', 'products', 'services', 'users']:
        route_def = f'def {route}()'
        if route_def in content and f'@login_required' not in content.split(route_def)[0].split('\n')[-5:]:
            # Ajouter le décorateur avant la définition de fonction
            parts = content.split(route_def)
            # Trouver la ligne exacte avec le décorateur de route
            route_decorator_lines = parts[0].split('\n')[-3:]
            for i, line in enumerate(route_decorator_lines):
                if '@admin.' in line:
                    # Insérer après cette ligne
                    route_decorator_lines.insert(i+1, '@login_required')
                    break
            
            # Reconstruire le fichier
            parts[0] = '\n'.join(parts[0].split('\n')[:-3] + route_decorator_lines)
            content = route_def.join(parts)
    
    # Écrire les modifications
    with open(admin_file, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print_success("Routes admin correctement configurées.")
    return True

# Vérification du modèle User dans models.py
def check_user_model():
    print_step("4", "Vérification du modèle User...")
    
    models_file = Path('models.py')
    if not models_file.exists():
        print_error("Fichier models.py non trouvé! Impossible de corriger.")
        return False
    
    # Lire le contenu actuel du fichier
    with open(models_file, 'r', encoding='utf-8') as f:
        content = f.read()
    
    # Vérifier si le modèle User hérite de UserMixin
    needs_import = 'from flask_login import UserMixin' not in content
    needs_mixin = 'class User(UserMixin, db.Model):' not in content and 'class User(db.Model, UserMixin):' not in content
    
    if not (needs_import or needs_mixin):
        print_success("Modèle User correctement configuré.")
        return True
    
    print_warning("Le modèle User n'hérite pas de UserMixin. Modification...")
    
    # Créer une sauvegarde du fichier original
    backup_file = Path('models.py.bak')
    shutil.copy2(models_file, backup_file)
    print_success(f"Backup créé : {backup_file}")
    
    # Ajouter l'import manquant
    if needs_import:
        if 'import' in content:
            # Trouver la première ligne d'import
            import_lines = [line for line in content.split('\n') if 'import' in line]
            if import_lines:
                content = content.replace(
                    import_lines[0],
                    import_lines[0] + '\nfrom flask_login import UserMixin'
                )
        else:
            # Ajouter au début du fichier
            content = 'from flask_login import UserMixin\n' + content
    
    # Modifier la classe User pour hériter de UserMixin
    if needs_mixin:
        if 'class User(db.Model):' in content:
            content = content.replace(
                'class User(db.Model):',
                'class User(UserMixin, db.Model):'
            )
    
    # Écrire les modifications
    with open(models_file, 'w', encoding='utf-8') as f:
        f.write(content)
    
    print_success("Modèle User correctement configuré.")
    return True

# Vérification de la base de données
def check_database():
    print_step("5", "Vérification de la base de données...")
    
    # Vérifier si le dossier instance existe
    instance_dir = Path('instance')
    if not instance_dir.exists():
        print_warning("Dossier instance non trouvé. Création...")
        instance_dir.mkdir()
    
    # Vérifier si la base de données existe
    db_file = Path('instance/gmpl.db')
    if not db_file.exists() or db_file.stat().st_size < 1000:  # Moins de 1KB, probablement vide
        print_warning("Base de données non trouvée ou vide. Recréation conseillée.")
        print("Pour créer la base de données avec un administrateur par défaut, exécutez :")
        print_colored("python create_admin.py", 'BOLD')
        if os.path.exists('create_admin.py'):
            response = input("Voulez-vous créer un administrateur maintenant? (o/n): ")
            if response.lower() == 'o':
                try:
                    import create_admin
                    create_admin.create_admin_user()
                    print_success("Administrateur créé avec succès.")
                except Exception as e:
                    print_error(f"Erreur lors de la création de l'administrateur: {e}")
                    print("Exécutez le script manuellement:")
                    print_colored("python create_admin.py", 'BOLD')
        else:
            print_warning("Le script create_admin.py n'a pas été trouvé. ")
    else:
        print_success("Base de données existante trouvée.")
    
    return True

# Fonction principale
def main():
    print_header("Correction de la page admin pour le fonctionnement local")
    
    # Vérifications à effectuer
    checks = [
        check_env_file,
        check_app_py,
        check_admin_routes,
        check_user_model,
        check_database
    ]
    
    # Effectuer les vérifications
    all_successful = True
    for check in checks:
        if not check():
            all_successful = False
    
    if all_successful:
        print_header("La page admin est maintenant corrigée pour fonctionner en local")
        print(f"\n{COLORS['GREEN']}Toutes les corrections ont été appliquées avec succès.{COLORS['END']}")
        print("\nPour tester la page admin:")
        print(f"1. Exécutez: {COLORS['BOLD']}python run_local_debug.py{COLORS['END']}")
        print(f"2. Accédez à: {COLORS['BOLD']}http://localhost:5000/admin{COLORS['END']}")
        print(f"3. Identifiants: {COLORS['BOLD']}admin / admin123456{COLORS['END']}")
    else:
        print_header("Certaines corrections n'ont pas pu être appliquées")
        print(f"\n{COLORS['YELLOW']}Des erreurs ont été rencontrées lors des corrections.{COLORS['END']}")
        print("\nSolutions alternatives:")
        print("1. Exécutez le site en production avec gunicorn:")
        print(f"   {COLORS['BOLD']}gunicorn --bind 0.0.0.0:5000 wsgi:app{COLORS['END']}")
        print("2. Utilisez les sauvegardes (*. bak) pour restaurer les fichiers si nécessaire")

if __name__ == "__main__":
    main()
