from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify
from flask_mysqldb import MySQL
import mysql.connector
from datetime import date, datetime, time, timedelta
import os
import hashlib
import json
from functools import wraps

app = Flask(__name__)

# Configuration de l'application
app.config.update(
    SECRET_KEY='biogalenic_gmao_2024_secret_key_very_long_and_secure',
    PERMANENT_SESSION_LIFETIME=timedelta(hours=24),
    SESSION_REFRESH_EACH_REQUEST=True,
    SESSION_COOKIE_SECURE=False,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax',
    SESSION_COOKIE_NAME='gmao_session',
    MYSQL_HOST='localhost',
    MYSQL_USER='root',
    MYSQL_PASSWORD='',
    MYSQL_DB='gestion_mei_1',
    MYSQL_CURSORCLASS='DictCursor',
    MYSQL_CONNECT_TIMEOUT=28800,
    MYSQL_READ_TIMEOUT=28800,
    MYSQL_WRITE_TIMEOUT=28800
)

# Initialisation de MySQL
mysql = MySQL(app)

PERMISSION_KEYS = [
    'interventions', 'equipements', 'pieces', 'preventifs', 'ordres',
    'fournisseurs', 'commandes', 'familles', 'operations', 'operateurs',
    'qualifications', 'outillages', 'gammes', 'constats', 'rapports',
    'utilisateurs', 'roles', 'activites', 'can_edit', 'can_add', 'can_delete',
    'export_data', 'valider_demande'
]

NOTIF_KEYS = [
    'nouvelle_intervention', 'intervention_urgente', 'intervention_traitee',
    'stock_alerte', 'maintenance_preventive', 'ordre_travail'
]

ALL_TRUE_PERMISSIONS  = {k: True  for k in PERMISSION_KEYS}
ALL_FALSE_PERMISSIONS = {k: False for k in PERMISSION_KEYS}

# Reconnexion automatique si MySQL coupe la connexion
def get_cursor():
    try:
        return mysql.connection.cursor()
    except Exception:
        mysql.connection.ping(reconnect=True)
        return mysql.connection.cursor()

# Fonction de vérification de connexion
def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:
            flash('Veuillez vous connecter pour accéder à cette page', 'danger')
            return redirect(url_for('login'))
        # Rafraîchir la session à chaque requête
        session.modified = True
        try:
            return f(*args, **kwargs)
        except Exception as e:
            import traceback
            print('ERREUR ROUTE:', traceback.format_exc())
            try:
                mysql.connection.rollback()
            except:
                pass
            flash('Une erreur est survenue. Veuillez réessayer.', 'danger')
            return redirect(request.referrer or url_for('dashboard'))
    return decorated_function

# Décorateurs de contrôle d'accès par rôle
def role_required(*roles):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if 'user_role' not in session:
                flash('Veuillez vous connecter pour accéder à cette page', 'danger')
                return redirect(url_for('login'))
            # SUPER ADMIN passe toujours, sinon vérifier si le rôle est autorisé
            if session['user_role'] != 'SUPER ADMIN' and session['user_role'] not in roles:
                flash('Vous n\'avez pas les droits nécessaires pour accéder à cette page', 'danger')
                return redirect(url_for('dashboard'))
            return f(*args, **kwargs)
        return decorated_function
    return decorator

# Décorateur pour les administrateurs uniquement
def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_role' not in session:
            flash('Veuillez vous connecter pour accéder à cette page', 'danger')
            return redirect(url_for('login'))
        
        # Les super admins et la direction ont accès à toutes les fonctionnalités
        admin_roles = ['SUPER ADMIN', 'DIRECTION', 'CHEF DEPARTEMENT']
        if session['user_role'] not in admin_roles:
            flash('Vous n\'avez pas les droits administratifs nécessaires', 'danger')
            return redirect(url_for('dashboard'))
        
        return f(*args, **kwargs)
    return decorated_function

# Décorateur pour les super administrateurs uniquement
def superadmin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if session.get('user_role') != 'SUPER ADMIN':
            flash("Accès réservé aux Super Admins.", 'danger')
            return redirect(url_for('dashboard'))
        return f(*args, **kwargs)
    return decorated_function

# Décorateur granulaire par clé de permission (module ou action)
# Usage: @perm_required('interventions')  ou  @perm_required('can_edit')
def perm_required(perm_key):
    """Vérifie qu'un utilisateur possède une permission précise.
    SUPER ADMIN bypasse toujours ce contrôle.
    """
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if 'user_id' not in session:
                flash('Veuillez vous connecter.', 'danger')
                return redirect(url_for('login'))
            # SUPER ADMIN a toujours accès
            if session.get('user_role') == 'SUPER ADMIN':
                return f(*args, **kwargs)
            perms = get_role_permissions(session.get('user_role', ''))
            if not perms.get(perm_key):
                flash(f"Accès refusé : vous n'avez pas la permission requise pour cette page.", 'danger')
                return redirect(url_for('dashboard'))
            return f(*args, **kwargs)
        return decorated_function
    return decorator

# Fonction pour vérifier les accès en fonction du rôle (colonne type de la table user)
def get_role_permissions(role):
    # Short-circuit pour SUPER ADMIN
    if role == 'SUPER ADMIN':
        return ALL_TRUE_PERMISSIONS

    try:
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT * FROM roles WHERE name = %s LIMIT 1", (role,))
        row = cursor.fetchone()
        cursor.close()

        if not row:
            app.logger.warning(f"Role '{role}' not found in roles table. Falling back to safe defaults.")
            return ALL_FALSE_PERMISSIONS

        # Map current DB columns to the permission dict
        permissions = {}
        for key in PERMISSION_KEYS:
            permissions[key] = bool(row.get(key, False))
        return permissions
    except Exception as e:
        app.logger.error(f"Error resolving permissions for role '{role}': {e}. Falling back to safe defaults.")
        return ALL_FALSE_PERMISSIONS

# Helper pour ajouter une notification dans la base de données
def add_db_notification(notif_key, title, message, type='info', link=None, user_id=None, role_name=None, permission_required=None):
    try:
        cursor = mysql.connection.cursor()
        cursor.execute("""
            INSERT INTO notifications (user_id, role_name, permission_required, title, message, type, notif_key, link)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
        """, (user_id, role_name, permission_required, title, message, type, notif_key, link))
        mysql.connection.commit()
        cursor.close()
    except Exception as e:
        app.logger.error(f"Error adding DB notification: {e}")

# Injecter les permissions dans tous les templates
@app.context_processor
def inject_permissions():
    if 'user_role' in session:
        role = session['user_role']
        permissions = get_role_permissions(role)
        return {'permissions': permissions, 'user_role': role}
    return {'permissions': {}, 'user_role': None}

# Injecter la config notifications dans tous les templates
@app.context_processor
def inject_notif_config():
    nc = {}
    if 'notif_config' in session:
        try: nc = json.loads(session['notif_config'])
        except: pass
    return {'notif_config_json': json.dumps(nc)}

# Injecter la date actuelle dans tous les templates
@app.context_processor
def inject_now():
    return {'now': datetime.now()}

# Injecter le compteur d'interventions en cours (pour badge sidebar)
@app.context_processor
def inject_pending_count():
    if 'user_id' not in session:
        return {'pending_interventions_count': 0}
    try:
        perms = get_role_permissions(session.get('user_role', ''))
        if not perms.get('interventions'):
            return {'pending_interventions_count': 0}
        
        is_admin = session.get('user_role') in ('SUPER ADMIN', 'DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
        
        # Le badge de la sidebar n'a de sens que pour l'équipe admin/maintenance
        # Il indique les interventions non encore consultées (nouvelles demandes)
        if is_admin:
            cursor = mysql.connection.cursor()
            cursor.execute(
                "SELECT COUNT(*) as n FROM dr WHERE est_consulter='non' AND annuler='non'"
            )
            count = cursor.fetchone()['n']
            cursor.close()
            return {'pending_interventions_count': count}
        else:
            # L'utilisateur normal n'a pas besoin d'un badge dans la sidebar
            # Il sait déjà qu'il a des demandes en cours
            return {'pending_interventions_count': 0}
    except Exception:
        return {'pending_interventions_count': 0}

# Routes
@app.route('/')
def index():
    if 'user_id' in session:
        return redirect(url_for('dashboard'))
    return redirect(url_for('login'))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # Connexion à la base de données
        cursor = mysql.connection.cursor()
        
        # Tentative d'authentification avec la table user
        # Hasher le mot de passe avec SHA-1 pour comparaison
        import hashlib
        hashed_password = hashlib.sha1(password.encode()).hexdigest()
        
        user_from_user_table = None
        try:
            # Vérifier si l'utilisateur existe dans la table user et est actif
            cursor.execute("SELECT * FROM user WHERE username = %s AND connect = 'oui'", [username])
            user_from_user_table = cursor.fetchone()
        except mysql.connection.Error as e:
            # Si la colonne 'connect' n'existe pas, ignorer l'erreur et continuer
            # Cela permet à l'authentification de secours de fonctionner.
            if e.args[0] == 1054: # Code d'erreur pour "Unknown column"
                flash("Avertissement : La table 'user' n'est pas à jour. Tentative avec l'ancienne méthode.", 'warning')
            else:
                # Pour les autres erreurs de base de données, les afficher
                raise
        
        if user_from_user_table and user_from_user_table['password'] == hashed_password:
            session.permanent = True
            session['user_id']   = user_from_user_table['id']
            session['username']  = user_from_user_table['username']
            session['user_role'] = user_from_user_table['type']
            # Charger la config notifications
            try:
                nc = json.loads(user_from_user_table.get('notif_config') or '{}')
            except Exception:
                nc = {}
            session['notif_config'] = json.dumps(nc)
            flash('Connexion réussie!', 'success')
            return redirect(url_for('dashboard'))
        else:
            # Tentative d'authentification avec la table utilisateurs (rétrocompatibilité)
            cursor.execute("SELECT * FROM utilisateurs WHERE username = %s", [username])
            user_from_utilisateurs_table = cursor.fetchone()
            
            if user_from_utilisateurs_table and user_from_utilisateurs_table['password'] == hashed_password:
                # Utilisateur trouvé dans la table utilisateurs
                session.permanent = True
                session['user_id'] = user_from_utilisateurs_table['id']
                session['username'] = user_from_utilisateurs_table['username']
                session['user_role'] = user_from_utilisateurs_table['role']
                
                flash('Connexion réussie!', 'success')
                return redirect(url_for('dashboard'))
            else:
                flash('Nom d\'utilisateur ou mot de passe incorrect', 'danger')
        
        cursor.close()
        
    return render_template('login.html')

@app.route('/logout')
def logout():
    # Supprimer l'utilisateur de la session
    session.pop('user_id', None)
    session.pop('username', None)
    session.pop('user_role', None)
    session.pop('permissions', None)
    flash('Vous avez été déconnecté.', 'success')
    return redirect(url_for('login'))

@app.route('/profil')
@login_required
def profil_utilisateur():
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM user WHERE id = %s", (session['user_id'],))
    user = cursor.fetchone()
    cursor.close()
    if not user:
        flash('Utilisateur non trouvé.', 'danger')
        return redirect(url_for('dashboard'))
    return render_template('utilisateurs/profil.html', user=user)

@app.route('/api/user_stats')
@login_required
def api_user_stats():
    username = session['username']
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT COUNT(*) as n FROM dr WHERE username = %s", [username])
    created = cursor.fetchone()['n']
    cursor.execute("SELECT COUNT(*) as n FROM dr WHERE username = %s AND est_traiter = 'oui'", [username])
    done = cursor.fetchone()['n']
    cursor.execute("SELECT COUNT(*) as n FROM dr WHERE username = %s AND est_traiter = 'non' AND annuler = 'non'", [username])
    pending = cursor.fetchone()['n']
    cursor.execute("SELECT COUNT(*) as n FROM dr WHERE username = %s AND annuler = 'oui'", [username])
    cancelled = cursor.fetchone()['n']
    cursor.close()
    return jsonify({'created': created, 'done': done, 'pending': pending, 'cancelled': cancelled})

@app.route('/api/notifications')
@login_required
def get_notifications():
    try:
        user_role = session.get('user_role', '')
        user_id = session.get('user_id')
        perms = get_role_permissions(user_role)
        
        cursor = mysql.connection.cursor()
        
        # Récupérer les notifications des 7 derniers jours
        cursor.execute("""
            SELECT * FROM notifications 
            WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
            ORDER BY id DESC
        """)
        all_notifs = cursor.fetchall()
        cursor.close()
        
        filtered_notifs = []
        for n in all_notifs:
            # Si la notif cible un user particulier
            if n.get('user_id') is not None:
                if n.get('user_id') != user_id:
                    continue
            # Si elle cible un rôle particulier
            elif n.get('role_name') is not None:
                if n.get('role_name') != user_role:
                    continue
            # Si elle cible une permission spécifique
            elif n.get('permission_required') is not None:
                perm = n.get('permission_required')
                if not perms.get(perm, False):
                    continue
            
            # Format date pour json
            n['timestamp'] = n['created_at'].isoformat()
            if 'created_at' in n:
                del n['created_at']
                
            filtered_notifs.append(n)
            
        return jsonify(filtered_notifs)
    except Exception as e:
        app.logger.error(f"Error fetching notifications: {e}")
        return jsonify([])

@app.route('/parametres', methods=['GET', 'POST'])
@login_required
def parametres_utilisateur():
    # Récupérer les informations de l'utilisateur connecté
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM user WHERE id = %s", (session['user_id'],))
    user = cursor.fetchone()
    
    if not user:
        cursor.close()
        flash('Utilisateur non trouvé.', 'danger')
        return redirect(url_for('dashboard'))
    
    if request.method == 'POST':
        # Vérifier si l'utilisateur essaie de changer son mot de passe
        current_password = request.form.get('current_password')
        new_password = request.form.get('new_password')
        confirm_password = request.form.get('confirm_password')
        
        if current_password and new_password and confirm_password:
            # Vérifier que le mot de passe actuel est correct
            hashed_current_password = hashlib.sha1(current_password.encode()).hexdigest()
            
            if hashed_current_password != user['password']:
                flash('Le mot de passe actuel est incorrect.', 'danger')
            elif new_password != confirm_password:
                flash('Les nouveaux mots de passe ne correspondent pas.', 'danger')
            elif len(new_password) < 6:
                flash('Le nouveau mot de passe doit contenir au moins 6 caractères.', 'danger')
            else:
                # Hacher le nouveau mot de passe et le mettre à jour dans la base de données
                hashed_new_password = hashlib.sha1(new_password.encode()).hexdigest()
                cursor.execute("UPDATE user SET password = %s WHERE id = %s", (hashed_new_password, session['user_id']))
                mysql.connection.commit()
                flash('Mot de passe mis à jour avec succès.', 'success')
        
        # Gérer les préférences (notifications)
        notifications = 'notifications' in request.form
        # Vous pourriez stocker ces préférences dans la base de données si nécessaire
        
        cursor.close()
        return redirect(url_for('parametres_utilisateur'))
    
    cursor.close()
    return render_template('utilisateurs/parametres.html', user=user)

@app.route('/dashboard')
@login_required
def dashboard():
    cursor = mysql.connection.cursor()
    perms = get_role_permissions(session.get('user_role', ''))
    user_only = session.get('user_role') not in ('SUPER ADMIN', 'DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')

    usr = session['username']

    # ── KPIs interventions (only if role has interventions access) ──
    total_interventions = 0
    interventions_en_cours = 0
    interventions_urgentes = 0
    interventions_terminees = 0
    interventions_annulees = 0
    dernieres_interventions = []
    par_degre = []
    par_mois = []
    urgentes_liste = []

    if perms.get('interventions'):
        if user_only:
            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE username = %s", [usr])
            total_interventions = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE est_traiter = 'non' AND annuler = 'non' AND username = %s", [usr])
            interventions_en_cours = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE est_traiter = 'non' AND annuler = 'non' AND degre = 'Trés urgent' AND username = %s", [usr])
            interventions_urgentes = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE est_traiter = 'oui' AND username = %s", [usr])
            interventions_terminees = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE annuler = 'oui' AND username = %s", [usr])
            interventions_annulees = cursor.fetchone()['n']

            # Dernières interventions
            cursor.execute("""
                SELECT dr.*, mei.designation
                FROM dr JOIN mei ON dr.id_mei = mei.id
                WHERE dr.annuler = 'non' AND dr.username = %s
                ORDER BY dr.date DESC, dr.id DESC
                LIMIT 8
            """, [usr])
            dernieres_interventions = cursor.fetchall()

            # Interventions par degré (pour graphique)
            cursor.execute("""
                SELECT degre, COUNT(*) as n FROM dr
                WHERE annuler = 'non' AND username = %s
                GROUP BY degre
            """, [usr])
            par_degre = cursor.fetchall()

            # Interventions par mois (12 derniers mois)
            cursor.execute("""
                SELECT DATE_FORMAT(date, '%%Y-%%m') as mois, COUNT(*) as n
                FROM dr
                WHERE date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) AND username = %s
                GROUP BY mois ORDER BY mois
            """, [usr])
            par_mois = cursor.fetchall()

            # Interventions urgentes en cours (liste)
            cursor.execute("""
                SELECT dr.*, mei.designation
                FROM dr JOIN mei ON dr.id_mei = mei.id
                WHERE dr.est_traiter = 'non' AND dr.annuler = 'non' AND dr.degre = 'Trés urgent' AND dr.username = %s
                ORDER BY dr.date DESC LIMIT 5
            """, [usr])
            urgentes_liste = cursor.fetchall()
        else:
            cursor.execute("SELECT COUNT(*) as n FROM dr")
            total_interventions = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE est_traiter = 'non' AND annuler = 'non'")
            interventions_en_cours = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE est_traiter = 'non' AND annuler = 'non' AND degre = 'Trés urgent'")
            interventions_urgentes = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE est_traiter = 'oui'")
            interventions_terminees = cursor.fetchone()['n']

            cursor.execute("SELECT COUNT(*) as n FROM dr WHERE annuler = 'oui'")
            interventions_annulees = cursor.fetchone()['n']

            # Dernières interventions
            cursor.execute("""
                SELECT dr.*, mei.designation
                FROM dr JOIN mei ON dr.id_mei = mei.id
                WHERE dr.annuler = 'non'
                ORDER BY dr.date DESC, dr.id DESC
                LIMIT 8
            """)
            dernieres_interventions = cursor.fetchall()

            # Interventions par degré (pour graphique)
            cursor.execute("""
                SELECT degre, COUNT(*) as n FROM dr
                WHERE annuler = 'non'
                GROUP BY degre
            """)
            par_degre = cursor.fetchall()

            # Interventions par mois (12 derniers mois)
            cursor.execute("""
                SELECT DATE_FORMAT(date, '%%Y-%%m') as mois, COUNT(*) as n
                FROM dr
                WHERE date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
                GROUP BY mois ORDER BY mois
            """)
            par_mois = cursor.fetchall()

            # Interventions urgentes en cours (liste)
            cursor.execute("""
                SELECT dr.*, mei.designation
                FROM dr JOIN mei ON dr.id_mei = mei.id
                WHERE dr.est_traiter = 'non' AND dr.annuler = 'non' AND dr.degre = 'Trés urgent'
                ORDER BY dr.date DESC LIMIT 5
            """)
            urgentes_liste = cursor.fetchall()

    # ── KPIs équipements (only if role has equipements access) ──
    total_equipements = 0
    top_equipements = []

    if perms.get('equipements'):
        cursor.execute("SELECT COUNT(*) as n FROM mei")
        total_equipements = cursor.fetchone()['n']

        # Top 5 équipements les plus en panne
        if user_only:
            cursor.execute("""
                SELECT mei.designation, COUNT(*) as n
                FROM dr JOIN mei ON dr.id_mei = mei.id
                WHERE dr.annuler = 'non' AND dr.username = %s
                GROUP BY dr.id_mei ORDER BY n DESC LIMIT 5
            """, [session['username']])
        else:
            cursor.execute("""
                SELECT mei.designation, COUNT(*) as n
                FROM dr JOIN mei ON dr.id_mei = mei.id
                WHERE dr.annuler = 'non'
                GROUP BY dr.id_mei ORDER BY n DESC LIMIT 5
            """)
        top_equipements = cursor.fetchall()

    # ── KPIs pièces & stock (only if role has pieces access) ──
    pieces_alerte = 0
    total_pieces = 0
    pieces_alerte_liste = []

    if perms.get('pieces'):
        cursor.execute("SELECT COUNT(*) as n FROM pr WHERE stock <= stock_alerte AND stock_alerte > 0")
        pieces_alerte = cursor.fetchone()['n']

        cursor.execute("SELECT COUNT(*) as n FROM pr")
        total_pieces = cursor.fetchone()['n']

        # Pièces en alerte stock
        cursor.execute("""
            SELECT designation, ref, stock, stock_alerte
            FROM pr WHERE stock <= stock_alerte AND stock_alerte > 0
            ORDER BY stock ASC LIMIT 5
        """)
        pieces_alerte_liste = cursor.fetchall()

    # ── Préventifs (only if role has preventifs access) ──
    preventifs_en_attente = 0
    preventifs_termines = 0

    if perms.get('preventifs'):
        try:
            cursor.execute("SELECT COUNT(*) as n FROM preventif WHERE est_traitee = 'non'")
            preventifs_en_attente = cursor.fetchone()['n']
            cursor.execute("SELECT COUNT(*) as n FROM preventif WHERE est_traitee = 'oui'")
            preventifs_termines = cursor.fetchone()['n']
        except Exception:
            preventifs_en_attente = 0
            preventifs_termines = 0

    # ── Ordres de travail (only if role has ordres access) ──
    total_ordres = 0
    ordres_signes = 0

    if perms.get('ordres'):
        try:
            cursor.execute("SELECT COUNT(*) as n FROM ord")
            total_ordres = cursor.fetchone()['n']
            cursor.execute("SELECT COUNT(*) as n FROM ord WHERE signature = 'oui'")
            ordres_signes = cursor.fetchone()['n']
        except Exception:
            total_ordres = 0
            ordres_signes = 0

    cursor.close()

    return render_template('dashboard.html',
        total_interventions=total_interventions,
        interventions_en_cours=interventions_en_cours,
        interventions_urgentes=interventions_urgentes,
        interventions_terminees=interventions_terminees,
        interventions_annulees=interventions_annulees,
        total_equipements=total_equipements,
        pieces_alerte=pieces_alerte,
        total_pieces=total_pieces,
        preventifs_en_attente=preventifs_en_attente,
        preventifs_termines=preventifs_termines,
        total_ordres=total_ordres,
        ordres_signes=ordres_signes,
        dernieres_interventions=dernieres_interventions,
        par_degre=par_degre,
        par_mois=par_mois,
        top_equipements=top_equipements,
        urgentes_liste=urgentes_liste,
        pieces_alerte_liste=pieces_alerte_liste,
    )

@app.route('/interventions')
@login_required
@perm_required('interventions')
def liste_interventions():
    status = request.args.get('status', '')
    urgence = request.args.get('urgence', '')
    date_debut = request.args.get('date_debut', '')
    date_fin = request.args.get('date_fin', '')
    id_mei = request.args.get('id_mei', '')
    periode = request.args.get('periode', '')

    # À la première visite sans filtres spécifiques, charger par défaut les 7 derniers jours (Dernière semaine)
    is_first_load = not any([status, urgence, date_debut, date_fin, id_mei, 'periode' in request.args])
    if is_first_load:
        periode = '7jours'

    effective_date_debut = date_debut
    effective_date_fin = date_fin

    now = datetime.now()
    if periode == '7jours' and not date_debut:
        effective_date_debut = (now - timedelta(days=7)).strftime('%Y-%m-%d')
    elif periode == '30jours' and not date_debut:
        effective_date_debut = (now - timedelta(days=30)).strftime('%Y-%m-%d')
    elif periode == 'mois' and not date_debut:
        effective_date_debut = now.strftime('%Y-%m-01')

    voir_tout = session.get('user_role') in ('SUPER ADMIN', 'DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
    
    # Quand l'admin/maintenance visite la liste première fois sans filtre spécial
    if voir_tout and is_first_load:
        try:
            cursor_upd = mysql.connection.cursor()
            cursor_upd.execute("UPDATE dr SET est_consulter = 'oui' WHERE est_consulter = 'non' AND annuler = 'non'")
            mysql.connection.commit()
            cursor_upd.close()
        except Exception:
            pass
    
    sql_query = """
        SELECT dr.*, mei.designation 
        FROM dr 
        JOIN mei ON dr.id_mei = mei.id 
        WHERE 1=1
    """
    params = []
    
    if not voir_tout:
        sql_query += " AND dr.username = %s"
        params.append(session['username'])
    
    if status:
        if status == 'en_cours':
            sql_query += " AND dr.est_traiter = 'non' AND dr.annuler = 'non'"
        elif status == 'traite':
            sql_query += " AND dr.est_traiter = 'oui'"
        elif status == 'annule':
            sql_query += " AND dr.annuler = 'oui'"
    if urgence:
        sql_query += " AND dr.degre = %s"
        params.append(urgence)
    if effective_date_debut:
        sql_query += " AND dr.date >= %s"
        params.append(effective_date_debut)
    if effective_date_fin:
        sql_query += " AND dr.date <= %s"
        params.append(effective_date_fin)
    if id_mei:
        sql_query += " AND dr.id_mei = %s"
        params.append(id_mei)
    
    sql_query += " ORDER BY dr.date DESC"
    
    cursor = mysql.connection.cursor()
    try:
        cursor.execute(sql_query, params)
        interventions = cursor.fetchall()
    except Exception as e:
        interventions = []
        flash('Erreur lors du chargement des interventions.', 'danger')
    finally:
        cursor.close()
    
    return render_template('interventions/liste.html', 
                           interventions=interventions, 
                           filtres={
                               'status': status,
                               'urgence': urgence,
                               'date_debut': date_debut,
                               'date_fin': date_fin,
                               'periode': periode,
                               'effective_date_debut': effective_date_debut
                           })


@app.route('/interventions/ajouter', methods=['GET', 'POST'])
@login_required
def ajouter_intervention():
    if request.method == 'POST':
        numero = request.form['numero']
        id_mei = request.form['id_mei']
        description = request.form['description']
        degre = request.form['degre']
        panne = request.form['panne']
        
        cursor = mysql.connection.cursor()
        
        # Générer la date et l'heure actuelles
        date_now = datetime.now().strftime('%Y-%m-%d')
        heure_now = datetime.now().strftime('%H:%M')
        
        # Insérer la nouvelle intervention
        cursor.execute("""
            INSERT INTO dr (numero, username, date, id_mei, date_arret, heure, panne, description, 
                           degre, user_mei, resp_user, est_consulter, est_traiter, annuler)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """, (
            numero, session['username'], date_now, id_mei, date_now, heure_now, panne, 
            description, degre, session['username'], '', 'non', 'non', 'non'
        ))
        
        mysql.connection.commit()
        cursor.close()
        
        # Récupérer l'ID de l'intervention nouvellement créée
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT id FROM dr WHERE numero = %s ORDER BY id DESC LIMIT 1", [numero])
        new_intervention = cursor.fetchone()
        cursor.close()
        
        if new_intervention:
            # Message spécial pour déclencher la notification sonore avec lien vers l'intervention
            intervention_id = new_intervention['id']
            intervention_url = url_for('voir_intervention', id=intervention_id)
            
            # Récupérer les détails de l'équipement concerné
            cursor = mysql.connection.cursor()
            cursor.execute("SELECT designation FROM mei WHERE id = %s", [id_mei])
            equipement_info = cursor.fetchone()
            cursor.close()
            
            equipement_nom = equipement_info['designation'] if equipement_info else 'Équipement inconnu'
            
            # Créer un résumé de l'intervention
            resume = {
                'equipement': equipement_nom,
                'description': description[:50] + '...' if len(description) > 50 else description,
                'priorite': degre,
                'date': date_now,
                'numero': numero
            }
            
            # Stocker l'URL et le résumé dans la session pour que le JavaScript puisse y accéder
            session['notification_link'] = intervention_url
            session['notification_type'] = 'intervention'
            session['notification_id'] = intervention_id
            session['notification_resume'] = resume
            notif_key = 'intervention_urgente' if degre == 'Trés urgent' else 'nouvelle_intervention'
            session['notif_key'] = notif_key
            
            # Ajouter à la base de données
            notif_type = 'danger' if degre == 'Trés urgent' else 'info'
            notif_title = "Intervention URGENTE" if degre == 'Trés urgent' else "Nouvelle intervention"
            notif_msg = f"N° {numero} | Équipement: {equipement_nom} | Par: {session['username']} | Priorité: {degre}"
            add_db_notification(
                notif_key=notif_key,
                title=notif_title,
                message=notif_msg,
                type=notif_type,
                link=intervention_url,
                permission_required='interventions'
            )
            
            flash('Nouvelle intervention ajoutée avec succès', 'success')
        else:
            flash('Nouvelle intervention ajoutée avec succès', 'success')
        
        return redirect(url_for('liste_interventions'))
    
    # Récupérer la liste des équipements pour le formulaire
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    cursor.close()
    
    return render_template('interventions/ajouter.html', equipements=equipements)

@app.route('/interventions/voir/<int:id>')
@login_required
def voir_intervention(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de l'intervention
    cursor.execute("""
        SELECT dr.*, mei.designation, mei.type as modele, mei.marque, mei.serie as n_serie
        FROM dr 
        JOIN mei ON dr.id_mei = mei.id 
        WHERE dr.id = %s
    """, [id])
    intervention = cursor.fetchone()
    
    # Récupérer les pièces de rechange utilisées pour cette intervention
    cursor.execute("""
        SELECT av_prs.*, pr.ref as reference, pr.designation
        FROM av_prs 
        JOIN pr ON av_prs.id_prs = pr.id 
        WHERE av_prs.id_constat = %s
    """, [id])
    pieces = cursor.fetchall()
    
    cursor.close()
    
    if not intervention:
        flash('Intervention non trouvée', 'danger')
        return redirect(url_for('liste_interventions'))
    
    is_admin = session.get('user_role') in ('SUPER ADMIN', 'DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
    if not is_admin and intervention['username'] != session['username']:
        flash("Vous n'avez pas l'autorisation de voir cette intervention.", 'danger')
        return redirect(url_for('liste_interventions'))
    
    # Marquer comme consultée si l'équipe admin/maintenance la voit pour la première fois
    if is_admin and intervention.get('est_consulter') == 'non':
        cursor2 = mysql.connection.cursor()
        cursor2.execute("UPDATE dr SET est_consulter = 'oui' WHERE id = %s", [id])
        mysql.connection.commit()
        cursor2.close()
    
    return render_template('interventions/voir.html', intervention=intervention, pieces=pieces)

@app.route('/interventions/traiter/<int:id>')
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def traiter_intervention(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails avant mise à jour pour la notif
    cursor.execute("SELECT username, numero FROM dr WHERE id = %s", [id])
    interv = cursor.fetchone()
    
    # Marquer l'intervention comme traitée
    cursor.execute("UPDATE dr SET est_traiter = 'oui' WHERE id = %s", [id])
    mysql.connection.commit()
    
    if interv:
        creator_username = interv['username']
        numero = interv['numero']
        cursor.execute("SELECT id FROM user WHERE username = %s", [creator_username])
        creator_user = cursor.fetchone()
        if creator_user:
            add_db_notification(
                notif_key='intervention_traitee',
                title="Intervention traitée",
                message=f"Votre demande d'intervention N° {numero} a été marquée comme traitée.",
                type='success',
                link=url_for('voir_intervention', id=id),
                user_id=creator_user['id']
            )
            
    cursor.close()
    session['notif_key'] = 'intervention_traitee'
    session['notification_link'] = url_for('voir_intervention', id=id)
    flash('Intervention marquée comme traitée avec succès', 'success')
    return redirect(url_for('voir_intervention', id=id))

@app.route('/interventions/annuler/<int:id>')
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def annuler_intervention(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails avant mise à jour pour la notif
    cursor.execute("SELECT username, numero FROM dr WHERE id = %s", [id])
    interv = cursor.fetchone()
    
    # Annuler l'intervention
    cursor.execute("UPDATE dr SET annuler = 'oui' WHERE id = %s", [id])
    mysql.connection.commit()
    
    if interv:
        creator_username = interv['username']
        numero = interv['numero']
        cursor.execute("SELECT id FROM user WHERE username = %s", [creator_username])
        creator_user = cursor.fetchone()
        if creator_user:
            add_db_notification(
                notif_key='intervention_annulee',
                title="Intervention annulée",
                message=f"Votre demande d'intervention N° {numero} a été annulée.",
                type='warning',
                link=url_for('voir_intervention', id=id),
                user_id=creator_user['id']
            )
            
    cursor.close()
    session['notif_key'] = 'intervention_annulee'
    session['notification_link'] = url_for('voir_intervention', id=id)
    flash('Intervention annulée avec succès', 'success')
    return redirect(url_for('voir_intervention', id=id))

@app.route('/equipements')
@login_required
@perm_required('equipements')
def liste_equipements():
    # Récupérer les filtres de la requête GET
    designation = request.args.get('designation', '')
    marque = request.args.get('marque', '')
    serie = request.args.get('serie', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM mei WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND designation LIKE %s"
        params.append(f'%{designation}%')
    
    if marque:
        sql_query += " AND marque LIKE %s"
        params.append(f'%{marque}%')
    
    if serie:
        sql_query += " AND serie LIKE %s"
        params.append(f'%{serie}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY designation"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    equipements = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('equipements/liste.html', 
                           equipements=equipements, 
                           filtres={
                               'designation': designation,
                               'marque': marque,
                               'serie': serie
                           })

@app.route('/pieces')
@login_required
@perm_required('pieces')
def liste_pieces():
    # Récupérer les filtres de la requête GET
    designation = request.args.get('designation', '')
    reference = request.args.get('reference', '')
    localisation = request.args.get('localisation', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM pr WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND designation LIKE %s"
        params.append(f'%{designation}%')
    
    if reference:
        sql_query += " AND ref LIKE %s"
        params.append(f'%{reference}%')
    
    if localisation:
        sql_query += " AND localisation LIKE %s"
        params.append(f'%{localisation}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY designation"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    pieces = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('pieces/liste.html', 
                           pieces=pieces, 
                           filtres={
                               'designation': designation,
                               'reference': reference,
                               'localisation': localisation
                           })

@app.route('/fournisseurs')
@login_required
@perm_required('fournisseurs')
def liste_fournisseurs():
    # Récupérer les filtres de la requête GET
    designation = request.args.get('designation', '')
    adresse = request.args.get('adresse', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT id, nom as designation, address as adresse, mobile as tel, email FROM fournisseur WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND nom LIKE %s"
        params.append(f'%{designation}%')
    
    if adresse:
        sql_query += " AND address LIKE %s"
        params.append(f'%{adresse}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY nom"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    fournisseurs = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('fournisseurs/liste.html', 
                           fournisseurs=fournisseurs, 
                           filtres={
                               'designation': designation,
                               'adresse': adresse
                           })

# Routes pour les équipements
@app.route('/equipements/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_equipement():
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        code_identification = request.form['code_identification']
        marque = request.form['marque']
        type_equipement = request.form['type']
        serie = request.form['serie']
        date_marche = request.form['date_marche']
        sensibilite = request.form['sensibilite']
        position = request.form['position']
        charge = request.form['charge']
        temps_moyen = request.form['temps_moyen']
        
        # Connexion à la base de données
        cursor = mysql.connection.cursor()
        
        # Insertion des données dans la table mei
        cursor.execute("""
            INSERT INTO mei 
            (designation, code_identification, marque, type, serie, date_marche, sensibilite, position, charge, temps_moyen, activee) 
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, '1')
        """, (designation, code_identification, marque, type_equipement, serie, date_marche, sensibilite, position, charge, temps_moyen))
        
        # Validation des modifications
        mysql.connection.commit()
        
        # Fermeture du curseur
        cursor.close()
        
        # Message de succès
        flash('Équipement ajouté avec succès', 'success')
        
        # Redirection vers la liste des équipements
        return redirect(url_for('liste_equipements'))
    
    # Affichage du formulaire d'ajout
    return render_template('equipements/ajouter.html')

@app.route('/equipements/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_equipement(id):
    # Récupérer les informations de l'équipement
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM mei WHERE id = %s", [id])
    equipement = cursor.fetchone()
    
    if not equipement:
        cursor.close()
        flash('Équipement non trouvé', 'danger')
        return redirect(url_for('liste_equipements'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        code_identification = request.form['code_identification']
        marque = request.form['marque']
        type_equipement = request.form['type']
        serie = request.form['serie']
        date_marche = request.form['date_marche']
        sensibilite = request.form['sensibilite']
        position = request.form['position']
        charge = request.form['charge']
        temps_moyen = request.form['temps_moyen']
        
        # Mise à jour des données dans la table mei
        cursor.execute("""
            UPDATE mei 
            SET designation = %s, code_identification = %s, marque = %s, 
                type = %s, serie = %s, date_marche = %s, sensibilite = %s, 
                position = %s, charge = %s, temps_moyen = %s 
            WHERE id = %s
        """, (designation, code_identification, marque, type_equipement, 
               serie, date_marche, sensibilite, position, charge, temps_moyen, id))
        
        mysql.connection.commit()
        cursor.close()
        session['notif_key'] = 'equipement_modifie'
        session['notification_link'] = url_for('voir_equipement', id=id)
        flash('Équipement modifié avec succès', 'success')
        return redirect(url_for('voir_equipement', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de modification
    return render_template('equipements/modifier.html', equipement=equipement)

@app.route('/equipements/voir/<int:id>')
@login_required
def voir_equipement(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM mei WHERE id = %s", [id])
    equipement = cursor.fetchone()
    cursor.execute("""
        SELECT dr.* FROM dr WHERE id_mei = %s ORDER BY date DESC LIMIT 10
    """, [id])
    interventions = cursor.fetchall()
    cursor.close()
    if not equipement:
        flash('Equipement non trouvé', 'danger')
        return redirect(url_for('liste_equipements'))
    return render_template('equipements/voir.html', equipement=equipement, interventions=interventions)

@app.route('/equipements/toggle-statut/<int:id>')
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def toggle_statut_equipement(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT activee FROM mei WHERE id = %s", [id])
    eq = cursor.fetchone()
    if not eq:
        cursor.close()
        flash('Equipement non trouvé', 'danger')
        return redirect(url_for('liste_equipements'))
    nouveau = '0' if eq['activee'] == '1' else '1'
    cursor.execute("UPDATE mei SET activee = %s WHERE id = %s", [nouveau, id])
    mysql.connection.commit()
    cursor.close()
    msg = 'Equipement activé' if nouveau == '1' else 'Equipement désactivé'
    session['notif_key'] = 'equipement_statut'
    session['notification_link'] = url_for('voir_equipement', id=id)
    flash(msg, 'success')
    return redirect(url_for('voir_equipement', id=id))

# Routes pour les pièces
@app.route('/pieces/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_piece(id):
    # Récupérer les informations de la pièce
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM pr WHERE id = %s", [id])
    piece = cursor.fetchone()
    
    if not piece:
        cursor.close()
        flash('Pièce non trouvée', 'danger')
        return redirect(url_for('liste_pieces'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        ref = request.form['ref']
        code_interne = request.form['code_interne']
        stock = request.form['stock']
        stock_alerte = request.form['stock_alerte']
        uq = request.form['uq']
        localisation = request.form['localisation']
        
        # Mise à jour des données dans la table pr
        cursor.execute("""
            UPDATE pr 
            SET designation = %s, ref = %s, code_interne = %s, 
                stock = %s, stock_alerte = %s, uq = %s, localisation = %s 
            WHERE id = %s
        """, (designation, ref, code_interne, stock, stock_alerte, uq, localisation, id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Pièce modifiée avec succès', 'success')
        
        # Redirection vers la page de détails de la pièce
        return redirect(url_for('voir_piece', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de modification
    return render_template('pieces/modifier.html', piece=piece)

@app.route('/pieces/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_piece():
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        ref = request.form['ref']
        code_interne = request.form['code_interne']
        stock = request.form['stock']
        stock_alerte = request.form['stock_alerte']
        uq = request.form['uq']
        localisation = request.form['localisation']
        
        # Connexion à la base de données
        cursor = mysql.connection.cursor()
        
        # Insertion des données dans la table pr
        cursor.execute("""
            INSERT INTO pr 
            (designation, ref, code_interne, stock, stock_alerte, uq, localisation) 
            VALUES (%s, %s, %s, %s, %s, %s, %s)
        """, (designation, ref, code_interne, stock, stock_alerte, uq, localisation))
        
        # Validation des modifications
        mysql.connection.commit()
        
        # Fermeture du curseur
        cursor.close()
        
        # Message de succès
        flash('Pièce ajoutée avec succès', 'success')
        
        # Redirection vers la liste des pièces
        return redirect(url_for('liste_pieces'))
    
    # Affichage du formulaire d'ajout
    return render_template('pieces/ajouter.html')

@app.route('/pieces/mouvement/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('SUPER ADMIN', 'DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def mouvement_piece(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la pièce
    cursor.execute("SELECT * FROM pr WHERE id = %s", [id])
    piece = cursor.fetchone()
    
    if not piece:
        cursor.close()
        flash('Pièce non trouvée', 'danger')
        return redirect(url_for('liste_pieces'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        quantite = int(request.form['quantite'])
        type_mouvement = request.form['type_mouvement']
        motif = request.form['motif']
        date_mouvement = request.form.get('date_mouvement', datetime.now().strftime('%Y-%m-%d'))
        
        # Calcul du nouveau stock
        nouveau_stock = piece['stock']
        if type_mouvement == 'entree':
            nouveau_stock += quantite
        elif type_mouvement == 'sortie':
            # Vérifier si le stock est suffisant
            if quantite > piece['stock']:
                flash('Stock insuffisant pour cette opération', 'danger')
                cursor.close()
                return render_template('pieces/mouvement.html', piece=piece)
            
            nouveau_stock -= quantite
        
        # Mise à jour du stock dans la table pr
        cursor.execute("""
            UPDATE pr 
            SET stock = %s 
            WHERE id = %s
        """, (nouveau_stock, id))
        
        mysql.connection.commit()
        cursor.close()
        
        is_alerte = nouveau_stock <= piece.get('stock_alerte', 0) and piece.get('stock_alerte', 0) > 0
        if is_alerte:
            add_db_notification(
                notif_key='stock_alerte',
                title="Alerte stock",
                message=f"La pièce {piece['designation']} (Réf: {piece['ref']}) a atteint le seuil d'alerte. Stock actuel: {nouveau_stock}.",
                type='warning',
                link=url_for('voir_piece', id=id),
                permission_required='pieces'
            )
            
        message = 'Entrée de ' if type_mouvement == 'entree' else 'Sortie de '
        flash(message + str(quantite) + ' unité(s) effectuée avec succès', 'success')
        session['notif_key'] = 'stock_alerte' if is_alerte else 'mouvement_stock'
        session['notification_link'] = url_for('voir_piece', id=id)
        return redirect(url_for('voir_piece', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de mouvement
    return render_template('pieces/mouvement.html', piece=piece)

@app.route('/pieces/voir/<int:id>')
@login_required
def voir_piece(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la pièce
    cursor.execute("SELECT * FROM pr WHERE id = %s", [id])
    piece = cursor.fetchone()
    
    # Récupérer les utilisations de cette pièce
    cursor.execute("""
        SELECT av_prs.*, dr.numero, dr.date
        FROM av_prs 
        JOIN dr ON av_prs.id_constat = dr.id 
        WHERE av_prs.id_prs = %s
        ORDER BY dr.date DESC
    """, [id])
    utilisations = cursor.fetchall()
    
    cursor.close()
    
    if not piece:
        flash('Pièce non trouvée', 'danger')
        return redirect(url_for('liste_pieces'))
    
    return render_template('pieces/voir.html', piece=piece, utilisations=utilisations)

# Routes pour les fournisseurs
@app.route('/fournisseurs/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_fournisseur():
    if request.method == 'POST':
        # Récupération des données du formulaire
        nom = request.form['nom']
        adresse = request.form['adresse']
        tel = request.form['tel']
        email = request.form['email']
        
        # Connexion à la base de données
        cursor = mysql.connection.cursor()
        
        # Insertion des données dans la table fournisseur
        cursor.execute("""
            INSERT INTO fournisseur 
            (nom, address, mobile, email) 
            VALUES (%s, %s, %s, %s)
        """, (nom, adresse, tel, email))
        
        # Validation des modifications
        mysql.connection.commit()
        
        # Fermeture du curseur
        cursor.close()
        
        # Message de succès
        flash('Fournisseur ajouté avec succès', 'success')
        
        # Redirection vers la liste des fournisseurs
        return redirect(url_for('liste_fournisseurs'))
    
    # Affichage du formulaire d'ajout
    return render_template('fournisseurs/ajouter.html')

@app.route('/fournisseurs/voir/<int:id>')
@login_required
def voir_fournisseur(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails du fournisseur
    cursor.execute("""
        SELECT id, nom as designation, address as adresse, mobile as tel, email 
        FROM fournisseur 
        WHERE id = %s
    """, [id])
    fournisseur = cursor.fetchone()
    
    # Récupérer les bons de livraison associés à ce fournisseur
    cursor.execute("""
        SELECT bl.* FROM bl WHERE id_fournisseur = %s ORDER BY date DESC LIMIT 10
    """, [id])
    bons_livraison = cursor.fetchall()
    
    cursor.close()
    
    if not fournisseur:
        flash('Fournisseur non trouvé', 'danger')
        return redirect(url_for('liste_fournisseurs'))
    
    return render_template('fournisseurs/voir.html', fournisseur=fournisseur, bons_livraison=bons_livraison)

# Routes pour les familles
@app.route('/familles')
@login_required
@perm_required('familles')
def liste_familles():
    # Récupérer les filtres de la requête GET
    designation = request.args.get('designation', '')
    code = request.args.get('code', '')
    secteur = request.args.get('secteur', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM famille WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND designation LIKE %s"
        params.append(f'%{designation}%')
    
    if code:
        sql_query += " AND code LIKE %s"
        params.append(f'%{code}%')
    
    if secteur:
        sql_query += " AND secteur = %s"
        params.append(secteur)
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY designation"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    familles = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('familles/liste.html', 
                           familles=familles, 
                           filtres={
                               'designation': designation,
                               'code': code,
                               'secteur': secteur
                           })

@app.route('/familles/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_famille():
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        code = request.form['code']
        secteur = request.form['secteur']
        
        # Connexion à la base de données
        cursor = mysql.connection.cursor()
        
        # Insertion des données dans la table famille
        cursor.execute("""
            INSERT INTO famille 
            (designation, code, secteur) 
            VALUES (%s, %s, %s)
        """, (designation, code, secteur))
        
        # Validation des modifications
        mysql.connection.commit()
        
        # Fermeture du curseur
        cursor.close()
        
        # Message de succès
        flash('Famille ajoutée avec succès', 'success')
        
        # Redirection vers la liste des familles
        return redirect(url_for('liste_familles'))
    
    # Affichage du formulaire d'ajout
    return render_template('familles/ajouter.html')

@app.route('/familles/voir/<int:id>')
@login_required
def voir_famille(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la famille
    cursor.execute("SELECT * FROM famille WHERE id = %s", [id])
    famille = cursor.fetchone()
    
    # Récupérer les équipements liés à cette famille
    cursor.execute("""
        SELECT * FROM mei WHERE famille = %s ORDER BY designation LIMIT 10
    """, [id])
    equipements = cursor.fetchall()
    
    cursor.close()
    
    if not famille:
        flash('Famille non trouvée', 'danger')
        return redirect(url_for('liste_familles'))
    
    return render_template('familles/voir.html', famille=famille, equipements=equipements)

@app.route('/familles/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_famille(id):
    # Récupérer les informations de la famille
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM famille WHERE id = %s", [id])
    famille = cursor.fetchone()
    
    if not famille:
        cursor.close()
        flash('Famille non trouvée', 'danger')
        return redirect(url_for('liste_familles'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        code = request.form['code']
        secteur = request.form['secteur']
        
        # Mise à jour des données dans la table famille
        cursor.execute("""
            UPDATE famille 
            SET designation = %s, code = %s, secteur = %s 
            WHERE id = %s
        """, (designation, code, secteur, id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Famille modifiée avec succès', 'success')
        
        # Redirection vers la page de détails de la famille
        return redirect(url_for('voir_famille', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de modification
    return render_template('familles/modifier.html', famille=famille)

# Routes de suppression
@app.route('/equipements/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_equipement(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'équipement existe
    cursor.execute("SELECT * FROM mei WHERE id = %s", [id])
    equipement = cursor.fetchone()
    
    if not equipement:
        cursor.close()
        flash('Équipement non trouvé', 'danger')
        return redirect(url_for('liste_equipements'))
    
    # Vérifier s'il y a des interventions liées à cet équipement
    cursor.execute("SELECT COUNT(*) as count FROM dr WHERE id_mei = %s", [id])
    result = cursor.fetchone()
    
    if result['count'] > 0:
        cursor.close()
        flash('Impossible de supprimer cet équipement car il est lié à des interventions', 'danger')
        return redirect(url_for('voir_equipement', id=id))
    
    # Supprimer l'équipement
    cursor.execute("DELETE FROM mei WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Équipement supprimé avec succès', 'success')
    return redirect(url_for('liste_equipements'))

@app.route('/pieces/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_piece(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la pièce existe
    cursor.execute("SELECT * FROM pr WHERE id = %s", [id])
    piece = cursor.fetchone()
    
    if not piece:
        cursor.close()
        flash('Pièce non trouvée', 'danger')
        return redirect(url_for('liste_pieces'))
    
    # Vérifier s'il y a des utilisations liées à cette pièce
    cursor.execute("SELECT COUNT(*) as count FROM av_prs WHERE id_prs = %s", [id])
    result = cursor.fetchone()
    
    if result['count'] > 0:
        cursor.close()
        flash('Impossible de supprimer cette pièce car elle est liée à des interventions', 'danger')
        return redirect(url_for('voir_piece', id=id))
    
    # Supprimer la pièce
    cursor.execute("DELETE FROM pr WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Pièce supprimée avec succès', 'success')
    return redirect(url_for('liste_pieces'))

@app.route('/familles/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_famille(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la famille existe
    cursor.execute("SELECT * FROM famille WHERE id = %s", [id])
    famille = cursor.fetchone()
    
    if not famille:
        cursor.close()
        flash('Famille non trouvée', 'danger')
        return redirect(url_for('liste_familles'))
    
    # Vérifier s'il y a des équipements liés à cette famille
    cursor.execute("SELECT COUNT(*) as count FROM mei WHERE famille = %s", [id])
    result = cursor.fetchone()
    
    if result['count'] > 0:
        cursor.close()
        flash('Impossible de supprimer cette famille car elle est liée à des équipements', 'danger')
        return redirect(url_for('voir_famille', id=id))
    
    # Supprimer la famille
    cursor.execute("DELETE FROM famille WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Famille supprimée avec succès', 'success')
    return redirect(url_for('liste_familles'))

@app.route('/fournisseurs/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_fournisseur(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si le fournisseur existe
    cursor.execute("SELECT * FROM fournisseur WHERE id = %s", [id])
    fournisseur = cursor.fetchone()
    
    if not fournisseur:
        cursor.close()
        flash('Fournisseur non trouvé', 'danger')
        return redirect(url_for('liste_fournisseurs'))
    
    # Vérifier s'il y a des bons de livraison liés à ce fournisseur
    cursor.execute("SELECT COUNT(*) as count FROM bl WHERE id_fournisseur = %s", [id])
    result = cursor.fetchone()
    
    if result['count'] > 0:
        cursor.close()
        flash('Impossible de supprimer ce fournisseur car il est lié à des bons de livraison', 'danger')
        return redirect(url_for('voir_fournisseur', id=id))
    
    # Supprimer le fournisseur
    cursor.execute("DELETE FROM fournisseur WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Fournisseur supprimé avec succès', 'success')
    return redirect(url_for('liste_fournisseurs'))

@app.route('/interventions/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_intervention(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'intervention existe
    cursor.execute("SELECT * FROM dr WHERE id = %s", [id])
    intervention = cursor.fetchone()
    
    if not intervention:
        cursor.close()
        flash('Intervention non trouvée', 'danger')
        return redirect(url_for('liste_interventions'))
    
    # Supprimer les pièces utilisées pour cette intervention
    cursor.execute("DELETE FROM av_prs WHERE id_constat = %s", [id])
    
    # Supprimer l'intervention
    cursor.execute("DELETE FROM dr WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Intervention supprimée avec succès', 'success')
    return redirect(url_for('liste_interventions'))

# Routes pour la maintenance préventive
@app.route('/preventifs')
@login_required
@perm_required('preventifs')
def liste_preventifs():
    # Récupérer les filtres de la requête GET
    numero = request.args.get('numero', '')
    mei_inv = request.args.get('mei_inv', '')
    statut = request.args.get('statut', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT p.*, m.designation as equipement FROM preventif p JOIN mei m ON p.mei_inv = m.id WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if numero:
        sql_query += " AND p.numero LIKE %s"
        params.append(f'%{numero}%')
    
    if mei_inv:
        sql_query += " AND p.mei_inv = %s"
        params.append(mei_inv)
    
    if statut:
        sql_query += " AND p.est_traitee = %s"
        params.append(statut)
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY p.date_prevu DESC"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    preventifs = cursor.fetchall()
    
    # Récupérer la liste des équipements pour le filtre
    cursor.execute("SELECT id, designation FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('preventifs/liste.html', 
                           preventifs=preventifs, 
                           equipements=equipements,
                           filtres={
                               'numero': numero,
                               'mei_inv': mei_inv,
                               'statut': statut
                           })

@app.route('/preventifs/ajouter', methods=['GET', 'POST'])
@login_required
def ajouter_preventif():
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id, designation FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    cursor.execute("SELECT id, designation FROM operation ORDER BY designation")
    operations = cursor.fetchall()
    cursor.close()

    if request.method == 'POST':
        numero = request.form['numero']
        mei_inv = request.form['mei_inv']
        date_prevu = request.form['date_prevu']

        cursor = mysql.connection.cursor()
        try:
            cursor.execute("""
                INSERT INTO preventif (numero, mei_inv, date_prevu, est_traitee)
                VALUES (%s, %s, %s, 'non')
            """, (numero, mei_inv, date_prevu))
            preventif_id = cursor.lastrowid
            for op_id in request.form.getlist('operations'):
                cursor.execute("""
                    INSERT INTO preventif_op (id_preventif, id_op) VALUES (%s, %s)
                """, (preventif_id, op_id))
            
            add_db_notification(
                notif_key='maintenance_preventive',
                title="Nouvelle maintenance préventive",
                message=f"La tâche de maintenance préventive N° {numero} a été planifiée pour le {date_prevu}.",
                type='info',
                link=url_for('voir_preventif', id=preventif_id),
                permission_required='preventifs'
            )
            
            mysql.connection.commit()
            flash('Maintenance préventive ajoutée avec succès', 'success')
            session['notif_key'] = 'maintenance_preventive'
        except Exception as e:
            mysql.connection.rollback()
            flash('Erreur lors de l\'ajout: ' + str(e), 'danger')
        finally:
            cursor.close()
        return redirect(url_for('liste_preventifs'))

    return render_template('preventifs/ajouter.html', equipements=equipements, operations=operations)

@app.route('/preventifs/voir/<int:id>')
@login_required
def voir_preventif(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la maintenance préventive
    cursor.execute("""
        SELECT p.*, m.designation as equipement, m.code_identification, m.marque, m.type, m.serie
        FROM preventif p 
        JOIN mei m ON p.mei_inv = m.id 
        WHERE p.id = %s
    """, [id])
    preventif = cursor.fetchone()
    
    if not preventif:
        cursor.close()
        flash('Maintenance préventive non trouvée', 'danger')
        return redirect(url_for('liste_preventifs'))
    
    # Récupérer les opérations associées
    cursor.execute("""
        SELECT o.* 
        FROM operation o 
        JOIN preventif_op po ON o.id = po.id_op 
        WHERE po.id_preventif = %s
    """, [id])
    operations = cursor.fetchall()
    
    cursor.close()
    
    return render_template('preventifs/voir.html', preventif=preventif, operations=operations)

@app.route('/preventifs/traiter/<int:id>', methods=['GET', 'POST'])
@login_required
def traiter_preventif(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la maintenance préventive
    cursor.execute("SELECT * FROM preventif WHERE id = %s", [id])
    preventif = cursor.fetchone()
    
    if not preventif:
        cursor.close()
        flash('Maintenance préventive non trouvée', 'danger')
        return redirect(url_for('liste_preventifs'))
    
    if preventif['est_traitee'] == 'oui':
        cursor.close()
        flash('Cette maintenance préventive a déjà été traitée', 'warning')
        return redirect(url_for('voir_preventif', id=id))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        date_debut = request.form['date_debut']
        heure_debut = request.form['heure_debut']
        date_fin = request.form['date_fin']
        heure_fin = request.form['heure_fin']
        
        # Mise à jour du statut de la maintenance préventive
        cursor.execute("""
            UPDATE preventif 
            SET est_traitee = 'oui', date_debut = %s, heure_debut = %s, date_fin = %s, heure_fin = %s 
            WHERE id = %s
        """, (date_debut, heure_debut, date_fin, heure_fin, id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        flash('Maintenance préventive marquée comme traitée avec succès', 'success')
        session['notif_key'] = 'preventif_traite'
        session['notification_link'] = url_for('voir_preventif', id=id)
        return redirect(url_for('voir_preventif', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de traitement
    return render_template('preventifs/traiter.html', preventif=preventif)

@app.route('/preventifs/reporter/<int:id>', methods=['GET', 'POST'])
@login_required
def reporter_preventif(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la maintenance préventive
    cursor.execute("SELECT * FROM preventif WHERE id = %s", [id])
    preventif = cursor.fetchone()
    
    if not preventif:
        cursor.close()
        flash('Maintenance préventive non trouvée', 'danger')
        return redirect(url_for('liste_preventifs'))
    
    if preventif['est_traitee'] == 'oui':
        cursor.close()
        flash('Cette maintenance préventive a déjà été traitée et ne peut pas être reportée', 'warning')
        return redirect(url_for('voir_preventif', id=id))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        date_reportee = request.form['date_reportee']
        
        # Mise à jour de la date reportée
        cursor.execute("""
            UPDATE preventif 
            SET date_reportee = %s 
            WHERE id = %s
        """, (date_reportee, id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Maintenance préventive reportée avec succès', 'success')
        
        # Redirection vers la page de détails
        return redirect(url_for('voir_preventif', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de report
    return render_template('preventifs/reporter.html', preventif=preventif)

@app.route('/preventifs/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_preventif(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la maintenance préventive existe
    cursor.execute("SELECT * FROM preventif WHERE id = %s", [id])
    preventif = cursor.fetchone()
    
    if not preventif:
        cursor.close()
        flash('Maintenance préventive non trouvée', 'danger')
        return redirect(url_for('liste_preventifs'))
    
    # Supprimer les opérations associées
    cursor.execute("DELETE FROM preventif_op WHERE id_preventif = %s", [id])
    
    # Supprimer la maintenance préventive
    cursor.execute("DELETE FROM preventif WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Maintenance préventive supprimée avec succès', 'success')
    return redirect(url_for('liste_preventifs'))

# Routes pour les opérations de maintenance
@app.route('/operations')
@login_required
@perm_required('operations')
def liste_operations():
    # Récupérer le filtre de la requête GET
    designation = request.args.get('designation', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM operation WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND designation LIKE %s"
        params.append(f'%{designation}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY designation"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    operations = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('operations/liste.html', 
                           operations=operations, 
                           filtres={
                               'designation': designation
                           })

@app.route('/operations/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_operation():
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        
        # Vérifier si une opération avec cette désignation existe déjà
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT * FROM operation WHERE designation = %s", [designation])
        existing_operation = cursor.fetchone()
        
        if existing_operation:
            cursor.close()
            flash('Une opération avec cette désignation existe déjà', 'danger')
            return render_template('operations/ajouter.html')
        
        # Insertion des données dans la table operation
        cursor.execute("""
            INSERT INTO operation 
            (designation) 
            VALUES (%s)
        """, [designation])
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès avec notification spéciale
        flash('Nouvelle intervention ajoutée avec succès', 'success')
        
        # Redirection vers la liste des opérations
        return redirect(url_for('liste_operations'))
    
    # Affichage du formulaire d'ajout
    return render_template('operations/ajouter.html')

@app.route('/operations/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_operation(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'opération existe
    cursor.execute("SELECT * FROM operation WHERE id = %s", [id])
    operation = cursor.fetchone()
    
    if not operation:
        cursor.close()
        flash('Opération non trouvée', 'danger')
        return redirect(url_for('liste_operations'))
    
    # Vérifier si l'opération est utilisée dans des gammes ou des maintenances préventives
    cursor.execute("SELECT COUNT(*) as count FROM preventif_op WHERE id_op = %s", [id])
    preventif_count = cursor.fetchone()['count']
    
    cursor.execute("SELECT COUNT(*) as count FROM gamme WHERE id_operation = %s", [id])
    gamme_count = cursor.fetchone()['count']
    
    if preventif_count > 0 or gamme_count > 0:
        cursor.close()
        flash('Impossible de supprimer cette opération car elle est utilisée dans des maintenances préventives ou des gammes', 'danger')
        return redirect(url_for('liste_operations'))
    
    # Supprimer l'opération
    cursor.execute("DELETE FROM operation WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Opération supprimée avec succès', 'success')
    return redirect(url_for('liste_operations'))

# Routes pour les opérateurs
@app.route('/operateurs')
@login_required
@perm_required('operateurs')
def liste_operateurs():
    # Récupérer les filtres de la requête GET
    nom = request.args.get('nom', '')
    fonction = request.args.get('fonction', '')
    specialite = request.args.get('specialite', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM operateur WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if nom:
        sql_query += " AND (nom LIKE %s OR prenom LIKE %s)"
        params.append(f'%{nom}%')
        params.append(f'%{nom}%')
    
    if fonction:
        sql_query += " AND fonction LIKE %s"
        params.append(f'%{fonction}%')
    
    if specialite:
        sql_query += " AND specialite LIKE %s"
        params.append(f'%{specialite}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY nom, prenom"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    operateurs = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('operateurs/liste.html', 
                           operateurs=operateurs, 
                           filtres={
                               'nom': nom,
                               'fonction': fonction,
                               'specialite': specialite
                           })

@app.route('/operateurs/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_operateur():
    if request.method == 'POST':
        # Récupération des données du formulaire
        nom = request.form['nom']
        prenom = request.form['prenom']
        code = request.form['code']
        diplome = request.form['diplome']
        specialite = request.form['specialite']
        fonction = request.form['fonction']
        
        # Insertion des données dans la table operateur
        cursor = mysql.connection.cursor()
        cursor.execute("""
            INSERT INTO operateur 
            (nom, prenom, code, diplome, specialite, fonction, occupe) 
            VALUES (%s, %s, %s, %s, %s, %s, 'non')
        """, (nom, prenom, code, diplome, specialite, fonction))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Stocker les informations de notification dans la session
        session['notification_link'] = url_for('voir_operateur', id=cursor.lastrowid)
        session['notification_type'] = 'operateur'
        session['notification_id'] = cursor.lastrowid
        
        # Message de succès
        flash('Opérateur ajouté avec succès', 'success')
        
        # Redirection vers la liste des opérateurs
        return redirect(url_for('liste_operateurs'))
    
    # Affichage du formulaire d'ajout
    return render_template('operateurs/ajouter.html')
@app.route('/operateurs/voir/<int:id>')
@login_required
def voir_operateur(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de l'opérateur
    cursor.execute("SELECT * FROM operateur WHERE id = %s", [id])
    operateur = cursor.fetchone()
    
    if not operateur:
        cursor.close()
        flash('Opérateur non trouvé', 'danger')
        return redirect(url_for('liste_operateurs'))
    
    # Récupérer les interventions associées à cet opérateur
    # Utiliser le username comme identifiant de l'opérateur dans la table dr
    cursor.execute("""
        SELECT dr.*, mei.designation as equipement 
        FROM dr 
        JOIN mei ON dr.id_mei = mei.id 
        WHERE dr.username = %s OR dr.resp_user = %s
        ORDER BY dr.date DESC
    """, [operateur['code'], operateur['code']])
    interventions = cursor.fetchall()
    
    cursor.close()
    
    return render_template('operateurs/voir.html', operateur=operateur, interventions=interventions)

@app.route('/operateurs/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_operateur(id):
    # Récupérer les informations de l'opérateur
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM operateur WHERE id = %s", [id])
    operateur = cursor.fetchone()
    
    if not operateur:
        cursor.close()
        flash('Opérateur non trouvé', 'danger')
        return redirect(url_for('liste_operateurs'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        nom = request.form['nom']
        prenom = request.form['prenom']
        code = request.form['code']
        diplome = request.form['diplome']
        specialite = request.form['specialite']
        fonction = request.form['fonction']
        
        # Mise à jour des données dans la table operateur
        cursor.execute("""
            UPDATE operateur 
            SET nom = %s, prenom = %s, code = %s, diplome = %s, specialite = %s, fonction = %s 
            WHERE id = %s
        """, (nom, prenom, code, diplome, specialite, fonction, id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Opérateur modifié avec succès', 'success')
        
        # Redirection vers la page de détails de l'opérateur
        return redirect(url_for('voir_operateur', id=id))
    
    cursor.close()
    
    # Affichage du formulaire de modification
    return render_template('operateurs/modifier.html', operateur=operateur)

@app.route('/operateurs/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_operateur(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'opérateur existe
    cursor.execute("SELECT * FROM operateur WHERE id = %s", [id])
    operateur = cursor.fetchone()
    
    if not operateur:
        cursor.close()
        flash('Opérateur non trouvé', 'danger')
        return redirect(url_for('liste_operateurs'))
    
    # Vérifier si l'opérateur est utilisé dans des interventions
    cursor.execute("SELECT COUNT(*) as count FROM dr WHERE operateur = %s", [id])
    intervention_count = cursor.fetchone()['count']
    
    if intervention_count > 0:
        cursor.close()
        flash('Impossible de supprimer cet opérateur car il est associé à des interventions', 'danger')
        return redirect(url_for('voir_operateur', id=id))
    
    # Supprimer l'opérateur
    cursor.execute("DELETE FROM operateur WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Opérateur supprimé avec succès', 'success')
    return redirect(url_for('liste_operateurs'))

# Routes pour les qualifications
@app.route('/qualifications')
@login_required
@perm_required('qualifications')
def liste_qualifications():
    # Récupérer le filtre de la requête GET
    designation = request.args.get('designation', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM qualification WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND designation LIKE %s"
        params.append(f'%{designation}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY designation"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    qualifications = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('qualifications/liste.html', 
                           qualifications=qualifications, 
                           filtres={
                               'designation': designation
                           })

@app.route('/qualifications/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_qualification():
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        
        # Vérifier si une qualification avec cette désignation existe déjà
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT * FROM qualification WHERE designation = %s", [designation])
        existing_qualification = cursor.fetchone()
        
        if existing_qualification:
            cursor.close()
            flash('Une qualification avec cette désignation existe déjà', 'danger')
            return render_template('qualifications/ajouter.html')
        
        # Insertion des données dans la table qualification
        cursor.execute("""
            INSERT INTO qualification 
            (designation) 
            VALUES (%s)
        """, [designation])
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Qualification ajoutée avec succès', 'success')
        
        # Redirection vers la liste des qualifications
        return redirect(url_for('liste_qualifications'))
    
    # Affichage du formulaire d'ajout
    return render_template('qualifications/ajouter.html')

@app.route('/qualifications/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_qualification(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la qualification existe
    cursor.execute("SELECT * FROM qualification WHERE id = %s", [id])
    qualification = cursor.fetchone()
    
    if not qualification:
        cursor.close()
        flash('Qualification non trouvée', 'danger')
        return redirect(url_for('liste_qualifications'))
    
    # Vérifier si la qualification est utilisée dans des gammes
    cursor.execute("SELECT COUNT(*) as count FROM qualification_gamme WHERE id_qualification = %s", [id])
    gamme_count = cursor.fetchone()['count']
    
    if gamme_count > 0:
        cursor.close()
        flash('Impossible de supprimer cette qualification car elle est utilisée dans des gammes', 'danger')
        return redirect(url_for('liste_qualifications'))
    
    # Supprimer la qualification
    cursor.execute("DELETE FROM qualification WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Qualification supprimée avec succès', 'success')
    return redirect(url_for('liste_qualifications'))

# Routes pour les outillages
@app.route('/outillages')
@login_required
@perm_required('outillages')
def liste_outillages():
    # Récupérer le filtre de la requête GET
    designation = request.args.get('designation', '')
    
    # Préparer la requête SQL de base
    sql_query = "SELECT * FROM outillage WHERE 1=1"
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if designation:
        sql_query += " AND designation LIKE %s"
        params.append(f'%{designation}%')
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY designation"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    outillages = cursor.fetchall()
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('outillages/liste.html', 
                           outillages=outillages, 
                           filtres={
                               'designation': designation
                           })

@app.route('/outillages/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_outillage():
    if request.method == 'POST':
        # Récupération des données du formulaire
        designation = request.form['designation']
        
        # Vérifier si un outillage avec cette désignation existe déjà
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT * FROM outillage WHERE designation = %s", [designation])
        existing_outillage = cursor.fetchone()
        
        if existing_outillage:
            cursor.close()
            flash('Un outillage avec cette désignation existe déjà', 'danger')
            return render_template('outillages/ajouter.html')
        
        # Insertion des données dans la table outillage
        cursor.execute("""
            INSERT INTO outillage 
            (designation) 
            VALUES (%s)
        """, [designation])
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Outillage ajouté avec succès', 'success')
        
        # Redirection vers la liste des outillages
        return redirect(url_for('liste_outillages'))
    
    # Affichage du formulaire d'ajout
    return render_template('outillages/ajouter.html')

@app.route('/outillages/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_outillage(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'outillage existe
    cursor.execute("SELECT * FROM outillage WHERE id = %s", [id])
    outillage = cursor.fetchone()
    
    if not outillage:
        cursor.close()
        flash('Outillage non trouvé', 'danger')
        return redirect(url_for('liste_outillages'))
    
    # Vérifier si l'outillage est utilisé dans des gammes
    cursor.execute("SELECT COUNT(*) as count FROM outillage_gamme WHERE id_outillage = %s", [id])
    gamme_count = cursor.fetchone()['count']
    
    if gamme_count > 0:
        cursor.close()
        flash('Impossible de supprimer cet outillage car il est utilisé dans des gammes', 'danger')
        return redirect(url_for('liste_outillages'))
    
    # Supprimer l'outillage
    cursor.execute("DELETE FROM outillage WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Outillage supprimé avec succès', 'success')
    return redirect(url_for('liste_outillages'))

# Routes pour les gammes de maintenance
@app.route('/gammes')
@login_required
@perm_required('gammes')
def liste_gammes():
    # Récupérer les filtres de la requête GET
    equipement = request.args.get('equipement', '')
    element = request.args.get('element', '')
    operation = request.args.get('operation', '')
    statut = request.args.get('statut', '')
    
    # Préparer la requête SQL de base
    sql_query = """
        SELECT g.*, m.designation as nom_equipement, o.designation as nom_operation, 
               op.nom as executant_nom, op.prenom as executant_prenom 
        FROM gamme g 
        LEFT JOIN mei m ON g.mei_ident = m.id 
        LEFT JOIN operation o ON g.id_operation = o.id 
        LEFT JOIN operateur op ON g.executant = op.id 
        WHERE 1=1
    """
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if equipement:
        sql_query += " AND g.mei_ident = %s"
        params.append(equipement)
    
    if element:
        sql_query += " AND g.element LIKE %s"
        params.append(f'%{element}%')
    
    if operation:
        sql_query += " AND g.id_operation = %s"
        params.append(operation)
        
    if statut:
        sql_query += " AND g.execution = %s"
        params.append(statut)
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY m.designation, g.element"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    gammes = cursor.fetchall()
    
    # Récupérer la liste des équipements pour le filtre
    cursor.execute("SELECT id, designation FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    
    # Récupérer la liste des opérations pour le filtre
    cursor.execute("SELECT id, designation FROM operation ORDER BY designation")
    operations = cursor.fetchall()
    
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('gammes/liste.html', 
                           gammes=gammes, 
                           equipements=equipements,
                           operations=operations,
                           filtres={
                               'equipement': equipement,
                               'element': element,
                               'operation': operation,
                               'statut': statut
                           })

@app.route('/gammes/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_gamme():
    # Récupérer la liste des équipements, opérations et exécutants pour le formulaire
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id, designation FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    
    cursor.execute("SELECT id, designation FROM operation ORDER BY designation")
    operations = cursor.fetchall()
    
    cursor.execute("SELECT id, nom, prenom, fonction FROM operateur ORDER BY nom, prenom")
    executants = cursor.fetchall()
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        mei_ident = request.form['mei_ident']
        element = request.form['element']
        id_operation = request.form['id_operation']
        executant = request.form['executant']
        marche = request.form['marche']
        duree = request.form['duree']
        periodicite = request.form['periodicite']
        execution = request.form.get('execution', 'non')
        
        # Insertion des données dans la table gamme
        cursor.execute("""
            INSERT INTO gamme 
            (mei_ident, element, id_operation, executant, marche, duree, periodicite, execution) 
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
        """, (mei_ident, element, id_operation, executant, marche, duree, periodicite, execution))
        
        # Récupérer l'ID de la gamme créée
        gamme_id = cursor.lastrowid
        
        # Ajouter les outillages si spécifiés
        outillages = request.form.getlist('outillages')
        for outillage_id in outillages:
            cursor.execute("""
                INSERT INTO outillage_gamme 
                (id_gamme, id_outillage) 
                VALUES (%s, %s)
            """, (gamme_id, outillage_id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Gamme de maintenance ajoutée avec succès', 'success')
        
        # Redirection vers la liste des gammes
        return redirect(url_for('liste_gammes'))
    
    # Récupérer la liste des outillages pour le formulaire
    cursor.execute("SELECT id, designation FROM outillage ORDER BY designation")
    outillages = cursor.fetchall()
    
    cursor.close()
    
    # Affichage du formulaire d'ajout
    return render_template('gammes/ajouter.html', 
                           equipements=equipements, 
                           operations=operations, 
                           executants=executants,
                           outillages=outillages)

@app.route('/gammes/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_gamme(id):
    # Récupérer les informations de la gamme
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la gamme
    cursor.execute("""
        SELECT g.*, m.designation as nom_equipement, o.designation as nom_operation, 
               op.nom as executant_nom, op.prenom as executant_prenom 
        FROM gamme g 
        LEFT JOIN mei m ON g.mei_ident = m.id 
        LEFT JOIN operation o ON g.id_operation = o.id 
        LEFT JOIN operateur op ON g.executant = op.id 
        WHERE g.id = %s
    """, [id])
    gamme = cursor.fetchone()
    
    if not gamme:
        cursor.close()
        flash('Gamme de maintenance non trouvée', 'danger')
        return redirect(url_for('liste_gammes'))
    
    # Récupérer la liste des équipements, opérations et exécutants pour le formulaire
    cursor.execute("SELECT id, designation FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    
    cursor.execute("SELECT id, designation FROM operation ORDER BY designation")
    operations = cursor.fetchall()
    
    cursor.execute("SELECT id, nom, prenom, fonction FROM operateur ORDER BY nom, prenom")
    executants = cursor.fetchall()
    
    # Récupérer les outillages associés à la gamme
    cursor.execute("""
        SELECT og.id_outillage 
        FROM outillage_gamme og 
        WHERE og.id_gamme = %s
    """, [id])
    outillages_associes = [row['id_outillage'] for row in cursor.fetchall()]
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        mei_ident = request.form['mei_ident']
        element = request.form['element']
        id_operation = request.form['id_operation']
        executant = request.form['executant']
        marche = request.form['marche']
        duree = request.form['duree']
        periodicite = request.form['periodicite']
        execution = request.form.get('execution', 'non')
        
        # Mise à jour des données dans la table gamme
        cursor.execute("""
            UPDATE gamme 
            SET mei_ident = %s, element = %s, id_operation = %s, executant = %s, 
                marche = %s, duree = %s, periodicite = %s, execution = %s 
            WHERE id = %s
        """, (mei_ident, element, id_operation, executant, marche, duree, periodicite, execution, id))
        
        # Supprimer les associations existantes avec les outillages
        cursor.execute("DELETE FROM outillage_gamme WHERE id_gamme = %s", [id])
        
        # Ajouter les nouveaux outillages sélectionnés
        outillages = request.form.getlist('outillages')
        for outillage_id in outillages:
            cursor.execute("""
                INSERT INTO outillage_gamme 
                (id_gamme, id_outillage) 
                VALUES (%s, %s)
            """, (id, outillage_id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Gamme de maintenance modifiée avec succès', 'success')
        
        # Redirection vers la page de détails de la gamme
        return redirect(url_for('voir_gamme', id=id))
    
    # Récupérer tous les outillages pour le formulaire
    cursor.execute("SELECT id, designation FROM outillage ORDER BY designation")
    outillages = cursor.fetchall()
    
    cursor.close()
    
    # Affichage du formulaire de modification
    return render_template('gammes/modifier.html', 
                           gamme=gamme, 
                           equipements=equipements, 
                           operations=operations, 
                           executants=executants,
                           outillages=outillages,
                           outillages_associes=outillages_associes)

@app.route('/gammes/voir/<int:id>')
@login_required
def voir_gamme(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la gamme
    cursor.execute("""
        SELECT g.*, m.designation as nom_equipement, o.designation as nom_operation, 
               op.nom as executant_nom, op.prenom as executant_prenom, 
               op.fonction as executant_fonction 
        FROM gamme g 
        LEFT JOIN mei m ON g.mei_ident = m.id 
        LEFT JOIN operation o ON g.id_operation = o.id 
        LEFT JOIN operateur op ON g.executant = op.id 
        WHERE g.id = %s
    """, [id])
    gamme = cursor.fetchone()
    
    if not gamme:
        cursor.close()
        flash('Gamme de maintenance non trouvée', 'danger')
        return redirect(url_for('liste_gammes'))
    
    # Récupérer les outillages associés
    cursor.execute("""
        SELECT o.* 
        FROM outillage o 
        JOIN outillage_gamme og ON o.id = og.id_outillage 
        WHERE og.id_gamme = %s
        ORDER BY o.designation
    """, [id])
    outillages = cursor.fetchall()
    
    cursor.close()
    
    return render_template('gammes/voir.html', gamme=gamme, outillages=outillages)

@app.route('/gammes/changer-statut/<int:id>')
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def changer_statut_gamme(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la gamme existe
    cursor.execute("SELECT * FROM gamme WHERE id = %s", [id])
    gamme = cursor.fetchone()
    
    if not gamme:
        cursor.close()
        flash('Gamme de maintenance non trouvée', 'danger')
        return redirect(url_for('liste_gammes'))
    
    # Inverser le statut d'exécution
    nouveau_statut = 'oui' if gamme['execution'] != 'oui' else 'non'
    
    # Mettre à jour le statut
    cursor.execute("UPDATE gamme SET execution = %s WHERE id = %s", [nouveau_statut, id])
    mysql.connection.commit()
    
    # Message de succès
    message = 'Gamme marquée comme exécutée' if nouveau_statut == 'oui' else 'Gamme marquée comme non exécutée'
    flash(message, 'success')
    
    cursor.close()
    return redirect(url_for('liste_gammes'))

@app.route('/gammes/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_gamme(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la gamme existe
    cursor.execute("SELECT * FROM gamme WHERE id = %s", [id])
    gamme = cursor.fetchone()
    
    if not gamme:
        cursor.close()
        flash('Gamme de maintenance non trouvée', 'danger')
        return redirect(url_for('liste_gammes'))
    
    # Supprimer les associations avec les outillages
    cursor.execute("DELETE FROM outillage_gamme WHERE id_gamme = %s", [id])
    
    # Supprimer la gamme
    cursor.execute("DELETE FROM gamme WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Gamme de maintenance supprimée avec succès', 'success')
    return redirect(url_for('liste_gammes'))

# Routes pour les commandes
@app.route('/commandes')
@login_required
@perm_required('commandes')
def liste_commandes():
    # Récupérer les filtres de la requête GET
    numero = request.args.get('numero', '')
    date_debut = request.args.get('date_debut', '')
    date_fin = request.args.get('date_fin', '')
    fournisseur = request.args.get('fournisseur', '')
    
    # Préparer la requête SQL de base
    sql_query = """
        SELECT c.id, c.num, c.date_cde, c.id_fournisseur, f.nom as nom_fournisseur
        FROM commande c
        LEFT JOIN fournisseur f ON c.id_fournisseur = f.id
        WHERE 1=1
    """
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if numero:
        sql_query += " AND c.num LIKE %s"
        params.append(f'%{numero}%')
    
    if fournisseur:
        sql_query += " AND c.id_fournisseur = %s"
        params.append(fournisseur)
    
    if date_debut and date_fin:
        sql_query += " AND c.date_cde BETWEEN %s AND %s"
        params.append(date_debut)
        params.append(date_fin)
    elif date_debut:
        sql_query += " AND c.date_cde >= %s"
        params.append(date_debut)
    elif date_fin:
        sql_query += " AND c.date_cde <= %s"
        params.append(date_fin)
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY c.date_cde DESC"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    commandes = cursor.fetchall()
    
    # Récupérer la liste des fournisseurs pour le filtre
    cursor.execute("SELECT id, nom FROM fournisseur ORDER BY nom")
    fournisseurs = cursor.fetchall()
    
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('commandes/liste.html', 
                           commandes=commandes,
                           fournisseurs=fournisseurs,
                           filtres={
                               'numero': numero,
                               'date_debut': date_debut,
                               'date_fin': date_fin,
                               'fournisseur': fournisseur
                           })

@app.route('/commandes/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_commande():
    if request.method == 'POST':
        # Récupération des données du formulaire
        numero = request.form['numero']
        date = request.form['date']
        id_fournisseur = request.form['id_fournisseur']
        description = request.form.get('description', '')
        
        # Insertion des données dans la table commande
        cursor = mysql.connection.cursor()
        
        # Vérifier si un numéro de commande existe déjà
        cursor.execute("SELECT * FROM commande WHERE num = %s", [numero])
        existing_commande = cursor.fetchone()
        
        if existing_commande:
            cursor.close()
            flash('Une commande avec ce numéro existe déjà', 'danger')
            return redirect(url_for('ajouter_commande'))
        
        # Préparer la requête SQL d'insertion
        sql_query = """
            INSERT INTO commande 
            (num, date_cde, id_fournisseur) 
            VALUES (%s, %s, %s)
        """
        
        cursor.execute(sql_query, (numero, date, id_fournisseur))
        
        # Récupérer l'ID de la nouvelle commande
        commande_id = cursor.lastrowid
        
        # Les articles de la commande seraient normalement enregistrés ici,
        # mais la table cde n'a pas la structure attendue pour stocker les articles
        # (pas de colonne id_commande, id_pr, quantite, prix_unitaire)
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Commande ajoutée avec succès', 'success')
        
        # Redirection vers la liste des commandes
        return redirect(url_for('liste_commandes'))
    
    # Récupérer la liste des fournisseurs pour le formulaire
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id, nom FROM fournisseur ORDER BY nom")
    fournisseurs = cursor.fetchall()
    
    # Récupérer la liste des pièces pour le formulaire
    cursor.execute("SELECT id, designation, ref FROM pr ORDER BY designation")
    pieces = cursor.fetchall()
    
    cursor.close()
    
    # Affichage du formulaire d'ajout
    return render_template('commandes/ajouter.html', fournisseurs=fournisseurs, pieces=pieces)

@app.route('/commandes/voir/<int:id>')
@login_required
def voir_commande(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de la commande
    cursor.execute("""
        SELECT c.id, c.num, c.date_cde, c.id_fournisseur, 
               f.nom as nom_fournisseur, f.address as adresse_fournisseur, 
               f.mobile as tel_fournisseur, f.email as email_fournisseur 
        FROM commande c 
        LEFT JOIN fournisseur f ON c.id_fournisseur = f.id 
        WHERE c.id = %s
    """, [id])
    commande = cursor.fetchone()
    
    if not commande:
        cursor.close()
        flash('Commande non trouvée', 'danger')
        return redirect(url_for('liste_commandes'))
    
    # La table cde n'a pas la structure attendue pour stocker les articles
    # associés à une commande (pas de colonne id_commande, id_pr, quantite, prix_unitaire)
    articles = []
    total = 0
    
    cursor.close()
    
    return render_template('commandes/voir.html', commande=commande, articles=articles, total=total)

@app.route('/commandes/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_commande(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer la commande
    cursor.execute("""
        SELECT c.* 
        FROM commande c 
        WHERE c.id = %s
    """, [id])
    commande = cursor.fetchone()
    
    if not commande:
        cursor.close()
        flash('Commande non trouvée', 'danger')
        return redirect(url_for('liste_commandes'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        numero = request.form['numero']
        date = request.form['date']
        id_fournisseur = request.form['id_fournisseur']
        
        # Vérifier si le numéro existe déjà pour une autre commande
        cursor.execute("SELECT * FROM commande WHERE num = %s AND id != %s", [numero, id])
        existing_commande = cursor.fetchone()
        
        if existing_commande:
            cursor.close()
            flash('Une autre commande avec ce numéro existe déjà', 'danger')
            return redirect(url_for('modifier_commande', id=id))
        
        # Mettre à jour la commande
        cursor.execute("""
            UPDATE commande 
            SET num = %s, date_cde = %s, id_fournisseur = %s 
            WHERE id = %s
        """, (numero, date, id_fournisseur, id))
        
        # La table cde n'a pas la structure attendue pour stocker les articles
        # associés à une commande
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Commande modifiée avec succès', 'success')
        
        # Redirection vers la page de détails
        return redirect(url_for('voir_commande', id=id))
    
    # La table cde n'a pas la structure attendue pour stocker les articles
    # associés à une commande
    
    # Récupérer la liste des fournisseurs pour le formulaire
    cursor.execute("SELECT id, nom FROM fournisseur ORDER BY nom")
    fournisseurs = cursor.fetchall()
    
    # Récupérer la liste des pièces pour le formulaire
    cursor.execute("SELECT id, designation, ref FROM pr ORDER BY designation")
    pieces = cursor.fetchall()
    
    cursor.close()
    
    return render_template('commandes/modifier.html', 
                           commande=commande, 
                           articles=[], 
                           fournisseurs=fournisseurs, 
                           pieces=pieces)

# La fonction changer_statut_commande est supprimée car il n'y a pas de colonne statut
# dans la table commande

@app.route('/commandes/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_commande(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si la commande existe
    cursor.execute("SELECT * FROM commande WHERE id = %s", [id])
    commande = cursor.fetchone()
    
    if not commande:
        cursor.close()
        flash('Commande non trouvée', 'danger')
        return redirect(url_for('liste_commandes'))
    
    # La table cde n'a pas de colonne id_commande, donc on ne peut pas supprimer
    # les articles associés à une commande
    
    # Supprimer uniquement la commande
    cursor.execute("DELETE FROM commande WHERE id = %s", [id])
    
    mysql.connection.commit()
    cursor.close()
    
    flash('Commande supprimée avec succès', 'success')
    return redirect(url_for('liste_commandes'))

# Routes pour les constats
@app.route('/constats')
@login_required
@perm_required('constats')
def liste_constats():
    # Récupérer les filtres de la requête GET
    numero = request.args.get('numero', '')
    date_debut = request.args.get('date_debut', '')
    date_fin = request.args.get('date_fin', '')
    
    # Préparer la requête SQL de base
    sql_query = """
        SELECT c.*, b.numero as num_bl 
        FROM constat c 
        LEFT JOIN bl b ON c.id_bl = b.id 
        WHERE 1=1 
    """
    params = []
    
    # Ajouter les conditions en fonction des filtres
    if numero:
        sql_query += " AND c.num LIKE %s"
        params.append(f'%{numero}%')
    
    if date_debut and date_fin:
        sql_query += " AND c.date BETWEEN %s AND %s"
        params.append(date_debut)
        params.append(date_fin)
    elif date_debut:
        sql_query += " AND c.date >= %s"
        params.append(date_debut)
    elif date_fin:
        sql_query += " AND c.date <= %s"
        params.append(date_fin)
    
    # Ajouter l'ordre de tri
    sql_query += " ORDER BY c.date DESC"
    
    # Exécuter la requête SQL
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    constats = cursor.fetchall()
    
    cursor.close()
    
    # Passer les valeurs des filtres au template pour les maintenir dans le formulaire
    return render_template('constats/liste.html', 
                           constats=constats, 
                           filtres={
                               'numero': numero,
                               'date_debut': date_debut,
                               'date_fin': date_fin
                           })

@app.route('/constats/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM', 'AQ')
def ajouter_constat():
    if request.method == 'POST':
        # Récupération des données du formulaire
        numero = request.form['numero']
        date = request.form['date']
        id_bl = request.form['id_bl']
        
        # Insertion des données dans la table constat
        cursor = mysql.connection.cursor()
        
        # Vérifier si un numéro de constat existe déjà
        cursor.execute("SELECT * FROM constat WHERE num = %s", [numero])
        existing_constat = cursor.fetchone()
        
        if existing_constat:
            cursor.close()
            flash('Un constat avec ce numéro existe déjà', 'danger')
            return redirect(url_for('ajouter_constat'))
        
        # Préparer la requête SQL d'insertion
        cursor.execute("""
            INSERT INTO constat 
            (num, date, id_bl) 
            VALUES (%s, %s, %s)
        """, (numero, date, id_bl))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Constat ajouté avec succès', 'success')
        
        # Redirection vers la liste des constats
        return redirect(url_for('liste_constats'))
    
    # Récupérer la liste des bons de livraison pour le formulaire
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id, numero, date FROM bl ORDER BY date DESC")
    bons_livraison = cursor.fetchall()
    cursor.close()
    
    # Affichage du formulaire d'ajout
    return render_template('constats/ajouter.html', bons_livraison=bons_livraison)

@app.route('/constats/voir/<int:id>')
@login_required
def voir_constat(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails du constat
    cursor.execute("""
        SELECT c.*, b.numero as num_bl, b.date as date_bl 
        FROM constat c 
        LEFT JOIN bl b ON c.id_bl = b.id 
        WHERE c.id = %s
    """, [id])
    constat = cursor.fetchone()
    
    if not constat:
        cursor.close()
        flash('Constat non trouvé', 'danger')
        return redirect(url_for('liste_constats'))
    
    # Pour l'instant, nous n'affichons pas les éléments du bon de livraison car la structure de la base de données
    # ne permet pas de les récupérer facilement avec la requête actuelle
    elements = []
    
    cursor.close()
    
    return render_template('constats/voir.html', constat=constat, elements=elements)

@app.route('/constats/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM', 'AQ')
def modifier_constat(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer le constat
    cursor.execute("SELECT * FROM constat WHERE id = %s", [id])
    constat = cursor.fetchone()
    
    if not constat:
        cursor.close()
        flash('Constat non trouvé', 'danger')
        return redirect(url_for('liste_constats'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        numero = request.form['numero']
        date = request.form['date']
        id_bl = request.form['id_bl']
        
        # Vérifier si le numéro existe déjà pour un autre constat
        cursor.execute("SELECT * FROM constat WHERE num = %s AND id != %s", [numero, id])
        existing_constat = cursor.fetchone()
        
        if existing_constat:
            cursor.close()
            flash('Un autre constat avec ce numéro existe déjà', 'danger')
            return redirect(url_for('modifier_constat', id=id))
        
        # Mettre à jour le constat
        cursor.execute("""
            UPDATE constat 
            SET num = %s, date = %s, id_bl = %s 
            WHERE id = %s
        """, (numero, date, id_bl, id))
        
        # Validation des modifications
        mysql.connection.commit()
        cursor.close()
        
        # Message de succès
        flash('Constat modifié avec succès', 'success')
        
        # Redirection vers la page de détails
        return redirect(url_for('voir_constat', id=id))
    
    # Récupérer la liste des bons de livraison pour le formulaire
    cursor.execute("SELECT id, numero, date FROM bl ORDER BY date DESC")
    bons_livraison = cursor.fetchall()
    
    cursor.close()
    
    return render_template('constats/modifier.html', constat=constat, bons_livraison=bons_livraison)

@app.route('/constats/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_constat(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si le constat existe
    cursor.execute("SELECT * FROM constat WHERE id = %s", [id])
    constat = cursor.fetchone()
    
    if not constat:
        cursor.close()
        flash('Constat non trouvé', 'danger')
        return redirect(url_for('liste_constats'))
    
    # Vérifier les relations avant de supprimer
    cursor.execute("SELECT COUNT(*) as count FROM av_prs WHERE id_constat = %s", [id])
    relation_count = cursor.fetchone()['count']
    
    if relation_count > 0:
        cursor.close()
        flash('Impossible de supprimer ce constat car il est utilisé par d\'autres éléments', 'danger')
        return redirect(url_for('voir_constat', id=id))
    
    # Supprimer le constat
    cursor.execute("DELETE FROM constat WHERE id = %s", [id])
    
    mysql.connection.commit()
    cursor.close()
    
    flash('Constat supprimé avec succès', 'success')
    return redirect(url_for('liste_constats'))

# ===== GESTION DES RAPPORTS DE CONTRÔLE =====

# Route pour la liste des rapports de contrôle
@app.route('/rapports')
@login_required
@perm_required('rapports')
def liste_rapports():
    # Préparer les filtres
    filtres = {
        'numero': request.args.get('numero', ''),
        'date_debut': request.args.get('date_debut', ''),
        'date_fin': request.args.get('date_fin', ''),
        'equipement': request.args.get('equipement', '')
    }
    
    # Préparer la requête SQL de base
    sql_query = """
        SELECT r.*, m.designation as nom_equipement 
        FROM rapport_ctrl r 
        LEFT JOIN mei m ON r.id_mei = m.id 
        WHERE 1=1 
    """
    params = []
    
    # Ajouter les filtres si nécessaire
    if filtres['numero']:
        sql_query += " AND r.num LIKE %s"
        params.append(f"%{filtres['numero']}%")
    
    if filtres['date_debut']:
        sql_query += " AND r.date >= %s"
        params.append(filtres['date_debut'])
    
    if filtres['date_fin']:
        sql_query += " AND r.date <= %s"
        params.append(filtres['date_fin'])
    
    if filtres['equipement']:
        sql_query += " AND m.designation LIKE %s"
        params.append(f"%{filtres['equipement']}%")
    
    # Exécuter la requête
    cursor = mysql.connection.cursor()
    cursor.execute(sql_query, params)
    rapports = cursor.fetchall()
    cursor.close()
    
    return render_template('rapports/liste.html', rapports=rapports, filtres=filtres)

# Route pour ajouter un rapport de contrôle
@app.route('/rapports/ajouter', methods=['GET', 'POST'])
@login_required
def ajouter_rapport():
    if request.method == 'POST':
        # Récupérer les données du formulaire
        numero = request.form['numero']
        id_mei = request.form['id_mei']
        nom_org = request.form['nom_org']
        date = request.form['date']
        constatation = request.form['constatation']
        valide = request.form.get('valide', 'non')
        
        # Insérer le rapport de contrôle dans la base de données
        cursor = mysql.connection.cursor()
        cursor.execute("""
            INSERT INTO rapport_ctrl (num, id_mei, nom_org, date, constatation, valide)
            VALUES (%s, %s, %s, %s, %s, %s)
        """, (numero, id_mei, nom_org, date, constatation, valide))
        mysql.connection.commit()
        cursor.close()
        
        flash('Rapport de contrôle ajouté avec succès', 'success')
        session['notif_key'] = 'rapport_ajoute'
        session['notification_link'] = url_for('liste_rapports')
        return redirect(url_for('liste_rapports'))
    
    # Récupérer la liste des équipements pour le formulaire
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id, designation, code_inventaire FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    cursor.close()
    
    # Date du jour pour le formulaire
    now = datetime.now()
    
    return render_template('rapports/ajouter.html', equipements=equipements, now=now)

# Route pour voir un rapport de contrôle
@app.route('/rapports/voir/<int:id>')
@login_required
def voir_rapport(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails du rapport
    cursor.execute("""
        SELECT r.*, m.designation as nom_equipement, m.code_inventaire, m.code_identification, m.marque, m.type, m.serie
        FROM rapport_ctrl r 
        LEFT JOIN mei m ON r.id_mei = m.id 
        WHERE r.id = %s
    """, [id])
    rapport = cursor.fetchone()
    
    if not rapport:
        cursor.close()
        flash('Rapport de contrôle non trouvé', 'danger')
        return redirect(url_for('liste_rapports'))
    
    cursor.close()
    
    return render_template('rapports/voir.html', rapport=rapport)

# Route pour modifier un rapport de contrôle
@app.route('/rapports/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM', 'AQ')
def modifier_rapport(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer le rapport
    cursor.execute("SELECT * FROM rapport_ctrl WHERE id = %s", [id])
    rapport = cursor.fetchone()
    
    if not rapport:
        cursor.close()
        flash('Rapport de contrôle non trouvé', 'danger')
        return redirect(url_for('liste_rapports'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        numero = request.form['numero']
        id_mei = request.form['id_mei']
        nom_org = request.form['nom_org']
        date = request.form['date']
        constatation = request.form['constatation']
        valide = request.form.get('valide', 'non')
        
        # Mettre à jour le rapport
        cursor.execute("""
            UPDATE rapport_ctrl 
            SET num = %s, id_mei = %s, nom_org = %s, date = %s, constatation = %s, valide = %s 
            WHERE id = %s
        """, (numero, id_mei, nom_org, date, constatation, valide, id))
        mysql.connection.commit()
        
        flash('Rapport de contrôle mis à jour avec succès', 'success')
        return redirect(url_for('voir_rapport', id=id))
    
    # Récupérer la liste des équipements pour le formulaire
    cursor.execute("SELECT id, designation, code_inventaire FROM mei ORDER BY designation")
    equipements = cursor.fetchall()
    
    cursor.close()
    
    return render_template('rapports/modifier.html', rapport=rapport, equipements=equipements)

# Route pour supprimer un rapport de contrôle
@app.route('/rapports/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_rapport(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si le rapport existe
    cursor.execute("SELECT * FROM rapport_ctrl WHERE id = %s", [id])
    rapport = cursor.fetchone()
    
    if not rapport:
        cursor.close()
        flash('Rapport de contrôle non trouvé', 'danger')
        return redirect(url_for('liste_rapports'))
    
    # Supprimer le rapport
    cursor.execute("DELETE FROM rapport_ctrl WHERE id = %s", [id])
    mysql.connection.commit()
    cursor.close()
    
    flash('Rapport de contrôle supprimé avec succès', 'success')
    return redirect(url_for('liste_rapports'))

# Routes pour les ordres de travail (ord)
@app.route('/ordres')
@login_required
@perm_required('ordres')
def liste_ordres():
    num_or = request.args.get('num_or', '')
    num_dr = request.args.get('num_dr', '')
    date_debut = request.args.get('date_debut', '')
    date_fin = request.args.get('date_fin', '')
    signature = request.args.get('signature', '')

    sql_query = """
        SELECT o.*, d.description as demande_libelle
        FROM ord o
        LEFT JOIN dr d ON o.num_dr = d.numero
        WHERE 1=1
    """
    params = []

    if num_or:
        sql_query += " AND o.num_or LIKE %s"
        params.append(f'%{num_or}%')
    if num_dr:
        sql_query += " AND o.num_dr LIKE %s"
        params.append(f'%{num_dr}%')
    if date_debut:
        sql_query += " AND STR_TO_DATE(o.date, '%%d/%%m/%%Y') >= STR_TO_DATE(%s, '%%Y-%%m-%%d')"
        params.append(date_debut)
    if date_fin:
        sql_query += " AND STR_TO_DATE(o.date, '%%d/%%m/%%Y') <= STR_TO_DATE(%s, '%%Y-%%m-%%d')"
        params.append(date_fin)
    if signature:
        sql_query += " AND o.signature = %s"
        params.append(signature)

    sql_query += " ORDER BY o.id DESC"

    cursor = mysql.connection.cursor()
    try:
        cursor.execute(sql_query, params if params else None)
        ordres = cursor.fetchall()
    except Exception:
        ordres = []
        flash('Erreur lors du chargement des ordres de travail.', 'danger')
    finally:
        cursor.close()

    return render_template('ordres/liste.html', ordres=ordres)

@app.route('/ordres/ajouter', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def ajouter_ordre():
    if request.method == 'POST':
        # Récupération des données du formulaire
        num_or = request.form['num_or']
        num_dr = request.form['num_dr']
        date = request.form['date']
        date_debut = request.form.get('date_debut', '')
        heure_debut = request.form.get('heure_debut', '')
        date_fin = request.form.get('date_fin', '')
        heure_fin = request.form.get('heure_fin', '')
        diagnostic = request.form.get('diagnostic', '')
        nature_intervention = request.form.get('nature_intervention', '')
        temps_diagnostic = request.form.get('temps_diagnostic', '')
        temps_intervention = request.form.get('temps_intervention', '')
        num_bp = request.form.get('num_bp', '')
        constatation = request.form.get('constatation', '')
        nom_prenom_user = session.get('username', '')
        date_recep = datetime.now().strftime('%d/%m/%Y')
        heure_recep = datetime.now().strftime('%H:%M')
        signature = request.form.get('signature', 'non')
        
        # Vérifier si l'ordre de travail existe déjà
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT id FROM ord WHERE num_or = %s", [num_or])
        existing_order = cursor.fetchone()
        
        if existing_order:
            flash('Un ordre de travail avec ce numéro existe déjà', 'danger')
            cursor.close()
            return redirect(url_for('ajouter_ordre'))
        
        # Insertion dans la base de données
        cursor.execute("""
            INSERT INTO ord (num_or, num_dr, date, date_debut, heure_debut, date_fin, heure_fin, 
            diagnostic, nature_intervention, temps_diagnostic, temps_intervention, num_bp, 
            constatation, nom_prenom_user, date_recep, heure_recep, signature)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """, (num_or, num_dr, date, date_debut, heure_debut, date_fin, heure_fin, diagnostic, 
              nature_intervention, temps_diagnostic, temps_intervention, num_bp, constatation, 
              nom_prenom_user, date_recep, heure_recep, signature))
        
        # Récupérer l'ID de l'ordre de travail créé
        ordre_id = cursor.lastrowid
        
        # Récupérer les opérateurs sélectionnés
        operateurs = request.form.getlist('operateurs')
        
        # Associer les opérateurs à l'ordre de travail
        for operateur_id in operateurs:
            cursor.execute("""
                INSERT INTO ornombreoperateur (num_or, id_operateur)
                VALUES (%s, %s)
            """, (num_or, operateur_id))
        
        add_db_notification(
            notif_key='ordre_travail',
            title="Nouvel ordre de travail",
            message=f"L'ordre de travail N° {num_or} a été créé (associé à la DI N° {num_dr}).",
            type='success',
            link=url_for('voir_ordre', id=ordre_id),
            permission_required='ordres'
        )
        
        mysql.connection.commit()
        cursor.close()
        session['notif_key'] = 'ordre_travail'
        session['notification_link'] = url_for('voir_ordre', id=ordre_id)
        flash('Ordre de travail ajouté avec succès', 'success')
        return redirect(url_for('voir_ordre', id=ordre_id))
    
    # Récupérer la liste des demandes d'intervention pour le formulaire
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT numero, description FROM dr WHERE est_traiter = 'non' AND annuler = 'non' ORDER BY date DESC")
    demandes = cursor.fetchall()
    
    # Récupérer la liste des opérateurs pour le formulaire
    cursor.execute("SELECT id, nom, prenom, code, specialite FROM operateur ORDER BY nom, prenom")
    operateurs = cursor.fetchall()
    
    cursor.close()
    
    # Générer un numéro d'ordre automatique basé sur l'année et le mois actuels
    now = datetime.now()
    prefix = f"OR{now.year % 100}{now.month:02d}-"
    
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT num_or FROM ord WHERE num_or LIKE %s ORDER BY id DESC LIMIT 1", [f"{prefix}%"])
    last_order = cursor.fetchone()
    cursor.close()
    
    if last_order:
        # Extraire le numéro et l'incrémenter
        last_num = int(last_order['num_or'].split('-')[1])
        new_num = f"{prefix}{last_num + 1:03d}"
    else:
        # Premier ordre du mois
        new_num = f"{prefix}001"
    
    return render_template('ordres/ajouter.html', demandes=demandes, operateurs=operateurs, new_num=new_num)

@app.route('/ordres/voir/<int:id>')
@login_required
def voir_ordre(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer les détails de l'ordre de travail
    cursor.execute("""
        SELECT o.*, d.description as demande_libelle, d.degre as demande_degre, 
               m.designation as equipement_nom, m.code_inventaire, m.position as localisation
        FROM ord o 
        LEFT JOIN dr d ON o.num_dr = d.numero 
        LEFT JOIN mei m ON d.id_mei = m.id 
        WHERE o.id = %s
    """, (id,))
    ordre = cursor.fetchone()
    
    if not ordre:
        cursor.close()
        flash('Ordre de travail non trouvé', 'danger')
        return redirect(url_for('liste_ordres'))
    
    # Récupérer les opérateurs associés à l'ordre de travail
    cursor.execute("""
        SELECT op.* 
        FROM ornombreoperateur ono 
        JOIN operateur op ON ono.id_operateur = op.id 
        WHERE ono.num_or = %s
    """, (ordre['num_or'],))
    operateurs = cursor.fetchall()
    
    cursor.close()
    
    return render_template('ordres/voir.html', ordre=ordre, operateurs=operateurs)

@app.route('/ordres/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@role_required('DIRECTION', 'CHEF DEPARTEMENT', 'STM', 'SIM', 'CEM')
def modifier_ordre(id):
    cursor = mysql.connection.cursor()
    
    # Récupérer l'ordre de travail
    cursor.execute("SELECT * FROM ord WHERE id = %s", (id,))
    ordre = cursor.fetchone()
    
    if not ordre:
        cursor.close()
        flash('Ordre de travail non trouvé', 'danger')
        return redirect(url_for('liste_ordres'))
    
    if request.method == 'POST':
        # Récupération des données du formulaire
        num_dr = request.form['num_dr']
        date = request.form['date']
        date_debut = request.form.get('date_debut', '')
        heure_debut = request.form.get('heure_debut', '')
        date_fin = request.form.get('date_fin', '')
        heure_fin = request.form.get('heure_fin', '')
        diagnostic = request.form.get('diagnostic', '')
        nature_intervention = request.form.get('nature_intervention', '')
        temps_diagnostic = request.form.get('temps_diagnostic', '')
        temps_intervention = request.form.get('temps_intervention', '')
        num_bp = request.form.get('num_bp', '')
        constatation = request.form.get('constatation', '')
        signature = request.form.get('signature', 'non')
        
        # Mise à jour dans la base de données
        cursor.execute("""
            UPDATE ord 
            SET num_dr = %s, date = %s, date_debut = %s, heure_debut = %s, date_fin = %s, heure_fin = %s, 
            diagnostic = %s, nature_intervention = %s, temps_diagnostic = %s, temps_intervention = %s, 
            num_bp = %s, constatation = %s, signature = %s 
            WHERE id = %s
        """, (num_dr, date, date_debut, heure_debut, date_fin, heure_fin, diagnostic, 
              nature_intervention, temps_diagnostic, temps_intervention, num_bp, constatation, 
              signature, id))
        
        # Supprimer les anciens opérateurs associés
        cursor.execute("DELETE FROM ornombreoperateur WHERE num_or = %s", (ordre['num_or'],))
        
        # Récupérer les opérateurs sélectionnés
        operateurs = request.form.getlist('operateurs')
        
        # Associer les opérateurs à l'ordre de travail
        for operateur_id in operateurs:
            cursor.execute("""
                INSERT INTO ornombreoperateur (num_or, id_operateur)
                VALUES (%s, %s)
            """, (ordre['num_or'], operateur_id))
        
        mysql.connection.commit()
        
        flash('Ordre de travail mis à jour avec succès', 'success')
        return redirect(url_for('voir_ordre', id=id))
    
    # Récupérer la liste des demandes d'intervention pour le formulaire
    cursor.execute("SELECT numero, description FROM dr ORDER BY date DESC")
    demandes = cursor.fetchall()
    
    # Récupérer la liste des opérateurs pour le formulaire
    cursor.execute("SELECT id, nom, prenom, code, specialite FROM operateur ORDER BY nom, prenom")
    operateurs = cursor.fetchall()
    
    # Récupérer les opérateurs associés à l'ordre de travail
    cursor.execute("SELECT id_operateur FROM ornombreoperateur WHERE num_or = %s", (ordre['num_or'],))
    operateurs_selectionnes = [op['id_operateur'] for op in cursor.fetchall()]
    
    cursor.close()
    
    return render_template('ordres/modifier.html', ordre=ordre, demandes=demandes, 
                           operateurs=operateurs, operateurs_selectionnes=operateurs_selectionnes)

@app.route('/ordres/supprimer/<int:id>')
@login_required
@role_required('SUPER ADMIN', 'STM', 'CEM')
def supprimer_ordre(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'ordre de travail existe
    cursor.execute("SELECT * FROM ord WHERE id = %s", (id,))
    ordre = cursor.fetchone()
    
    if not ordre:
        cursor.close()
        flash('Ordre de travail non trouvé', 'danger')
        return redirect(url_for('liste_ordres'))
    
    # Supprimer les opérateurs associés
    cursor.execute("DELETE FROM ornombreoperateur WHERE num_or = %s", (ordre['num_or'],))
    
    # Supprimer l'ordre de travail
    cursor.execute("DELETE FROM ord WHERE id = %s", (id,))
    mysql.connection.commit()
    cursor.close()
    
    flash('Ordre de travail supprimé avec succès', 'success')
    return redirect(url_for('liste_ordres'))

# Routes pour la gestion des utilisateurs (table user)
@app.route('/utilisateurs')
@login_required
@perm_required('utilisateurs')
def liste_utilisateurs():
    cursor = mysql.connection.cursor()
    
    # Récupérer les filtres de la requête GET
    username = request.args.get('username', '')
    type_user = request.args.get('type', '')
    connect = request.args.get('connect', '')
    
    # Construction de la requête SQL avec filtres
    sql_query = "SELECT * FROM user WHERE 1=1"
    params = []
    
    if username:
        sql_query += " AND username LIKE %s"
        params.append(f'%{username}%')
    
    if type_user:
        sql_query += " AND type = %s"
        params.append(type_user)
    
    if connect:
        sql_query += " AND connect = %s"
        params.append(connect)
    
    sql_query += " ORDER BY id"
    
    # Exécuter la requête
    if params:
        cursor.execute(sql_query, tuple(params))
    else:
        cursor.execute(sql_query)
        
    utilisateurs = cursor.fetchall()
    cursor.close()
    
    return render_template('utilisateurs/liste.html', utilisateurs=utilisateurs)

@app.route('/utilisateurs/ajouter', methods=['GET', 'POST'])
@login_required
@admin_required
def ajouter_utilisateur():
    if request.method == 'POST':
        # Récupération des données du formulaire
        username = request.form['username']
        password = request.form['password']
        type_user = request.form['type']
        connect = request.form.get('connect', 'non')  # Si la case n'est pas cochée, utiliser 'non'
        
        # Hasher le mot de passe avec SHA-1
        import hashlib
        hashed_password = hashlib.sha1(password.encode()).hexdigest()
        
        cursor = mysql.connection.cursor()
        
        # Vérifier si le nom d'utilisateur existe déjà
        cursor.execute("SELECT id FROM user WHERE username = %s", (username,))
        existing = cursor.fetchone()
        
        if existing:
            flash('Un utilisateur avec ce nom existe déjà', 'danger')
            return redirect(url_for('ajouter_utilisateur'))
        
        # Fetch notification defaults for assigned role
        cursor.execute("SELECT notif_config_default FROM roles WHERE name = %s LIMIT 1", (type_user,))
        role_data = cursor.fetchone()
        notif_config_str = role_data['notif_config_default'] if role_data else None

        # Insertion dans la base de données
        cursor.execute("""
            INSERT INTO user (username, password, type, connect, notif_config)
            VALUES (%s, %s, %s, %s, %s)
        """, (username, hashed_password, type_user, connect, notif_config_str))
        
        mysql.connection.commit()
        cursor.close()
        
        flash('Utilisateur ajouté avec succès', 'success')
        return redirect(url_for('liste_utilisateurs'))
    
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT name, is_builtin FROM roles ORDER BY name")
    roles = cursor.fetchall()
    cursor.close()
    return render_template('utilisateurs/ajouter.html', roles=roles)

@app.route('/utilisateurs/voir/<int:id>')
@login_required
@admin_required
def voir_utilisateur(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM user WHERE id = %s", (id,))
    utilisateur = cursor.fetchone()
    cursor.close()
    if not utilisateur:
        flash('Utilisateur non trouvé', 'danger')
        return redirect(url_for('liste_utilisateurs'))
    # Parser notif_config
    notif_parsed = {}
    if utilisateur.get('notif_config'):
        try: notif_parsed = json.loads(utilisateur['notif_config'])
        except: pass
    utilisateur = dict(utilisateur)
    utilisateur['notif_config_parsed'] = notif_parsed
    return render_template('utilisateurs/voir.html', utilisateur=utilisateur)

@app.route('/utilisateurs/modifier/<int:id>', methods=['GET', 'POST'])
@login_required
@admin_required
def modifier_utilisateur(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM user WHERE id = %s", (id,))
    utilisateur = cursor.fetchone()
    if not utilisateur:
        cursor.close()
        flash('Utilisateur non trouvé', 'danger')
        return redirect(url_for('liste_utilisateurs'))

    # S'assurer que la colonne notif_config existe
    try:
        cursor.execute("ALTER TABLE user ADD COLUMN IF NOT EXISTS notif_config TEXT DEFAULT NULL")
        mysql.connection.commit()
    except Exception:
        pass

    if request.method == 'POST':
        username   = request.form['username']
        password   = request.form.get('password', '')
        type_user  = request.form['type']
        connect    = request.form.get('connect', 'non')

        # Notifications cochees
        notif_keys = ['nouvelle_intervention','intervention_urgente','intervention_traitee',
                      'stock_alerte','maintenance_preventive','ordre_travail']
        notif_config = {k: ('1' if request.form.get('notif_' + k) else '0') for k in notif_keys}

        cursor.execute("SELECT id FROM user WHERE username = %s AND id != %s", (username, id))
        if cursor.fetchone():
            flash('Un autre utilisateur avec ce nom existe déjà', 'danger')
            return redirect(url_for('modifier_utilisateur', id=id))

        if password:
            hashed = hashlib.sha1(password.encode()).hexdigest()
            cursor.execute("""
                UPDATE user SET username=%s, password=%s, type=%s, connect=%s, notif_config=%s WHERE id=%s
            """, (username, hashed, type_user, connect, json.dumps(notif_config), id))
        else:
            cursor.execute("""
                UPDATE user SET username=%s, type=%s, connect=%s, notif_config=%s WHERE id=%s
            """, (username, type_user, connect, json.dumps(notif_config), id))

        mysql.connection.commit()
        cursor.close()
        flash('Utilisateur mis à jour avec succès', 'success')
        return redirect(url_for('voir_utilisateur', id=id))

    cursor.close()
    # Parser notif_config existant
    notif_config = {}
    if utilisateur.get('notif_config'):
        try: notif_config = json.loads(utilisateur['notif_config'])
        except: pass

    # Fetch roles dynamically
    cursor_roles = mysql.connection.cursor()
    cursor_roles.execute("SELECT name, is_builtin FROM roles ORDER BY name")
    roles = cursor_roles.fetchall()
    cursor_roles.close()

    return render_template('utilisateurs/modifier.html', utilisateur=utilisateur, notif_config=notif_config, roles=roles)

@app.route('/utilisateurs/supprimer/<int:id>')
@login_required
@admin_required
def supprimer_utilisateur(id):
    cursor = mysql.connection.cursor()
    
    # Vérifier si l'utilisateur existe
    cursor.execute("SELECT * FROM user WHERE id = %s", (id,))
    utilisateur = cursor.fetchone()
    
    if not utilisateur:
        cursor.close()
        flash('Utilisateur non trouvé', 'danger')
        return redirect(url_for('liste_utilisateurs'))
    
    # Supprimer l'utilisateur
    cursor.execute("DELETE FROM user WHERE id = %s", (id,))
    mysql.connection.commit()
    cursor.close()
    
    flash('Utilisateur supprimé avec succès', 'success')
    return redirect(url_for('liste_utilisateurs'))

# Routes pour la gestion des rôles (Role_Manager)
@app.route('/roles')
@login_required
@perm_required('roles')
def liste_roles():
    cursor = mysql.connection.cursor()
    try:
        cursor.execute("""
            SELECT r.*, COUNT(u.id) as user_count 
            FROM roles r 
            LEFT JOIN user u ON u.type = r.name 
            GROUP BY r.id 
            ORDER BY r.name
        """)
        roles = cursor.fetchall()
        cursor.close()
    except Exception as e:
        roles = []
        try: cursor.close()
        except: pass
        flash("La table des rôles n'est pas encore initialisée. Veuillez exécuter la migration.", "info")
    return render_template('roles/liste.html', roles=roles)

@app.route('/roles/ajouter', methods=['GET', 'POST'])
@login_required
@superadmin_required
def ajouter_role():
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id, name FROM roles ORDER BY name")
    all_roles = cursor.fetchall()
    cursor.close()

    source_role = None
    source_id = request.args.get('source_id')
    if source_id:
        try:
            cursor = mysql.connection.cursor()
            cursor.execute("SELECT * FROM roles WHERE id = %s LIMIT 1", (source_id,))
            source_role = cursor.fetchone()
            cursor.close()
            if source_role:
                source_role = dict(source_role)
                try:
                    source_role['notif_defaults_parsed'] = json.loads(source_role.get('notif_config_default') or '{}')
                except:
                    source_role['notif_defaults_parsed'] = {}
        except:
            pass

    if request.method == 'POST':
        name = request.form.get('name', '').strip()
        description = request.form.get('description', '').strip()
        color = request.form.get('color', '#6366f1').strip()
        icon = request.form.get('icon', 'fa-user-tag').strip()

        # Validation
        if not name:
            flash("Le nom du rôle ne peut pas être vide.", "danger")
            return render_template('roles/ajouter.html', all_roles=all_roles, source_role=source_role)
        if len(name) > 50:
            flash("Le nom du rôle ne peut pas dépasser 50 caractères.", "danger")
            return render_template('roles/ajouter.html', all_roles=all_roles, source_role=source_role)

        # Doublon case-insensitive check
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT id FROM roles WHERE LOWER(name) = LOWER(%s) LIMIT 1", (name,))
        if cursor.fetchone():
            cursor.close()
            flash("Un rôle portant ce nom existe déjà.", "danger")
            return render_template('roles/ajouter.html', all_roles=all_roles, source_role=source_role)

        # Collecter les permissions
        perms_data = {}
        for key in PERMISSION_KEYS:
            perms_data[key] = 1 if request.form.get(key) else 0

        # Collecter les notifications
        notif_data = {}
        for key in NOTIF_KEYS:
            notif_data[key] = '1' if request.form.get('notif_' + key) else '0'

        columns = ['name', 'description', 'is_builtin', 'color', 'icon', 'notif_config_default'] + list(perms_data.keys())
        values = [name, description, 0, color, icon, json.dumps(notif_data)] + list(perms_data.values())

        placeholders = ", ".join(["%s"] * len(columns))
        cols_str = ", ".join([f"`{c}`" for c in columns])
        sql = f"INSERT INTO roles ({cols_str}) VALUES ({placeholders})"

        try:
            cursor.execute(sql, tuple(values))
            mysql.connection.commit()
            cursor.close()
            flash("Rôle créé avec succès !", "success")
            
            # Récupérer l'ID pour rediriger
            cursor = mysql.connection.cursor()
            cursor.execute("SELECT id FROM roles WHERE name = %s LIMIT 1", (name,))
            new_role = cursor.fetchone()
            cursor.close()
            
            return redirect(url_for('voir_role', id=new_role['id']))
        except Exception as e:
            mysql.connection.rollback()
            cursor.close()
            app.logger.error(f"Error creating role: {e}")
            flash("Une erreur est survenue lors de la création du rôle.", "danger")
            return render_template('roles/ajouter.html', all_roles=all_roles, source_role=source_role)

    return render_template('roles/ajouter.html', all_roles=all_roles, source_role=source_role)

@app.route('/roles/<int:id>')
@login_required
@superadmin_required
def voir_role(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM roles WHERE id = %s LIMIT 1", (id,))
    role = cursor.fetchone()
    if not role:
        cursor.close()
        flash("Rôle introuvable.", "danger")
        return redirect(url_for('liste_roles'))

    cursor.execute("SELECT COUNT(*) as user_count FROM user WHERE type = %s", (role['name'],))
    user_count = cursor.fetchone()['user_count']
    cursor.close()

    # Parser notifications
    notif_config = {}
    if role.get('notif_config_default'):
        try:
            notif_config = json.loads(role['notif_config_default'])
        except:
            pass

    return render_template('roles/voir.html', role=role, user_count=user_count, notif_config=notif_config)

@app.route('/roles/<int:id>/modifier', methods=['GET', 'POST'])
@login_required
@superadmin_required
def modifier_role(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM roles WHERE id = %s LIMIT 1", (id,))
    role = cursor.fetchone()
    if not role:
        cursor.close()
        flash("Rôle introuvable.", "danger")
        return redirect(url_for('liste_roles'))

    cursor.execute("SELECT COUNT(*) as user_count FROM user WHERE type = %s", (role['name'],))
    user_count = cursor.fetchone()['user_count']
    cursor.close()

    notif_config = {}
    if role.get('notif_config_default'):
        try:
            notif_config = json.loads(role['notif_config_default'])
        except:
            pass

    if request.method == 'POST':
        name = request.form.get('name', '').strip()
        description = request.form.get('description', '').strip()
        color = request.form.get('color', '#6366f1').strip()
        icon = request.form.get('icon', 'fa-user-tag').strip()

        # Validation
        if not name:
            flash("Le nom du rôle ne peut pas être vide.", "danger")
            return render_template('roles/modifier.html', role=role, user_count=user_count, notif_config=notif_config)
        if len(name) > 50:
            flash("Le nom du rôle ne peut pas dépasser 50 caractères.", "danger")
            return render_template('roles/modifier.html', role=role, user_count=user_count, notif_config=notif_config)

        # Doublon case-insensitive check
        cursor = mysql.connection.cursor()
        cursor.execute("SELECT id FROM roles WHERE LOWER(name) = LOWER(%s) AND id != %s LIMIT 1", (name, id))
        if cursor.fetchone():
            cursor.close()
            flash("Un autre rôle portant ce nom existe déjà.", "danger")
            return render_template('roles/modifier.html', role=role, user_count=user_count, notif_config=notif_config)

        # Collecter les permissions
        perms_data = {}
        for key in PERMISSION_KEYS:
            if role['name'] == 'SUPER ADMIN':
                perms_data[key] = 1
            else:
                perms_data[key] = 1 if request.form.get(key) else 0

        # Collecter les notifications
        notif_data = {}
        for key in NOTIF_KEYS:
            notif_data[key] = '1' if request.form.get('notif_' + key) else '0'

        name_changed = (role['name'] != name)

        set_clauses = [
            "`name` = %s", "`description` = %s", "`color` = %s", "`icon` = %s", "`notif_config_default` = %s"
        ]
        params = [name, description, color, icon, json.dumps(notif_data)]

        for key in PERMISSION_KEYS:
            set_clauses.append(f"`{key}` = %s")
            params.append(perms_data[key])

        params.append(id)
        sql = f"UPDATE roles SET {', '.join(set_clauses)} WHERE id = %s"

        try:
            cursor.execute(sql, tuple(params))
            if name_changed:
                cursor.execute("UPDATE user SET type = %s WHERE type = %s", (name, role['name']))
            mysql.connection.commit()
            cursor.close()
            flash("Rôle mis à jour avec succès !", "success")
            return redirect(url_for('voir_role', id=id))
        except Exception as e:
            mysql.connection.rollback()
            cursor.close()
            app.logger.error(f"Error updating role: {e}")
            flash("Une erreur est survenue lors de la mise à jour du rôle.", "danger")
            return render_template('roles/modifier.html', role=role, user_count=user_count, notif_config=notif_config)

    return render_template('roles/modifier.html', role=role, user_count=user_count, notif_config=notif_config)

@app.route('/roles/<int:id>/supprimer', methods=['POST'])
@login_required
@superadmin_required
def supprimer_role(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM roles WHERE id = %s LIMIT 1", (id,))
    role = cursor.fetchone()
    if not role:
        cursor.close()
        flash("Rôle introuvable.", "danger")
        return redirect(url_for('liste_roles'))

    # Guard 1: built-in roles cannot be deleted
    if role['is_builtin'] or role['name'] == 'SUPER ADMIN':
        cursor.close()
        flash("Les rôles intégrés ne peuvent pas être supprimés.", "danger")
        return redirect(url_for('liste_roles'))

    # Guard 2: assigned users check
    cursor.execute("SELECT COUNT(*) as user_count FROM user WHERE type = %s", (role['name'],))
    user_count = cursor.fetchone()['user_count']
    if user_count > 0:
        cursor.close()
        flash(f"Ce rôle est attribué à {user_count} utilisateur(s). Veuillez les réassigner avant la suppression.", "danger")
        return redirect(url_for('voir_role', id=id))

    try:
        cursor.execute("DELETE FROM roles WHERE id = %s", (id,))
        mysql.connection.commit()
        cursor.close()
        flash("Rôle supprimé avec succès !", "success")
    except Exception as e:
        mysql.connection.rollback()
        cursor.close()
        app.logger.error(f"Error deleting role: {e}")
        flash("Une erreur est survenue lors de la suppression du rôle.", "danger")

    return redirect(url_for('liste_roles'))

@app.route('/roles/<int:id>/copier')
@login_required
@superadmin_required
def copier_role(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT id FROM roles WHERE id = %s LIMIT 1", (id,))
    role = cursor.fetchone()
    cursor.close()
    if not role:
        flash("Rôle introuvable.", "danger")
        return redirect(url_for('liste_roles'))
    return redirect(url_for('ajouter_role', source_id=id))

@app.route('/utilisateurs/<int:id>/reset-notif', methods=['POST'])
@login_required
@admin_required
def reset_notif_utilisateur(id):
    cursor = mysql.connection.cursor()
    cursor.execute("SELECT * FROM user WHERE id = %s LIMIT 1", (id,))
    user = cursor.fetchone()
    if not user:
        cursor.close()
        flash("Utilisateur non trouvé.", "danger")
        return redirect(url_for('liste_utilisateurs'))

    # Charger la configuration par défaut du rôle
    cursor.execute("SELECT notif_config_default FROM roles WHERE name = %s LIMIT 1", (user['type'],))
    role = cursor.fetchone()
    
    if not role or not role.get('notif_config_default'):
        cursor.close()
        flash("Aucune préférence de notification par défaut configurée pour ce rôle.", "warning")
        return redirect(url_for('modifier_utilisateur', id=id))

    try:
        cursor.execute("UPDATE user SET notif_config = %s WHERE id = %s", (role['notif_config_default'], id))
        mysql.connection.commit()
        cursor.close()
        flash("Configuration des notifications réinitialisée aux valeurs par défaut du rôle.", "success")
    except Exception as e:
        mysql.connection.rollback()
        cursor.close()
        app.logger.error(f"Error resetting user notification defaults: {e}")
        flash("Une erreur est survenue lors de la réinitialisation.", "danger")

    return redirect(url_for('modifier_utilisateur', id=id))

# Routes pour le systu00e8me de suivi des actions
@app.route('/api/activities', methods=['POST'])
def add_activity():
    if 'user_id' not in session:
        return jsonify({'error': 'Non connecte'}), 401
    # Ru00e9cupu00e9rer les donnu00e9es JSON de la requête
    data = request.json
    
    # Vu00e9rifier que les donnu00e9es requises sont pru00e9sentes
    if not all(key in data for key in ['action', 'module', 'description']):
        return jsonify({'error': 'Donnu00e9es incomplu00e8tes'}), 400
    
    # Pru00e9parer les donnu00e9es pour l'insertion
    action = data['action']
    module = data['module']
    description = data['description']
    details = data.get('details', {})
    username = data.get('username', session.get('username', 'Utilisateur inconnu'))
    timestamp = data.get('timestamp', datetime.now().isoformat())
    
    # Cru00e9er la connexion u00e0 la base de donnu00e9es
    cursor = mysql.connection.cursor()
    
    try:
        # Vu00e9rifier si la table existe, sinon la cru00e9er
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS activities (
                id INT AUTO_INCREMENT PRIMARY KEY,
                timestamp DATETIME NOT NULL,
                username VARCHAR(100) NOT NULL,
                action VARCHAR(50) NOT NULL,
                module VARCHAR(50) NOT NULL,
                description TEXT NOT NULL,
                details JSON,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        mysql.connection.commit()
        
        # Insu00e9rer l'activitu00e9 dans la base de donnu00e9es
        cursor.execute("""
            INSERT INTO activities (timestamp, username, action, module, description, details)
            VALUES (%s, %s, %s, %s, %s, %s)
        """, (
            datetime.fromisoformat(timestamp.replace('Z', '+00:00')),
            username,
            action,
            module,
            description,
            json.dumps(details)
        ))
        mysql.connection.commit()
        
        # Ru00e9cupu00e9rer l'ID de l'activitu00e9 cru00e9u00e9e
        activity_id = cursor.lastrowid
        
        cursor.close()
        
        return jsonify({
            'success': True,
            'message': 'Activitu00e9 enregistru00e9e avec succu00e8s',
            'activity_id': activity_id
        }), 201
        
    except Exception as e:
        cursor.close()
        return jsonify({'error': str(e)}), 500

@app.route('/activites')
@login_required
@perm_required('activites')
def liste_activites():
    # Ru00e9cupu00e9rer les filtres de la requête GET
    username = request.args.get('username', '')
    module = request.args.get('module', '')
    action = request.args.get('action', '')
    date_debut = request.args.get('date_debut', '')
    date_fin = request.args.get('date_fin', '')
    
    # Construction de la requête SQL avec filtres
    sql_query = """
        SELECT * FROM activities
        WHERE 1=1
    """
    params = []
    
    if username:
        sql_query += " AND username LIKE %s"
        params.append(f'%{username}%')
    
    if module:
        sql_query += " AND module = %s"
        params.append(module)
    
    if action:
        sql_query += " AND action = %s"
        params.append(action)
    
    if date_debut:
        sql_query += " AND DATE(timestamp) >= %s"
        params.append(date_debut)
    
    if date_fin:
        sql_query += " AND DATE(timestamp) <= %s"
        params.append(date_fin)
    
    sql_query += " ORDER BY timestamp DESC LIMIT 1000"
    
    cursor = mysql.connection.cursor()
    
    try:
        # Vu00e9rifier si la table existe
        cursor.execute("""
            SELECT COUNT(*) as count FROM information_schema.tables 
            WHERE table_schema = %s AND table_name = 'activities'
        """, [app.config['MYSQL_DB']])
        table_exists = cursor.fetchone()['count'] > 0
        
        if not table_exists:
            # Cru00e9er la table si elle n'existe pas
            cursor.execute("""
                CREATE TABLE IF NOT EXISTS activities (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    timestamp DATETIME NOT NULL,
                    username VARCHAR(100) NOT NULL,
                    action VARCHAR(50) NOT NULL,
                    module VARCHAR(50) NOT NULL,
                    description TEXT NOT NULL,
                    details JSON,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            """)
            mysql.connection.commit()
            activites = []
        else:
            # Exu00e9cuter la requête avec les filtres
            if params:
                cursor.execute(sql_query, tuple(params))
            else:
                cursor.execute(sql_query)
            
            activites = cursor.fetchall()
        
        # Ru00e9cupu00e9rer les modules et actions disponibles pour les filtres
        if table_exists:
            cursor.execute("SELECT DISTINCT module FROM activities ORDER BY module")
            modules = cursor.fetchall()
            
            cursor.execute("SELECT DISTINCT action FROM activities ORDER BY action")
            actions = cursor.fetchall()
        else:
            modules = []
            actions = []
        
        cursor.close()
        
        return render_template('activites/liste.html', 
                               activites=activites, 
                               modules=modules, 
                               actions=actions)
        
    except Exception as e:
        cursor.close()
        flash(f'Erreur lors de la ru00e9cupu00e9ration des activitu00e9s: {str(e)}', 'danger')
        return redirect(url_for('dashboard'))

@app.route('/activites/voir/<int:id>')
@login_required
@role_required('SUPER ADMIN')
def voir_activite(id):
    cursor = mysql.connection.cursor()
    
    # Ru00e9cupu00e9rer l'activitu00e9
    cursor.execute("SELECT * FROM activities WHERE id = %s", [id])
    activite = cursor.fetchone()
    
    if not activite:
        cursor.close()
        flash('Activitu00e9 non trouvu00e9e', 'danger')
        return redirect(url_for('liste_activites'))
    
    cursor.close()
    
    return render_template('activites/voir.html', activite=activite)

# Gestion globale des erreurs pour eviter la deconnexion intempestive
@app.errorhandler(500)
def internal_error(e):
    import traceback
    print('ERREUR 500:', traceback.format_exc())
    try:
        mysql.connection.rollback()
    except:
        pass
    if 'user_id' in session:
        flash(f'Erreur serveur: {str(e)}', 'danger')
        return redirect(request.referrer or url_for('dashboard'))
    return redirect(url_for('login'))

# Lancement de l'application
if __name__ == '__main__':
    app.run(
        host='192.168.1.71',
        port=5050,
        debug=False,
        threaded=True
    )
