from django.shortcuts import render
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate
from django.http import HttpResponse, FileResponse, JsonResponse
from .forms import formConnexion, formSignup, FileUploadForm, FileEditForm, PasswordResetForm, SetPasswordForm, UserEditForm, NoteForm
from django.contrib.auth.decorators import login_required
from django.http import FileResponse, HttpResponseForbidden, Http404
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import ProtectedFile, UserFile, UserNote
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
import django
import os
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
import json
import os
from django.conf import settings
import mimetypes
from django.core.paginator import Paginator
from django.contrib import messages
from pathlib import Path
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.utils.encoding import force_bytes, force_str
import re

"""def login_view(request):
    form = formConnexion(request.POST or None)

    if request.method == 'POST':
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(request, username=username, password=password)
            if user is not None:
                login(request, user)
                return redirect('index')
            else:
                form.add_error(None, "Nom d'utilisateur ou mot de passe faux")
    return render(request, 'login.html', {'form':form})

def signup_view(request):
    form = formSignup(request.POST or None)

    if request.method == 'POST':
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect('index')
    return render(request, 'signup.html',{'form':form})
"""

def log_connection(request, page):
    print("Connection")
    return redirect('index')

def get_files(user=None):
    """
    Retourne les fichiers disponibles, triés par propriétaire
    Cette fonction a été optimisée pour réduire le temps de chargement
    """
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    uploads_dir = os.path.join(BASE_DIR, 'uploads')
    
    # Créer le dossier uploads s'il n'existe pas
    if not os.path.exists(uploads_dir):
        os.makedirs(uploads_dir)
    
    # Import pour la normalisation Unicode
    import unicodedata
    import re
    from pathlib import Path
    
    # Liste tous les fichiers physiques en une seule fois pour éviter les accès répétés au disque
    all_files = []
    for f in os.listdir(uploads_dir):
        if os.path.isfile(os.path.join(uploads_dir, f)) and f != 'files.json':
            all_files.append(f)
    
    # Initialisation des résultats
    result = {}
    
    if user and user.is_authenticated:
        try:
            # Utilisation de values_list pour optimiser la requête à la BD
            # Cette opération est plus efficace car elle ne récupère que les noms de fichiers
            user_files = list(UserFile.objects.filter(user=user).values_list('filename', flat=True))
            no_owner_files = list(UserFile.objects.filter(user=None).values_list('filename', flat=True))
            
            # Nous n'avons pas besoin de charger les fichiers des autres utilisateurs
            # sauf si c'est un administrateur qui a besoin de tout voir
            if user.is_staff:
                other_user_files = list(UserFile.objects.exclude(user=user).exclude(user=None).values_list('filename', flat=True))
            else:
                other_user_files = []
            
            # Fichiers qui existent physiquement mais pas dans le modèle
            model_files = set(user_files) | set(no_owner_files) | set(other_user_files)
            unknown_files = [f for f in all_files if f not in model_files]
            
            # Utilisation de bulk_create pour créer plusieurs objets en une seule requête
            if unknown_files:
                UserFile.objects.bulk_create([
                    UserFile(filename=f, user=None)
                    for f in unknown_files
                ])
                no_owner_files.extend(unknown_files)
            
            # Construction du résultat
            result = {
                'user_files': user_files,
                'no_owner_files': no_owner_files
            }
            
            # Ajout des fichiers des autres utilisateurs seulement si c'est un administrateur
            if user.is_staff:
                result['other_user_files'] = other_user_files
            
        except Exception as e:
            import traceback
            print(f"Erreur dans get_files: {str(e)}")
            print(traceback.format_exc())
            # En cas d'erreur, considérer tous les fichiers comme sans propriétaire
            result = {'no_owner_files': all_files}
    else:
        # Pour les utilisateurs non connectés, afficher tous les fichiers publics
        result = {'all_files': all_files}
    
    return result

def get_files_fallback(user=None):
    """
    Version de secours de get_files qui ne dépend pas de la base de données
    À utiliser si la table UserFile n'existe pas encore
    """
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    uploads_dir = os.path.join(BASE_DIR, 'uploads')
    
    # Créer le dossier uploads s'il n'existe pas
    if not os.path.exists(uploads_dir):
        os.makedirs(uploads_dir)
        # Définir les permissions du dossier
        try:
            import stat
            os.chmod(uploads_dir, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH)  # 775 permissions
        except Exception as e:
            print(f"Erreur lors de la définition des permissions du dossier: {str(e)}")
    
    # Liste tous les fichiers physiques
    all_files = []
    try:
        all_files = [f for f in os.listdir(uploads_dir) if os.path.isfile(os.path.join(uploads_dir, f)) and f != 'files.json']
        
        # Vérifier et corriger les permissions des fichiers
        for f in all_files:
            file_path = os.path.join(uploads_dir, f)
            if not os.access(file_path, os.R_OK):
                try:
                    import stat
                    os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH)  # 664 permissions
                    print(f"Permissions du fichier corrigées: {file_path}")
                except Exception as e:
                    print(f"Impossible de modifier les permissions: {str(e)}")
    except Exception as e:
        print(f"Erreur lors de la lecture du dossier uploads: {str(e)}")
    
    # Version simplifiée qui considère tous les fichiers comme sans propriétaire
    if user and user.is_authenticated:
        return {'user_files': [], 'no_owner_files': all_files, 'other_user_files': []}
    else:
        return {'all_files': all_files}

def index(request):
    host = request.get_host()
    if host == "benigne.dev":
        return render(request, "index.html")
    elif host == "perso.benigne.dev":
        if request.user.is_authenticated:
            return redirect('files')
        else:
            print("Not authenticated")
            return redirect('/login/')
    return render(request, "index.html")


def login(request):
    """
    Fonction de connexion des utilisateurs
    Cette fonction a été optimisée pour améliorer les performances
    """
    # Vérifier si l'utilisateur est déjà connecté
    if request.user.is_authenticated:
        return redirect('/')
    
    # Récupérer le paramètre next s'il existe
    next_url = request.GET.get('next', '')
    redirect_message = ""
    
    # Interpréter le paramètre next pour afficher un message approprié
    if next_url:
        if 'files/' in next_url:
            redirect_message = "Veuillez vous connecter pour accéder à vos fichiers."
        elif 'video/' in next_url:
            redirect_message = "Veuillez vous connecter pour accéder aux vidéos."
        elif 'notes/' in next_url:
            redirect_message = "Veuillez vous connecter pour accéder à vos notes."
        else:
            redirect_message = "Veuillez vous connecter pour accéder à cette page."
    
    # Initialiser le formulaire pour GET
    form = formConnexion()
    
    # Traitement du formulaire pour POST
    if request.method == 'POST':
        form = formConnexion(request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            
            # Cas particulier : 'guest' est géré différemment
            if username == 'guest':
                form.add_error(None, "Nom d'utilisateur ou mot de passe faux")
            else:
                password = form.cleaned_data.get('password')
                
                # Authentification via Django
                user = authenticate(request, username=username, password=password)
                
                if user is not None:
                    # Connexion réussie
                    django.contrib.auth.login(request, user)
                    
                    # Précharger certaines données pour accélérer l'accès à la page suivante
                    if 'files/' in request.GET.get('next', ''):
                        try:
                            # Pré-chargement asynchrone des fichiers utilisateur
                            # Cela permet de réduire le temps de chargement de la page files
                            user_files = list(UserFile.objects.filter(user=user).values_list('filename', flat=True))
                        except:
                            pass
                      # Redirection vers la page demandée ou la page d'accueil
                    return redirect(request.GET.get('next', '/'))
                else:
                    # Échec de l'authentification
                    form.add_error("password", "Nom d'utilisateur ou mot de passe faux")
    
    # Rendu du template avec le formulaire
    context = {
        'form': form, 
        'current_form': 'login',
        'redirect_message': redirect_message,
        'next_url': next_url
    }
    return render(request, "authentication.html", context)


def logout(request):
    django.contrib.auth.logout(request)
    return redirect('index')


def register(request):
    if request.method == 'POST':
        form = formSignup(request.POST)
        if form.is_valid():
            # Vérifier si l'email existe déjà
            email = form.cleaned_data.get('email')
            if User.objects.filter(email=email).exists():
                form.add_error('email', "Cette adresse email est déjà utilisée. Veuillez en choisir une autre.")
                # Afficher le formulaire avec l'erreur
                return render(request, "authentication.html", {'form': form, 'current_form': 'register'})
                
            try:
                user = form.save()
                
                # Envoi d'un email de confirmation
                subject = 'Bienvenue sur benigne.dev !'
                
                try:
                    html_message = render_to_string('emails/welcome_email.html', {
                        'username': user.username,
                    })
                    plain_message = strip_tags(html_message)
                    from_email = settings.DEFAULT_FROM_EMAIL
                    to_email = user.email
                    
                    send_mail(
                        subject,
                        plain_message,
                        from_email,
                        [to_email],
                        html_message=html_message,
                        fail_silently=False,  # Modifié: Ne pas ignorer les erreurs d'envoi
                    )
                    print(f"Email de bienvenue envoyé à {to_email}")
                except Exception as e:
                    # Amélioration de la journalisation des erreurs
                    print(f"Erreur lors de l'envoi de l'email: {str(e)}")
                    print(f"Type d'erreur: {type(e).__name__}")
                    import traceback
                    print(f"Traceback: {traceback.format_exc()}")
                    # Ajouter un message d'erreur mais continuer le processus
                    messages.warning(request, "Votre compte a été créé mais nous n'avons pas pu vous envoyer l'email de bienvenue. Vous pouvez quand même vous connecter.")
                
                # Rediriger même si l'email échoue
                return redirect('login')
            except Exception as e:
                print(f"Erreur lors de la création du compte : {str(e)}")
                form.add_error(None, "Une erreur s'est produite lors de la création du compte. Veuillez réessayer.")
        else:
            # Log les erreurs pour le débogage
            print(f"Erreurs de formulaire: {form.errors}")
    else:
        form = formSignup()
    
    # Afficher le formulaire avec les erreurs si nécessaire
    return render(request, "authentication.html", {'form': form, 'current_form': 'register'})


def reset_password(request):
    if request.method == 'POST':
        form = PasswordResetForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            try:
                user = User.objects.get(email=email)
                
                # Générer le token unique pour la réinitialisation
                token = default_token_generator.make_token(user)
                uid = urlsafe_base64_encode(force_bytes(user.pk))
                
                # Créer l'URL de réinitialisation
                reset_url = f"https://benigne.dev/reset_password_confirm/{uid}/{token}/"
                
                # Préparer et envoyer l'email
                subject = "Réinitialisation de votre mot de passe sur benigne.dev"
                html_message = render_to_string('emails/password_reset_email.html', {
                    'username': user.username,
                    'reset_url': reset_url,
                })
                plain_message = strip_tags(html_message)
                from_email = settings.DEFAULT_FROM_EMAIL
                
                try:
                    send_mail(
                        subject,
                        plain_message,
                        from_email,
                        [email],
                        html_message=html_message,
                        fail_silently=False,
                    )
                    print(f"Email de réinitialisation envoyé à {email}")
                    return render(request, "authentication.html", {
                        'form': form,
                        'success_message': "Un email avec les instructions de réinitialisation a été envoyé à votre adresse.",
                        'current_form': 'reset'
                    })
                except Exception as e:
                    print(f"Erreur lors de l'envoi de l'email : {str(e)}")
                    form.add_error(None, "Erreur lors de l'envoi de l'email. Veuillez réessayer plus tard.")
            except User.DoesNotExist:
                # Cette erreur ne devrait pas se produire normalement car le formulaire vérifie déjà l'existence de l'email
                form.add_error('email', "Aucun compte n'est associé à cette adresse e-mail.")
            except Exception as e:
                print(f"Erreur inattendue lors de la réinitialisation du mot de passe : {str(e)}")
                form.add_error(None, "Une erreur inattendue s'est produite. Veuillez réessayer plus tard.")
    else:
        form = PasswordResetForm()
    
    return render(request, "authentication.html", {'form': form, 'current_form': 'reset'})


def reset_password_confirm(request, uidb64, token):
    try:
        # Décoder l'identifiant utilisateur
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
        
        # Vérifier la validité du token
        if not default_token_generator.check_token(user, token):
            return render(request, "registration/password_reset_confirm.html", {
                'validlink': False
            })
        
        if request.method == 'POST':
            form = SetPasswordForm(request.POST)
            if form.is_valid():
                # Mettre à jour le mot de passe
                user.set_password(form.cleaned_data['new_password1'])
                user.save()
                
                # Rediriger vers la page de connexion avec un message de succès
                messages.success(request, "Votre mot de passe a été modifié avec succès. Vous pouvez maintenant vous connecter.")
                return redirect('login')
        else:
            form = SetPasswordForm()
        
        return render(request, "registration/password_reset_confirm.html", {
            'form': form,
            'validlink': True
        })
    
    except (TypeError, ValueError, OverflowError, User.DoesNotExist):
        return render(request, "registration/password_reset_confirm.html", {
            'validlink': False
        })

@login_required
def files(request):
    """
    Vue pour afficher et uploader des fichiers
    Cette fonction a été optimisée pour améliorer les performances de chargement
    """
    # Vérifier si l'utilisateur est le compte invité
    is_guest = request.user.username == 'guest'
    
    # Initialiser le contexte et le formulaire
    context = {'is_guest': is_guest}
    
    # Préparation du formulaire avec traitement conditionnel pour les invités
    form = FileUploadForm()
    
    # Récupérer les fichiers tôt pour optimiser le chargement initial
    try:
        files_data = get_files(request.user)
    except Exception as e:
        import traceback
        print(f"Erreur lors de la récupération des fichiers: {str(e)}")
        print(traceback.format_exc())
        files_data = get_files_fallback(request.user)
    
    # Traitement du formulaire uniquement pour les utilisateurs non-invités et en cas de POST
    if request.method == 'POST' and not is_guest:
        form = FileUploadForm(request.POST, request.FILES)
        if form.is_valid():
            # Itérer sur chaque fichier uploadé
            for uploaded_file in request.FILES.getlist('file'):
                file_visibility = request.POST.get('file_visibility', 'private')
                ip_address = get_client_ip(request)
                BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                uploads_dir = os.path.join(BASE_DIR, 'uploads')
                
                # Normalisation et sanitisation du nom de fichier pour éviter les problèmes d'encodage
                import unicodedata
                import re
                from pathlib import Path
                
                # Préserver l'extension de fichier originale
                original_filename = uploaded_file.name
                file_name, file_ext = os.path.splitext(original_filename)
                
                # Remplacer les caractères problématiques par leur équivalent ASCII
                # Translittération des caractères accentués
                normalized = unicodedata.normalize('NFKD', file_name)
                # Supprimer les caractères diacritiques (accents, etc.)
                ascii_name = ''.join([c for c in normalized if not unicodedata.combining(c)])
                # Supprimer tout caractère non-alphanumérique
                safe_name = re.sub(r'[^a-zA-Z0-9_\-\.]', '_', ascii_name)
                
                # Reconstruire le nom de fichier avec l'extension
                safe_filename = safe_name + file_ext
                # Garder le nom original pour l'affichage
                display_filename = original_filename
                
                # Utiliser pathlib avec le nom sécurisé
                uploads_path = Path(uploads_dir)
                file_path = uploads_path / safe_filename
                
                try:
                    # Ouvrir le fichier avec le nom sécurisé
                    with open(os.path.join(uploads_dir, safe_filename), 'wb') as destination:
                        for chunk in uploaded_file.chunks():
                            destination.write(chunk)
                    
                    os.chmod(os.path.join(uploads_dir, safe_filename), 0o664)
                    file_size = os.path.getsize(os.path.join(uploads_dir, safe_filename))
                    user = request.user if file_visibility == 'private' else None
                    
                    # Stocker à la fois le nom d'affichage et le nom de fichier réel dans la base de données
                    file_obj = UserFile.objects.create(
                        filename=safe_filename,  # Nom réel sur le disque
                        display_name=display_filename,  # Nom original avec accents
                        user=user,
                        ip_address=ip_address,
                        file_size=file_size
                    )
                    
                    print(f"Fichier uploadé avec succès: {display_filename} (stocké comme {safe_filename})")
                    
                except Exception as e:
                    import traceback
                    print(f"Erreur lors de l'upload: {str(e)}")
                    print(traceback.format_exc())
            
            files_data = get_files(request.user)
            return redirect('files')
    
    # Préparation du contexte pour le template
    context.update({
        'form': form,
        'files_data': files_data,
    })
    
    return render(request, "files.html", context)

def get_client_ip(request):
    """
    Fonction utilitaire pour obtenir l'adresse IP du client
    """
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0].strip()
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip

@login_required
def file_admin(request):
    """
    Vue d'administration des fichiers, accessible uniquement aux administrateurs
    """
    # Vérifier si l'utilisateur est administrateur
    if not request.user.is_staff:
        return HttpResponseForbidden("Vous n'avez pas les permissions nécessaires pour accéder à cette page.")
    
    # Paramètres de pagination et de tri
    page = request.GET.get('page', 1)
    sort_by = request.GET.get('sort', '-upload_date')  # Par défaut, tri par date d'upload (plus récent d'abord)
    
    # Champs de tri valides pour éviter les injections SQL
    valid_sort_fields = ['filename', '-filename', 'upload_date', '-upload_date', 'file_size', 
                        '-file_size', 'user__username', '-user__username', 'ip_address', '-ip_address']
    
    if sort_by not in valid_sort_fields:
        sort_by = '-upload_date'  # Valeur par défaut si le champ de tri n'est pas valide
        
    # Récupérer tous les fichiers avec le tri spécifié
    all_files = UserFile.objects.all().order_by(sort_by)
    
    # Mettre à jour les tailles de fichiers si nécessaire
    for file in all_files:
        if file.file_size is None:
            try:
                file_path = file.get_file_path()
                if file_path.exists():
                    file.file_size = file_path.stat().st_size
                    file.save(update_fields=['file_size'])
            except Exception as e:
                print(f"Erreur lors de la mise à jour de la taille du fichier {file.filename}: {str(e)}")
    
    # Filtrage par recherche si spécifié
    search_query = request.GET.get('search', '')
    if search_query:
        all_files = all_files.filter(filename__icontains=search_query)
    
    # Pagination des résultats (100 fichiers par page)
    paginator = Paginator(all_files, 100)  # 100 fichiers par page
    
    try:
        files_page = paginator.page(page)
    except:
        # Si le numéro de page est invalide, afficher la première page
        files_page = paginator.page(1)
    
    context = {
        'files': files_page,
        'current_sort': sort_by,
        'search_query': search_query,
        'page_obj': files_page,  # Pour les contrôles de pagination
        'is_paginated': True if paginator.num_pages > 1 else False,
        'paginator': paginator
    }
    
    return render(request, "files/file_admin.html", context)

@login_required
def delete_file(request, filename):
    """
    Vue pour supprimer un fichier
    Accessible uniquement aux administrateurs
    """
    # Vérifier si l'utilisateur est administrateur
    if not request.user.is_staff:
        return HttpResponseForbidden("Vous n'avez pas les permissions nécessaires pour effectuer cette action.")
    
    # Normalisation du nom de fichier pour gérer correctement les caractères Unicode
    import unicodedata
    safe_filename = unicodedata.normalize('NFC', filename)
    
    # Récupérer le fichier - utiliser filter() au lieu de get() pour gérer les doublons
    try:
        # Trouver tous les fichiers avec le même nom
        file_objs = UserFile.objects.filter(filename=safe_filename)
        
        if not file_objs.exists():
            messages.error(request, f"Le fichier {safe_filename} n'existe pas dans la base de données.")
            return redirect('file_admin')
        
        # Supprimer le fichier physique (une seule fois)
        file_path = file_objs.first().get_file_path()
        if file_path.exists():
            try:
                file_path.unlink()
            except Exception as e:
                messages.warning(request, f"Impossible de supprimer le fichier physique: {str(e)}")
        
        # Compter combien de fichiers seront supprimés
        file_count = file_objs.count()
        
        # Supprimer toutes les entrées dans la base de données
        file_objs.delete()
        
        # Message de succès
        if file_count > 1:
            messages.success(request, f"Le fichier {safe_filename} a été supprimé avec succès ({file_count} entrées dupliquées nettoyées).")
        else:
            messages.success(request, f"Le fichier {safe_filename} a été supprimé avec succès.")
            
    except Exception as e:
        # En cas d'erreur
        messages.error(request, f"Erreur lors de la suppression du fichier {safe_filename}: {str(e)}")
    
    # Rediriger vers la page d'administration
    return redirect('file_admin')

def guest(request):
    u = User.objects.get(username="guest")
    u.set_password("votre_mot_de_passe_complexe")
    u.save()
    if not request.user.is_authenticated:
        # Authentifier directement avec les identifiants fixes
        user = authenticate(request, username='guest', password='votre_mot_de_passe_complexe')
        django.contrib.auth.login(request, user)
        request.session.set_expiry(0)
    return redirect('/')

def custom_404(request, exception):
    return render(request, "404.html", status=404)

@login_required(login_url='/login/')
def serve_file(request, filename):
    """
    Vue sécurisée pour servir les fichiers uploadés
    Vérifie les permissions avant de servir le fichier
    """
    # Récupérer le fichier depuis la base de données
    try:
        # Si le nom contient des caractères spéciaux, il s'agit probablement du display_name
        user_file = UserFile.objects.filter(display_name=filename).first()
        
        # Si non trouvé avec display_name, essayer avec filename
        if not user_file:
            user_file = UserFile.objects.filter(filename=filename).first()
            
        if not user_file:
            raise Http404("Le fichier demandé n'existe pas dans la base de données.")
            
        # Utiliser le nom de fichier stocké sur le disque
        safe_filename = user_file.filename
        
        # Vérifier si l'utilisateur a accès au fichier
        if user_file.user and user_file.user != request.user and not request.user.is_superuser:
            return HttpResponseForbidden("Vous n'avez pas la permission d'accéder à ce fichier.")
            
        # Vérifier si le fichier existe sur le disque
        BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        file_path = os.path.join(BASE_DIR, 'uploads', safe_filename)
        
        if not os.path.exists(file_path) or not os.path.isfile(file_path):
            raise Http404("Le fichier demandé n'existe pas sur le disque.")
        
        # Vérifier que le fichier est lisible
        if not os.access(file_path, os.R_OK):
            # Si le fichier n'est pas lisible, essayer de corriger les permissions
            try:
                import stat
                os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH)  # 664 permissions
                print(f"Permissions du fichier corrigées: {file_path}")
            except Exception as perm_err:
                print(f"Impossible de modifier les permissions: {str(perm_err)}")
                return HttpResponseForbidden(f"Le fichier existe mais n'est pas accessible. Veuillez contacter l'administrateur.")
        
        # Déterminer le type MIME du fichier
        content_type, encoding = mimetypes.guess_type(file_path)
        if content_type is None:
            content_type = 'application/octet-stream'
        
        # Nom à afficher dans le navigateur (nom original avec accents si disponible)
        content_filename = user_file.display_name or safe_filename
        
        # Ouvrir et servir le fichier
        try:
            response = FileResponse(open(file_path, 'rb'), content_type=content_type)
            response['Content-Disposition'] = f'inline; filename="{content_filename}"'
            return response
        except Exception as e:
            import traceback
            print(f"Erreur lors de l'accès au fichier: {str(e)}")
            print(traceback.format_exc())
            return HttpResponseForbidden(f"Erreur lors de l'accès au fichier: {str(e)}")
            
    except Exception as global_err:
        import traceback
        print(f"Erreur globale dans serve_file: {str(global_err)}")
        print(traceback.format_exc())
        return HttpResponseForbidden(f"Erreur lors de l'accès au fichier: {str(global_err)}")

@login_required
def edit_file(request, filename):
    """
    Vue pour éditer le propriétaire et la visibilité d'un fichier
    """
    # Vérifier si l'utilisateur est administrateur
    if not request.user.is_staff:
        return HttpResponseForbidden("Vous n'avez pas les permissions nécessaires pour accéder à cette page.")
    
    # Récupérer le fichier
    file = get_object_or_404(UserFile, filename=filename)
    
    if request.method == 'POST':
        form = FileEditForm(request.POST)
        if form.is_valid():
            # Récupérer les données du formulaire
            new_user = form.cleaned_data.get('user')
            visibility = form.cleaned_data.get('visibility')
            
            # Mettre à jour le propriétaire en fonction de la visibilité
            if visibility == 'private' and new_user:
                file.user = new_user
            elif visibility == 'public':
                file.user = None
            
            # Sauvegarder les modifications
            file.save()
            
            # Message de succès
            messages.success(request, f"Le fichier {filename} a été modifié avec succès.")
            
            # Rediriger vers la page d'administration
            return redirect('file_admin')
    else:
        # Déterminer la visibilité actuelle
        initial_visibility = 'private' if file.user else 'public'
        
        # Préremplir le formulaire avec les données actuelles
        form = FileEditForm(initial={
            'user': file.user,
            'visibility': initial_visibility
        })
    
    context = {
        'form': form,
        'file': file,
        'title': 'Modifier le fichier',
    }
    
    return render(request, 'files/edit_file.html', context)

@login_required
def user_admin(request):
    """
    Vue d'administration des utilisateurs, accessible uniquement aux administrateurs
    Maintenant accessible via /files/users/
    """
    # Vérifier si l'utilisateur est administrateur
    if not request.user.is_staff:
        return HttpResponseForbidden("Vous n'avez pas les permissions nécessaires pour accéder à cette page.")
    
    # Paramètres de pagination et de tri
    page = request.GET.get('page', 1)
    sort_by = request.GET.get('sort', 'username')  # Par défaut, tri par nom d'utilisateur
    
    # Champs de tri valides pour éviter les injections SQL
    valid_sort_fields = ['username', '-username', 'email', '-email', 'date_joined', '-date_joined', 
                         'last_login', '-last_login', 'is_staff', '-is_staff', 'is_active', '-is_active']
    
    if sort_by not in valid_sort_fields:
        sort_by = 'username'  # Valeur par défaut si le champ de tri n'est pas valide
        
    # Récupérer tous les utilisateurs avec le tri spécifié
    all_users = User.objects.all().order_by(sort_by)
    
    # Filtrage par recherche si spécifié
    search_query = request.GET.get('search', '')
    if search_query:
        all_users = all_users.filter(username__icontains=search_query) | \
                   all_users.filter(email__icontains=search_query)
    
    # Pagination des résultats (20 utilisateurs par page)
    paginator = Paginator(all_users, 20)
    
    try:
        users_page = paginator.page(page)
    except:
        # Si le numéro de page est invalide, afficher la première page
        users_page = paginator.page(1)
    
    context = {
        'users': users_page,
        'current_sort': sort_by,
        'search_query': search_query,
        'page_obj': users_page,  # Pour les contrôles de pagination
        'is_paginated': True if paginator.num_pages > 1 else False,
        'paginator': paginator
    }
    
    return render(request, "users/user_admin.html", context)

@login_required
def edit_user(request, user_id):
    """
    Vue pour modifier les droits d'un utilisateur
    Maintenant accessible via /files/users/edit/<user_id>/
    """
    # Vérifier si l'utilisateur est administrateur
    if not request.user.is_staff:
        return HttpResponseForbidden("Vous n'avez pas les permissions nécessaires pour accéder à cette page.")
    
    # Récupérer l'utilisateur à modifier
    user_to_edit = get_object_or_404(User, id=user_id)
    
    # Empêcher la modification de son propre compte
    if user_to_edit == request.user:
        messages.error(request, "Vous ne pouvez pas modifier votre propre compte via cette interface.")
        return redirect('user_admin')
    
    if request.method == 'POST':
        form = UserEditForm(request.POST)
        if form.is_valid():
            # Mettre à jour les permissions de l'utilisateur
            user_to_edit.is_staff = form.cleaned_data.get('is_staff', False)
            user_to_edit.is_active = form.cleaned_data.get('is_active', True)
            user_to_edit.save()
            
            # Message de succès
            messages.success(request, f"Les droits de l'utilisateur {user_to_edit.username} ont été modifiés avec succès.")
            
            # Rediriger vers la page d'administration des utilisateurs
            return redirect('user_admin')
    else:
        # Préremplir le formulaire avec les données actuelles
        form = UserEditForm(user=user_to_edit)
    
    context = {
        'form': form,
        'user_to_edit': user_to_edit,
        'title': "Modifier les droits de l'utilisateur",
    }
    
    return render(request, 'users/edit_user.html', context)

@login_required
def delete_user(request, user_id):
    """
    Vue pour supprimer un utilisateur
    Maintenant accessible via /files/users/delete/<user_id>/
    """
    # Vérifier si l'utilisateur est administrateur
    if not request.user.is_staff:
        return HttpResponseForbidden("Vous n'avez pas les permissions nécessaires pour effectuer cette action.")
    
    # Récupérer l'utilisateur à supprimer
    user_to_delete = get_object_or_404(User, id=user_id)
    
    # Empêcher la suppression de son propre compte
    if user_to_delete == request.user:
        messages.error(request, "Vous ne pouvez pas supprimer votre propre compte.")
        return redirect('user_admin')
    
    # Récupérer le nom d'utilisateur avant la suppression
    username = user_to_delete.username
    
    try:
        # Option 1: Supprimer complètement l'utilisateur et ses fichiers associés
        if request.GET.get('delete_files', 'false').lower() == 'true':
            # Récupérer tous les fichiers de l'utilisateur
            user_files = UserFile.objects.filter(user=user_to_delete)
            
            # Supprimer les fichiers physiques
            for file in user_files:
                file_path = file.get_file_path()
                if file_path.exists():
                    try:
                        file_path.unlink()
                    except Exception as e:
                        messages.warning(request, f"Impossible de supprimer le fichier {file.filename}: {str(e)}")
            
            # Supprimer l'utilisateur (cascade delete pour les fichiers en base de données)
            user_to_delete.delete()
            messages.success(request, f"L'utilisateur {username} et tous ses fichiers ont été supprimés avec succès.")
        else:
            # Option 2: Rendre les fichiers publics avant de supprimer l'utilisateur
            UserFile.objects.filter(user=user_to_delete).update(user=None)
            
            # Supprimer l'utilisateur
            user_to_delete.delete()
            messages.success(request, f"L'utilisateur {username} a été supprimé avec succès. Ses fichiers sont maintenant publics.")
    
    except Exception as e:
        messages.error(request, f"Erreur lors de la suppression de l'utilisateur {username}: {str(e)}")
    
    return redirect('user_admin')

@login_required
def video(request):
    """
    Vue pour la page vidéo permettant de lire des fichiers MP4 avec des sous-titres SRT
    """
    # Initialiser le contexte
    context = {}
    
    # Récupérer les fichiers disponibles
    try:
        files_data = get_files(request.user)
    except Exception as e:
        import traceback
        print(f"Erreur lors de la récupération des fichiers: {str(e)}")
        print(traceback.format_exc())
        files_data = get_files_fallback(request.user)
    
    # Filtrer pour ne garder que les fichiers MP4 et SRT
    mp4_files = []
    srt_files = []
    
    for file_type, files_list in files_data.items():
        for file in files_list:
            # Convertir le nom de fichier en minuscules pour la comparaison d'extension
            lower_filename = file.lower()
            if lower_filename.endswith('.mp4'):
                mp4_files.append(file)
            elif lower_filename.endswith('.vtt'):
                srt_files.append(file)
    
    # Récupérer les paramètres de l'URL (si une vidéo ou un fichier de sous-titres est spécifié)
    selected_video = request.GET.get('video', '')
    selected_subtitle = request.GET.get('subtitle', '')
    
    context.update({
        'mp4_files': mp4_files,
        'srt_files': srt_files,
        'selected_video': selected_video,
        'selected_subtitle': selected_subtitle,
    })
    
    return render(request, "video.html", context)

@login_required(login_url='/login/')
def serve_subtitle(request, filename):
    """
    Vue pour servir les fichiers de sous-titres SRT
    """
    if not filename.lower().endswith('.vtt'):
        return HttpResponseForbidden("Ce point d'accès est uniquement pour les fichiers de sous-titres SRT.")
    
    # Utiliser la fonction serve_file existante pour les vérifications d'accès et de sécurité
    response = serve_file(request, filename)
    
    # Si la réponse est valide (pas une erreur), modifier les en-têtes pour les sous-titres
    if isinstance(response, FileResponse):
        response['Content-Type'] = 'text/plain; charset=utf-8'
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
    
    return response

@login_required(login_url='/login/')
def view_note(request):
    """
    Vue pour afficher et éditer la note de l'utilisateur
    """
    # Récupérer ou créer la note de l'utilisateur
    note, created = UserNote.objects.get_or_create(
        user=request.user,
        defaults={'content': '', 'title': 'Ma note'}
    )
    
    context = {
        'note': note,
    }
    
    return render(request, 'notes/note.html', context)

@login_required(login_url='/login/')
def save_note(request):
    """
    Vue pour sauvegarder la note via AJAX
    """
    if request.method == 'POST' and request.is_ajax():
        content = request.POST.get('content', '')
        
        # Récupérer ou créer la note
        note, created = UserNote.objects.get_or_create(
            user=request.user,
            defaults={'content': content, 'title': 'Ma note'}
        )
        
        # Mettre à jour le contenu
        note.content = content
        note.save()
        
        return JsonResponse({'success': True})
    
    return JsonResponse({'success': False})

@login_required(login_url='/login/')
def view_note(request):
    """
    Vue pour afficher et éditer la note de l'utilisateur
    """
    # Récupérer ou créer la note de l'utilisateur
    note, created = UserNote.objects.get_or_create(
        user=request.user,
        defaults={'content': '', 'title': 'Ma note'}
    )
    
    context = {
        'note': note,
    }
    
    return render(request, 'notes/note.html', context)

@login_required(login_url='/login/')
def save_note(request):
    """
    Vue pour sauvegarder la note via AJAX
    """
    if request.method == 'POST' and request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        content = request.POST.get('content', '')
        
        # Récupérer ou créer la note
        note, created = UserNote.objects.get_or_create(
            user=request.user,
            defaults={'content': content, 'title': 'Ma note'}
        )
        
        # Mettre à jour le contenu
        note.content = content
        note.save()
        
        return JsonResponse({'success': True})
    
    return JsonResponse({'success': False})

@login_required(login_url='/login/')
def serve_pawn_file(request, filename):
    """
    Vue pour servir les fichiers spécifiques à la page pawn
    """
    # Cette fonction reprend la logique de serve_file
    return serve_file(request, filename)

