from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.utils import secure_filename as werkzeug_secure_filename
import unicodedata
from flask import Flask, render_template, request, redirect, url_for, flash, session, send_file, send_from_directory, current_app, make_response, jsonify, abort, Blueprint
from flask_login import LoginManager, current_user, login_required, login_user, logout_user, user_logged_in, user_logged_out
from cas_server import cas_bp, admin_required, count_logged_in_users
from models import db, User, Document, DocumentVersion
import os
import pandas as pd
from io import StringIO
from datetime import datetime
import mistune
import frontmatter
from bs4 import BeautifulSoup
import re
import time
import hashlib
from flask_compress import Compress
from flask_sqlalchemy import SQLAlchemy
from flask_session import Session
import logging
from sqlalchemy import text
import subprocess
import openpyxl
import tempfile
import shutil
import threading
import mimetypes
import platform
from sumy.parsers.plaintext import PlaintextParser
from sumy.nlp.tokenizers import Tokenizer
from sumy.summarizers.lex_rank import LexRankSummarizer
import nltk
nltk.download('punkt')

# Initialisation de l'application Flask
app = Flask(__name__, static_folder='static', static_url_path='/static')
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
#app.config['SERVER_NAME'] = '10.15.61.100'

app.config['PREFERRED_URL_SCHEME'] = 'https'
app.config['APPLICATION_ROOT'] = '/'
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "fallback-secret-key")
app.config.update(
    ENV='production',
    SESSION_COOKIE_NAME='session',
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax',
    PREFERRED_URL_SCHEME='https'
)

app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+mysqlconnector://bdc_user:Password*2025@localhost/knowledge_base"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_ECHO"] = True
app.config['UPLOAD_FOLDER'] = '/var/sftp/uploads'
app.config['MAX_CONTENT_LENGTH'] = 200 * 1024 * 1024  # 200 Mo
app.config['ALLOWED_EXTENSIONS'] = {'txt', 'pdf', 'docx', 'pptx', 'xlsx', 'md', 'html', 'htm', 'csv', 'json', 'xml'}

#app.config['SESSION_TYPE'] = 'sqlalchemy'
#app.config['SESSION_SQLALCHEMY'] = db
app.config['SESSION_TYPE'] = 'filesystem'# Stocker les sessions sur le disque
Session(app)

# Configuration du logging
handler = logging.FileHandler('/home/hns/appliBDC/knowledge_base.log')
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
app.logger.addHandler(handler)
app.logger.setLevel(logging.DEBUG)

# Initialisation de la base de données
db.init_app(app)

# Initialisation de Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)

# Déclaration des Blueprints
main = Blueprint("main", __name__)

# Mappage des types de fichiers et de leurs logos
FILE_TYPE_ICONS = {
    'txt': 'txt-icon.png',
    'pdf': 'pdf-icon.png',
    'docx': 'docx-icon.png',
    'pptx': 'pptx-icon.png',
    'xlsx': 'xlsx-icon.png',
    'html': 'html-icon.png',
    'htm': 'html-icon.png',
    'md': 'md-icon.png',
    'csv': 'csv-icon.png',
    'json': 'json-icon.png',
    'xml': 'xml-icon.png',
}

# Mappage des types MIME
MIME_TYPES = {
    'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'odt': 'application/vnd.oasis.opendocument.text',
    'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'ods': 'application/vnd.oasis.opendocument.spreadsheet',
    'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'odp': 'application/vnd.oasis.opendocument.presentation',
    'pdf': 'application/pdf',
    'txt': 'text/plain',
    'md': 'text/markdown',
    'html': 'text/html',
    'htm': 'text/html',
    'csv': 'text/csv',
    'json': 'application/json',
    'xml': 'application/xml',
}

import platform
import subprocess
import os

# Mappage des applications par défaut pour Linux (Ubuntu)
DEFAULT_APPS_LINUX = {
    'docx': 'libreoffice',
    'pptx': 'libreoffice',
    'xlsx': 'libreoffice',
    'pdf': 'xdg-open',
    'txt': 'xdg-open',
    'md': 'code',
    'html': 'xdg-open',
    'htm': 'xdg-open',
    'csv': 'libreoffice',
    'json': 'code',
    'xml': 'code',
}

# Mappage des applications par défaut pour Windows
DEFAULT_APPS_WINDOWS = {
    'docx': 'start',
    'pptx': 'start',
    'xlsx': 'start',
    'pdf': 'start',
    'txt': 'notepad',
    'md': 'code',
    'html': 'start',
    'htm': 'start',
    'csv': 'start',
    'json': 'code',
    'xml': 'code',
}

def count_logged_in_users():
    return sum(1 for session in Session.query.filter_by(is_authenticated=True).all())

from cas_server import count_logged_in_users

@app.context_processor
def inject_logged_in_users():
    return dict(logged_in_users=count_logged_in_users())

# Afficher la liste des utilisateurs
@main.route('/admin/users')
@login_required
@admin_required
def users_list():
    users = User.query.all()
    return render_template('users_list.html', users=users)

@main.route('/admin/disconnect_user/<int:user_id>', methods=['POST'])
@login_required
@admin_required
def disconnect_user(user_id):
    user = User.query.get_or_404(user_id)
    username = user.username

    # Trouver et supprimer la session de l'utilisateur
    active_sessions = get_active_sessions()
    for session_id, user_in_session in list(active_sessions.items()):
        if user_in_session == username:
            del active_sessions[session_id]
            break
    session['active_sessions'] = active_sessions

    flash(f"L'utilisateur {username} a été déconnecté.", "success")
    return redirect(url_for('main.admin'))

@app.after_request
def after_request(response):
    response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "0"
    return response


def get_default_apps():
    system = platform.system()
    if system == 'Linux':
        return DEFAULT_APPS_LINUX
    elif system == 'Windows':
        return DEFAULT_APPS_WINDOWS
    else:
        return DEFAULT_APPS_LINUX  # Fallback

def open_with_default_app(file_path, file_type):
    try:
        default_apps = get_default_apps()
        app = default_apps.get(file_type, None)

        if app is None:
            return False

        if platform.system() == 'Windows':
            if app == 'start':
                os.startfile(file_path)
            elif app == 'code':
                subprocess.Popen(['code', file_path])
            elif app == 'notepad':
                subprocess.Popen(['notepad', file_path])
            else:
                subprocess.Popen([app, file_path], shell=True)
        else:  # Linux
            if app == 'xdg-open':
                subprocess.Popen(['/usr/bin/xdg-open', file_path])  # Chemin absolu
            else:
                subprocess.Popen([app, file_path])
        return True
    except Exception as e:
        current_app.logger.error(f"Erreur lors de l'ouverture du fichier : {e}")
        return False

# DEFAULT_APPS = get_default_apps()

def secure_filename(filename):
    filename = unicodedata.normalize('NFKD', filename)
    filename = filename.encode('ascii', 'ignore').decode('ascii')
    filename = re.sub(r'[^\w\-_.() ]', '_', filename)
    filename = re.sub(r'[() ]', '_', filename)
    return werkzeug_secure_filename(filename)

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

def render_markdown(filepath):
    with open(filepath, 'r', encoding='utf-8') as f:
        content = f.read()
    return mistune.markdown(content)

def read_html_file(filepath):
    with open(filepath, 'r', encoding='utf-8') as f:
        return f.read()

def generate_toc(markdown_content):
    headers = re.findall(r'^(#{1,6})\s*(.*)', markdown_content, re.MULTILINE)
    toc = []
    for level, text in headers:
        indent = '  ' * (int(level) - 1)
        anchor = text.lower().replace(' ', '-').replace('.', '').replace(',', '').replace(';', '')
        toc.append(f"{indent}- [{text}](#{anchor})")
    return '\n'.join(toc) if toc else None

def sanitize_html(html_content):
    soup = BeautifulSoup(html_content, 'html.parser')
    for script in soup(["script", "iframe", "frame", "object", "embed"]):
        script.decompose()
    for tag in soup.find_all(True):
        for attr in ["onerror", "onload", "onclick", "style", "javascript"]:
            if attr in tag.attrs:
                del tag[attr]
    return str(soup)

def sync_documents_with_db():
    with app.app_context():
        documents_dir = app.config['UPLOAD_FOLDER']
        documents_in_db = Document.query.all()
        for doc in documents_in_db:
            if doc.filename:
                expected_path = os.path.join(documents_dir, doc.filename)
                if os.path.exists(expected_path):
                    if doc.file_path != expected_path:
                        current_app.logger.info(f"Updating file_path for document {doc.id}: {doc.file_path} -> {expected_path}")
                        doc.file_path = expected_path
                        db.session.commit()
                else:
                    current_app.logger.warning(f"File {doc.filename} not found in {documents_dir}")

def generate_file_hash(content):
    return hashlib.md5(content.encode('utf-8')).hexdigest()

def highlight_keywords(text, query):
    if not query:
        return text
    words = query.split()
    for word in words:
        text = re.sub(f'({re.escape(word)})', r'<span class="highlight">\1</span>', text, flags=re.IGNORECASE)
    return text

def _resolve_document_path(document):
    if document.file_path and os.path.exists(document.file_path):
        current_app.logger.info(f"File exists: {document.file_path}")
        return document.file_path
    current_app.logger.warning(f"File not found: {document.file_path}")
    return None

def generate_summary(content, sentences_count=2):
    """Génère un résumé intelligent à partir du contenu du document."""
    if not content:
        return None

    parser = PlaintextParser.from_string(content, Tokenizer("french"))
    summarizer = LexRankSummarizer()
    summary = summarizer(parser.document, sentences_count)

    return " ".join([str(sentence) for sentence in summary])


@main.route("/")
def index():
    return redirect(url_for('cas.login'))


@main.route('/favicon.ico')
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static'), 'favicon.ico', mimetype='image/vnd.microsoft.icon')

@main.route('/create-test-session')
def create_test_session():
    app.logger.info("Route /create-test-session appelée !")
    user = User.query.first()
    if user:
        app.logger.info(f"Utilisateur trouvé : {user.username}")
        login_user(user)
        return "Session créée avec succès ! Vérifie les cookies dans ton navigateur."
    return "Aucun utilisateur trouvé en base."

@app.context_processor
def inject_documents_count():
    from models import Document
    documents_count = Document.query.count()
    return dict(documents_count=documents_count)


@main.route('/document_search')
@login_required
def document_search():
    def generate_summary(content, max_words=30):
        if not content:
            return None
        words = content.split()[:max_words]
        summary = " ".join(words)
        if len(content.split()) > max_words:
            summary += "..."
        return summary

    def extract_content(file_path):
        import os
        file_ext = os.path.splitext(file_path)[1].lower()

        try:
            if file_ext == '.txt':
                with open(file_path, 'r', encoding='utf-8') as file:
                    return file.read()
            elif file_ext == '.pdf':
                from PyPDF2 import PdfReader
                reader = PdfReader(file_path)
                text = ""
                for page in reader.pages:
                    text += page.extract_text()
                return text
            elif file_ext == '.docx':
                from docx import Document
                doc = Document(file_path)
                return "\n".join([para.text for para in doc.paragraphs])
            elif file_ext in ['.pptx', '.ppt']:
                from pptx import Presentation
                prs = Presentation(file_path)
                text = ""
                for slide in prs.slides:
                    for shape in slide.shapes:
                        if hasattr(shape, "text"):
                            text += shape.text + "\n"
                return text
            else:
                print(f"Type de fichier non supporté: {file_ext}")
                return None
        except Exception as e:
            print(f"Erreur lors de l'extraction du contenu de {file_path}: {e}")
            return None

    try:
        query = request.args.get('q', '')
        file_type = request.args.get('type', '')
        page = request.args.get('page', 1, type=int)
        per_page = 6

        documents_query = Document.query

        if query:
            documents_query = documents_query.filter(
                Document.title.contains(query) |
                (Document.description.contains(query) if Document.description is not None else False) |
                (Document.content.contains(query) if Document.content is not None else False)
            )

        if file_type:
            documents_query = documents_query.filter(Document.file_type == file_type)

        documents = documents_query.order_by(Document.created_at.desc()).paginate(page=page, per_page=per_page, error_out=False)

        for doc in documents.items:
            # Extraire le contenu si nécessaire
            if not doc.content and doc.file_path:
                print(f"Extraction du contenu pour le document {doc.id}")
                doc.content = extract_content(doc.file_path)
                db.session.commit()

            # Générer une description si elle est vide et que le contenu existe
            if not doc.description and doc.content:
                print(f"Génération d'un résumé pour le document {doc.id}")
                doc.description = generate_summary(doc.content)
                doc.is_auto_description = True
                db.session.commit()
            elif not doc.description:
                doc.description = "Aucune description disponible"
                doc.is_auto_description = False
                db.session.commit()

            # Recherche de mots-clés
            doc.found_keywords = []
            if query.lower() in doc.title.lower():
                doc.found_keywords.append("Titre")
            if doc.description and query.lower() in doc.description.lower():
                doc.found_keywords.append("Description")
            if doc.content and query.lower() in doc.content.lower():
                doc.found_keywords.append("Contenu")
                index = doc.content.lower().find(query.lower())
                if index != -1:
                    start = max(0, index - 20)
                    end = min(len(doc.content), index + len(query) + 20)
                    doc.content_snippet = doc.content[start:end]
                    doc.content_snippet_highlighted = highlight_keywords(doc.content_snippet, query)
                else:
                    doc.content_snippet_highlighted = None

        file_types = db.session.query(Document.file_type.distinct()).filter(Document.file_type.isnot(None)).all()
        file_types = [ft[0] for ft in file_types]

        return render_template('search.html',
                             documents=documents,
                             user=current_user,
                             query=query,
                             file_types=file_types,
                             selected_type=file_type,
                             FILE_TYPE_ICONS=FILE_TYPE_ICONS,
                             highlight_keywords=highlight_keywords)
    except Exception as e:
        current_app.logger.error(f"Erreur dans document_search: {str(e)}")
        flash("Une erreur est survenue lors de la recherche", "error")
        return render_template('search.html',
                             documents=None,
                             user=current_user,
                             query=request.args.get('q', ''),
                             file_types=[],
                             selected_type='',
                             FILE_TYPE_ICONS=FILE_TYPE_ICONS,
                             highlight_keywords=highlight_keywords)


@main.route('/open_with_host/<int:document_id>')
def open_with_host(document_id):
    document = Document.query.get_or_404(document_id)
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], document.filename)
    abs_path = os.path.abspath(file_path)
    return jsonify({
        "sftp_path": f"sftp://sftp_hns@knowledge.local{abs_path.replace('/var/sftp', '')}",
        "protocol_link": f"knowledgebase://open?path={abs_path}"
    })

@main.route('/check_updates/<int:document_id>')
def check_updates(document_id):
    document = Document.query.get_or_404(document_id)
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], document.filename)
    last_modified = os.path.getmtime(file_path)
    return jsonify({"last_modified": last_modified})

@main.route('/update_document/<int:document_id>')
def update_document(document_id):
    document = Document.query.get_or_404(document_id)
    document.updated_at = datetime.utcnow()
    db.session.commit()
    return jsonify({"status": "success"})


from flask import send_file

@main.route('/open_with_app/<int:document_id>', methods=['GET'])
@login_required
def open_with_app(document_id):
    document = Document.query.get_or_404(document_id)
    file_path = document.file_path

    if not os.path.exists(file_path):
        return jsonify({"status": "error", "message": "Fichier introuvable"}), 404

    try:
        return send_file(file_path, as_attachment=True)
    except Exception as e:
        current_app.logger.error(f"Erreur open_with_app : {e}")
        return jsonify({"status": "error", "message": str(e)}), 500


@main.route('/upload', methods=['GET', 'POST'])
@login_required
@admin_required
def upload():
    if request.method == 'POST':
        # Vérifiez si le champ 'file' est présent dans la requête
        if 'file' not in request.files:
            flash('Aucun fichier sélectionné', 'error')
            return redirect(request.url)

        files = request.files.getlist('file')
        if not files or all(file.filename == '' for file in files):
            flash('Aucun fichier sélectionné', 'error')
            return redirect(request.url)

        for file in files:
            if file.filename == '':
                continue

            if file:
                filename = secure_filename(file.filename)
                filepath = os.path.join('/var/sftp/uploads', filename)

                # Vérifie que le répertoire d'upload existe
                os.makedirs(os.path.dirname(filepath), exist_ok=True)

                try:
                    file.save(filepath)

                    # Sauvegarder les informations du fichier dans la base de données
                    file_type = filename.split('.')[-1].lower()
                    document = Document(
                        title=filename,
                        description=request.form.get('description', ''),
                        file_type=file_type,
                        file_path=filepath,
                        filename=filename,
                        uploaded_by=current_user.username
                    )
                    db.session.add(document)
                    db.session.commit()

                except Exception as e:
                    db.session.rollback()
                    flash(f"Erreur lors de l'upload du fichier {filename}: {str(e)}", 'error')
                    return redirect(request.url)

        flash('Fichier(s) uploadé(s) avec succès!', 'success')
        return redirect(url_for('main.document_search'))

    return render_template('upload.html')


@main.route('/preview_upload', methods=['POST'])
@login_required
@admin_required
def preview_upload():
    if 'file' not in request.files:
        return jsonify({'error': 'Aucun fichier sélectionné'}), 400
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'Aucun fichier sélectionné'}), 400
    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        return jsonify({'filename': filename}), 200
    return jsonify({'error': 'Type de fichier non autorisé'}), 400

@main.route('/documents/<int:document_id>')
@login_required
def view_document(document_id):
    document = Document.query.get_or_404(document_id)
    if not os.path.exists(document.file_path):
        app.logger.error(f"Fichier introuvable : {document.file_path}")
        abort(404)
    if not os.access(document.file_path, os.R_OK):
        app.logger.error(f"Permission refusée pour le fichier : {document.file_path}")
        abort(403)
    return send_from_directory(os.path.dirname(document.file_path), os.path.basename(document.file_path), as_attachment=False)

@main.route('/admin')
@login_required
@admin_required
def admin():
    users = User.query.all()
    return render_template("admin.html", users=users)


@main.route('/edit_description/<int:document_id>', methods=['GET', 'POST'])
@login_required
def edit_description(document_id):
    document = Document.query.get_or_404(document_id)

    if request.method == 'POST':
        new_description = request.form.get('description', '')
        document.description = new_description
        document.is_auto_description = False
        db.session.commit()
        flash('Description mise à jour avec succès', 'success')
        return redirect(url_for('main.view_document', document_id=document_id))

    return render_template('edit_description.html', document=document)


@main.route('/admin/documents')
@login_required
@admin_required
def admin_documents():
    sort_by = request.args.get('sort_by', 'created_at')
    direction = request.args.get('direction', 'desc')

    # Déterminez l'ordre de tri
    if sort_by == 'title':
        if direction == 'asc':
            documents = Document.query.order_by(Document.title.asc()).all()
        else:
            documents = Document.query.order_by(Document.title.desc()).all()
    elif sort_by == 'file_type':
        if direction == 'asc':
            documents = Document.query.order_by(Document.file_type.asc()).all()
        else:
            documents = Document.query.order_by(Document.file_type.desc()).all()
    elif sort_by == 'uploaded_by':
        if direction == 'asc':
            documents = Document.query.order_by(Document.uploaded_by.asc()).all()
        else:
            documents = Document.query.order_by(Document.uploaded_by.desc()).all()
    else:  # Par défaut, tri par date
        if direction == 'asc':
            documents = Document.query.order_by(Document.created_at.asc()).all()
        else:
            documents = Document.query.order_by(Document.created_at.desc()).all()

    return render_template('admin_documents.html', documents=documents)


@main.route('/edit_document/<int:document_id>', methods=['GET', 'POST'])
@login_required
@admin_required
def edit_document(document_id):
    document = Document.query.get_or_404(document_id)

    if request.method == 'GET':
        content = ""
        if document.file_type in ['txt', 'md', 'html', 'json', 'xml', 'csv']:
            try:
                with open(document.file_path, 'r', encoding='utf-8') as f:
                    content = f.read()
            except Exception as e:
                flash(f"Impossible de lire le fichier: {str(e)}", "warning")
                content = ""

        return render_template("admin_edit_document.html",
                             document=document,
                             content=content,
                             is_editable=True)


@main.route('/check_file_modified/<int:document_id>')
@login_required
@admin_required
def check_file_modified(document_id):
    document = Document.query.get_or_404(document_id)
    last_modified = os.path.getmtime(document.file_path)
    return jsonify({"last_modified": last_modified})


@main.route('/save_document/<int:document_id>', methods=['POST'])
@login_required
@admin_required
def save_document(document_id):
    document = Document.query.get_or_404(document_id)
    success_message = None

    # Mise à jour du titre
    if 'title' in request.form:
        document.title = request.form['title']

    # Mise à jour de la description
    if 'description' in request.form:
        new_description = request.form['description']
        if new_description != document.description:
            document.description = new_description
            document.is_auto_description = False  # Indique que la description a été modifiée manuellement
            success_message = "Description mise à jour avec succès."

    # Pour les fichiers texte/Markdown/HTML/JSON/XML
    if document.file_type in ['txt', 'md', 'html', 'csv', 'json', 'xml'] and 'content' in request.form:
        try:
            # Sauvegarder une copie avant modification
            backup_path = f"{document.file_path}.bak"
            shutil.copy2(document.file_path, backup_path)

            # Écrire le nouveau contenu
            with open(document.file_path, 'w', encoding='utf-8') as f:
                f.write(request.form['content'])

            # Mettre à jour le contenu dans la base de données
            document.content = request.form['content']
            success_message = "Document mis à jour avec succès!"
        except PermissionError:
            flash("Vous n'avez pas la permission d'écrire dans ce fichier. Vérifiez les permissions du dossier.", "error")
            return redirect(url_for('main.edit_document', document_id=document_id))
        except Exception as e:
            flash(f"Erreur lors de la sauvegarde: {str(e)}", "error")
            if os.path.exists(backup_path):
                shutil.copy2(backup_path, document.file_path)
            return redirect(url_for('main.edit_document', document_id=document_id))

    # Pour les autres types de fichiers (upload de fichier)
    if 'file' in request.files and request.files['file'].filename:
        file = request.files['file']
        if file.filename:
            try:
                # Sauvegarder l'ancien fichier
                backup_path = f"{document.file_path}.bak"
                shutil.copy2(document.file_path, backup_path)

                # Déterminer le chemin final du fichier
                upload_folder = app.config['UPLOAD_FOLDER']
                new_filename = secure_filename(file.filename)

                # Si le nom du fichier a changé, mettre à jour les informations du document
                if new_filename != document.filename:
                    # Supprimer l'ancien fichier s'il existe
                    if os.path.exists(document.file_path):
                        os.remove(document.file_path)

                    # Mettre à jour les informations du document
                    document.filename = new_filename
                    document.file_type = os.path.splitext(new_filename)[1][1:].lower()

                # Définir le chemin final du fichier
                document.file_path = os.path.join(upload_folder, document.filename)

                # Enregistrer le nouveau fichier
                file.save(document.file_path)

                # Extraire le contenu du nouveau fichier
                document.content = extract_content(document.file_path)

                success_message = "Fichier mis à jour avec succès!"
            except PermissionError:
                flash("Vous n'avez pas la permission d'écrire dans ce dossier. Vérifiez les permissions de /var/sftp/uploads.", "error")
                return redirect(url_for('main.edit_document', document_id=document_id))
            except Exception as e:
                flash(f"Erreur lors de la mise à jour du fichier: {str(e)}", "error")
                if os.path.exists(backup_path):
                    shutil.copy2(backup_path, document.file_path)
                return redirect(url_for('main.edit_document', document_id=document_id))

    # Mettre à jour la date de modification
    document.updated_at = datetime.utcnow()
    db.session.commit()

    # Afficher un message de confirmation
    if success_message:
        flash(success_message, "success")

    # Rediriger vers la liste des documents côté administrateur
    return redirect(url_for('main.admin_documents'))

@main.route('/document_history/<int:document_id>')
@login_required
@admin_required
def document_history(document_id):
    if not session.get('is_admin'):
        flash("Accès réservé aux administrateurs.", "error")
        return redirect(url_for('main.document_search'))
    document = Document.query.get_or_404(document_id)
    versions = DocumentVersion.query.filter_by(document_id=document_id).order_by(DocumentVersion.created_at.desc()).all()
    return render_template('document_history.html', document=document, versions=versions)

@main.route('/restore_version/<int:version_id>')
@login_required
@admin_required
def restore_version(version_id):
    if not session.get('is_admin'):
        flash("Accès réservé aux administrateurs.", "error")
        return redirect(url_for('main.document_search'))
    version = DocumentVersion.query.get_or_404(version_id)
    document = Document.query.get_or_404(version.document_id)
    with open(document.file_path, 'w', encoding='utf-8') as f:
        f.write(version.content)
    document.content_hash = version.hash
    document.updated_at = datetime.utcnow()
    db.session.commit()
    flash("Version restaurée avec succès!", "success")
    return redirect(url_for('main.view_document', document_id=document.id))

@main.route('/delete_document/<int:document_id>', methods=['POST'])
@login_required
@admin_required
def delete_document(document_id):
    if not session.get('is_admin'):
        flash("Accès réservé aux administrateurs.", "error")
        return redirect(url_for('main.document_search'))
    document = Document.query.get_or_404(document_id)
    path = _resolve_document_path(document)
    if path and os.path.exists(path) and not os.path.isdir(path):
        os.remove(path)
    db.session.delete(document)
    db.session.commit()
    flash("Document supprimé avec succès!", "success")
    return redirect(url_for('main.admin_documents'))

@main.route('/download/<int:document_id>')
@login_required
def download_document(document_id):
    document = Document.query.get_or_404(document_id)
    if not os.path.exists(document.file_path):
        abort(404)

    response = make_response(send_from_directory(
        os.path.dirname(document.file_path),
        os.path.basename(document.file_path),
        as_attachment=True
    ))
    response.headers['Content-Type'] = MIME_TYPES.get(document.file_type, 'application/octet-stream')
    response.headers['Content-Disposition'] = f'attachment; filename="{document.filename}"'
    return response

@main.route('/open_pptx/<int:document_id>')
@login_required
def open_pptx(document_id):
    document = Document.query.get_or_404(document_id)
    if not os.path.exists(document.file_path):
        abort(404)

    if not open_with_default_app(document.file_path, document.file_type):
        return f"""
        <div class="alert alert-warning">
            Impossible d'ouvrir le fichier PowerPoint.
            <br><br>
            <a href="{url_for('main.download_document', document_id=document_id)}" class="btn btn-sm btn-primary mt-2">
                <i class="bi bi-download"></i> Télécharger le fichier
            </a>
            <br>
            <small class="text-muted">
                Ouvrez manuellement le fichier avec LibreOffice Impress après l'avoir téléchargé.
            </small>
        </div>
        """
    return "Le fichier PowerPoint a été ouvert avec LibreOffice Impress. Vous pouvez fermer cet onglet."

@login_required
@admin_required
@login_manager.user_loader
def load_user(user_id):
    if "username" in session and session.get("is_authenticated"):
        user = User.query.filter_by(username=session["username"]).first()
        if user:
            session["role"] = user.role
            session["is_admin"] = (user.role == "admin")
        return user
    return None

@main.route('/admin/import_users', methods=['GET', 'POST'])
@login_required
@admin_required
def import_users():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('Aucun fichier sélectionné', 'error')
            return redirect(url_for('main.admin'))

        file = request.files['file']
        if file.filename == '':
            flash('Aucun fichier sélectionné', 'error')
            return redirect(url_for('main.admin'))

        if file:
            try:
                if file.filename.endswith('.csv'):
                    df = pd.read_csv(StringIO(file.stream.read().decode("UTF8")), sep=';')
                elif file.filename.endswith('.xlsx'):
                    df = pd.read_excel(file.stream)
                else:
                    flash('Format de fichier non supporté', 'error')
                    return redirect(url_for('main.admin'))

                for _, row in df.iterrows():
                    username = row['Utilisateur']
                    email = row['Email']
                    role = row['Rôle']

                    if not User.query.filter_by(username=username).first():
                        new_user = User(username=username, email=email, role=role)
                        db.session.add(new_user)

                db.session.commit()
                flash(f"{len(df)} utilisateurs importés avec succès !", 'success')
            except Exception as e:
                db.session.rollback()
                flash(f"Erreur lors de l'import : {str(e)}", 'error')

        return redirect(url_for('main.admin'))

    return render_template('import_users.html')

@main.route('/admin/add_user', methods=['GET', 'POST'])
@login_required
@admin_required
def add_user():
    if request.method == 'POST':
        username = request.form['username']
        email = request.form['email']
        role = request.form['role']

        if User.query.filter_by(username=username).first():
            flash(f"L'utilisateur {username} existe déjà.", 'error')
            return redirect(url_for('main.add_user'))

        new_user = User(username=username, email=email, role=role)
        db.session.add(new_user)
        db.session.commit()

        flash(f"Utilisateur {username} ajouté avec succès !", 'success')
        return redirect(url_for('main.admin'))

    return render_template('add_user.html')

@main.route('/admin/edit_user/<int:user_id>', methods=['GET', 'POST'])
@login_required
@admin_required
def edit_user(user_id):
    user = User.query.get_or_404(user_id)
    if request.method == 'POST':
        user.role = request.form['role']
        db.session.commit()
        flash(f"Rôle de l'utilisateur {user.username} mis à jour avec succès!", "success")
        return redirect(url_for('main.admin'))

    return render_template('edit_user.html', user=user)

@main.route('/admin/delete_user/<int:user_id>', methods=['POST'])
@login_required
@admin_required
def delete_user(user_id):
    user = User.query.get_or_404(user_id)
    db.session.delete(user)
    db.session.commit()
    flash(f"Utilisateur {user.username} supprimé avec succès!", "success")
    return redirect(url_for('main.admin'))


# Enregistrement des Blueprints
app.register_blueprint(main, url_prefix="/")
app.register_blueprint(cas_bp, url_prefix='/cas')

# Création des tables (si nécessaire) et synchronisation des documents
with app.app_context():
    db.create_all()
    sync_documents_with_db()
