import json

from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth import logout, login, authenticate
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import JsonResponse, HttpResponse
from django.views.decorators.http import require_POST
from django.db.models import Count
from rest_framework import viewsets, status, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly, AllowAny
from rest_framework.pagination import PageNumberPagination
from django.shortcuts import render
from django.db.models import Q, Count, Avg, F
from django.utils import timezone
from django.core.cache import cache
from datetime import timedelta

from .models import (
    Language, Category, Exhibition, Artwork, ArtworkTranslation,
    Media, AudioGuide, Visit, Favorite, Comment, Statistics, User, Artwork, Artwork3DView, Artwork3DSession,
    VirtualRoom, ActivationToken
)
from .serializers import (
    LanguageSerializer, CategorySerializer, ExhibitionSerializer,
    ArtworkListSerializer, ArtworkDetailSerializer, MediaSerializer,
    AudioGuideSerializer, VisitSerializer, VisitCreateSerializer,
    FavoriteSerializer, FavoriteCreateSerializer, CommentSerializer,
    CommentCreateSerializer, CommentModerateSerializer, StatisticsSerializer,
    SearchSerializer, BulkArtworkUpdateSerializer, UserSerializer
)
from .permissions import IsContentModeratorOrAdmin, IsMuseumAdminOrReadOnly


# ==================== PAGINATION ====================
class StandardResultsSetPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    max_page_size = 100


# ==================== LANGUAGE VIEWSET ====================
class LanguageViewSet(viewsets.ReadOnlyModelViewSet):
    """API pour les langues disponibles"""
    queryset = Language.objects.filter(is_active=True)
    serializer_class = LanguageSerializer
    permission_classes = [AllowAny]
    pagination_class = None

    def list(self, request, *args, **kwargs):
        # Cache pour 1 heure
        cache_key = 'languages_list'
        cached_data = cache.get(cache_key)
        if cached_data:
            return Response(cached_data)

        response = super().list(request, *args, **kwargs)
        cache.set(cache_key, response.data, 3600)
        return response


# ==================== CATEGORY VIEWSET ====================
class CategoryViewSet(viewsets.ReadOnlyModelViewSet):
    """API pour les catégories"""
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    permission_classes = [AllowAny]
    lookup_field = 'slug'
    pagination_class = None

    @action(detail=True, methods=['get'])
    def artworks(self, request, slug=None):
        """Liste des œuvres d'une catégorie"""
        category = self.get_object()
        artworks = category.get_artworks()

        # Pagination
        paginator = StandardResultsSetPagination()
        page = paginator.paginate_queryset(artworks, request)

        serializer = ArtworkListSerializer(page, many=True,
                                           context={'request': request, 'language': request.GET.get('lang', 'fr')})
        return paginator.get_paginated_response(serializer.data)


# ==================== EXHIBITION VIEWSET ====================
class ExhibitionViewSet(viewsets.ReadOnlyModelViewSet):
    """API pour les expositions"""
    queryset = Exhibition.objects.filter(is_active=True)
    serializer_class = ExhibitionSerializer
    permission_classes = [AllowAny]
    lookup_field = 'slug'
    pagination_class = StandardResultsSetPagination

    def get_queryset(self):
        queryset = super().get_queryset()

        # Filtrer par statut
        status_param = self.request.query_params.get('status')
        if status_param == 'ongoing':
            today = timezone.now().date()
            queryset = queryset.filter(start_date__lte=today, end_date__gte=today)
        elif status_param == 'upcoming':
            today = timezone.now().date()
            queryset = queryset.filter(start_date__gt=today)
        elif status_param == 'past':
            today = timezone.now().date()
            queryset = queryset.filter(end_date__lt=today)

        return queryset.order_by('-start_date')

    @action(detail=True, methods=['get'])
    def artworks(self, request, slug=None):
        """Liste des œuvres d'une exposition"""
        exhibition = self.get_object()
        artworks = exhibition.get_artworks()

        paginator = StandardResultsSetPagination()
        page = paginator.paginate_queryset(artworks, request)

        serializer = ArtworkListSerializer(page, many=True,
                                           context={'request': request, 'language': request.GET.get('lang', 'fr')})
        return paginator.get_paginated_response(serializer.data)


# ==================== ARTWORK VIEWSET ====================
class ArtworkViewSet(viewsets.ModelViewSet):
    """API principale pour les œuvres"""
    queryset = Artwork.objects.filter(is_published=True)
    permission_classes = [IsAuthenticatedOrReadOnly]
    pagination_class = StandardResultsSetPagination
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['reference_code', 'translations__title', 'translations__description', 'translations__artist']
    ordering_fields = ['created_at', 'view_count', 'favorites_count']
    ordering = ['-created_at']

    def get_serializer_class(self):
        if self.action == 'list':
            return ArtworkListSerializer
        return ArtworkDetailSerializer

    def get_queryset(self):
        queryset = super().get_queryset()

        # Préchargement des relations
        queryset = queryset.select_related('category', 'created_by').prefetch_related(
            'translations', 'media', 'exhibitions'
        )

        # Filtres
        category = self.request.query_params.get('category')
        if category:
            queryset = queryset.filter(category__slug=category)

        exhibition = self.request.query_params.get('exhibition')
        if exhibition:
            queryset = queryset.filter(exhibitions__slug=exhibition)

        period = self.request.query_params.get('period')
        if period:
            queryset = queryset.filter(period__icontains=period)

        origin = self.request.query_params.get('origin')
        if origin:
            queryset = queryset.filter(origin__icontains=origin)

        is_featured = self.request.query_params.get('featured')
        if is_featured == 'true':
            queryset = queryset.filter(is_featured=True)

        return queryset

    def retrieve(self, request, *args, **kwargs):
        # Vérifier le cache
        artwork_id = kwargs.get('pk')
        lang = request.GET.get('lang', 'fr')
        cache_key = f'artwork_{artwork_id}_{lang}'

        cached_data = cache.get(cache_key)
        if cached_data:
            return Response(cached_data)

        instance = self.get_object()

        # Incrémenter le compteur de vues
        instance.view_count = F('view_count') + 1
        instance.save(update_fields=['view_count'])
        instance.refresh_from_db()

        serializer = self.get_serializer(instance)

        # Cache pour 1 heure
        cache.set(cache_key, serializer.data, 3600)

        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def featured(self, request):
        """Œuvres mises en avant"""
        featured = self.get_queryset().filter(is_featured=True)[:6]
        serializer = ArtworkListSerializer(featured, many=True,
                                           context={'request': request, 'language': request.GET.get('lang', 'fr')})
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def popular(self, request):
        """Œuvres les plus populaires"""
        popular = self.get_queryset().order_by('-view_count')[:10]
        serializer = ArtworkListSerializer(popular, many=True,
                                           context={'request': request, 'language': request.GET.get('lang', 'fr')})
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def recent(self, request):
        """Œuvres récemment ajoutées"""
        recent = self.get_queryset().order_by('-created_at')[:10]
        serializer = ArtworkListSerializer(recent, many=True,
                                           context={'request': request, 'language': request.GET.get('lang', 'fr')})
        return Response(serializer.data)

    @action(detail=True, methods=['get'])
    def translations(self, request, pk=None):
        """Récupère toutes les traductions d'une œuvre"""
        artwork = self.get_object()
        translations = artwork.translations.all()
        from .serializers import ArtworkTranslationSerializer
        serializer = ArtworkTranslationSerializer(translations, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['get'])
    def audio(self, request, pk=None):
        """Récupère l'audio guide"""
        artwork = self.get_object()
        lang = request.query_params.get('lang', 'fr')

        try:
            translation = artwork.translations.get(language=lang)
            audio_guide = translation.audio_guides.first()
            if audio_guide:
                serializer = AudioGuideSerializer(audio_guide, context={'request': request})
                return Response(serializer.data)
            return Response({'error': 'Audio guide non disponible'}, status=status.HTTP_404_NOT_FOUND)
        except ArtworkTranslation.DoesNotExist:
            return Response({'error': 'Traduction non disponible'}, status=status.HTTP_404_NOT_FOUND)

    @action(detail=True, methods=['get'])
    def related(self, request, pk=None):
        """Œuvres similaires"""
        artwork = self.get_object()
        related = Artwork.objects.filter(
            category=artwork.category,
            is_published=True
        ).exclude(id=artwork.id)[:6]

        serializer = ArtworkListSerializer(related, many=True,
                                           context={'request': request, 'language': request.GET.get('lang', 'fr')})
        return Response(serializer.data)

    @action(detail=False, methods=['post'])
    def search(self, request):
        """Recherche avancée"""
        search_serializer = SearchSerializer(data=request.data)
        search_serializer.is_valid(raise_exception=True)

        query = search_serializer.validated_data['query']
        lang = search_serializer.validated_data['language']

        artworks = self.get_queryset().filter(
            Q(translations__title__icontains=query, translations__language=lang) |
            Q(translations__description__icontains=query, translations__language=lang) |
            Q(translations__artist__icontains=query, translations__language=lang) |
            Q(reference_code__icontains=query)
        ).distinct()

        if 'category' in search_serializer.validated_data:
            artworks = artworks.filter(category__id=search_serializer.validated_data['category'])

        if 'period' in search_serializer.validated_data:
            artworks = artworks.filter(period__icontains=search_serializer.validated_data['period'])

        paginator = StandardResultsSetPagination()
        page = paginator.paginate_queryset(artworks, request)
        serializer = ArtworkListSerializer(page, many=True, context={'request': request, 'language': lang})
        return paginator.get_paginated_response(serializer.data)

    @action(detail=True, methods=['get'])
    def view_3d(self, request, pk=None):
        """Récupère les données de la vue 3D (version simplifiée)"""
        artwork = self.get_object()

        if not artwork.has_3d_view():
            return Response(
                {'error': 'Vue 3D non disponible pour cette œuvre'},
                status=status.HTTP_404_NOT_FOUND
            )

        data = {
            'panorama_url': request.build_absolute_uri(artwork.panorama_360.url),
            'initial_yaw': artwork.initial_yaw,
            'initial_pitch': artwork.initial_pitch,
            'initial_fov': artwork.initial_fov,
            'auto_rotate': artwork.auto_rotate,
            'auto_rotate_speed': artwork.auto_rotate_speed,
        }

        return Response(data)

    @action(detail=True, methods=['post'], url_path='3d-session/start')
    def start_3d_session(self, request, pk=None):
        """Démarre une session de visualisation 3D"""
        artwork = self.get_object()
        device_type = request.data.get('device_type', 'desktop')

        session = Artwork3DSession.objects.create(
            artwork=artwork,
            user=request.user if request.user.is_authenticated else None,
            session_key=request.session.session_key or str(uuid.uuid4()),
            device_type=device_type
        )

        return Response({
            'session_id': str(session.id),
            'started_at': session.started_at
        }, status=status.HTTP_201_CREATED)

    @action(detail=True, methods=['post'], url_path='3d-session/(?P<session_id>[^/.]+)/interact')
    def record_3d_interaction(self, request, pk=None, session_id=None):
        """Enregistre une interaction dans la session 3D"""
        try:
            session = Artwork3DSession.objects.get(id=session_id)
            hotspot_id = request.data.get('hotspot_id')
            interaction_type = request.data.get('interaction_type')

            session.record_interaction(hotspot_id, interaction_type)

            return Response({'status': 'recorded'})
        except Artwork3DSession.DoesNotExist:
            return Response(
                {'error': 'Session non trouvée'},
                status=status.HTTP_404_NOT_FOUND
            )

    @action(detail=True, methods=['post'], url_path='3d-session/(?P<session_id>[^/.]+)/end')
    def end_3d_session(self, request, pk=None, session_id=None):
        """Termine une session de visualisation 3D"""
        try:
            session = Artwork3DSession.objects.get(id=session_id)
            session.ended_at = timezone.now()

            # Calculer la durée
            if session.started_at:
                delta = session.ended_at - session.started_at
                session.duration = int(delta.total_seconds())

            session.save()

            return Response({
                'status': 'ended',
                'duration': session.duration,
                'interactions_count': session.interactions_count,
                'zoom_count': session.zoom_count
            })
        except Artwork3DSession.DoesNotExist:
            return Response(
                {'error': 'Session non trouvée'},
                status=status.HTTP_404_NOT_FOUND
            )

    @action(detail=True, methods=['get'])
    def has_3d_view(self, request, pk=None):
        """Vérifie si une œuvre a une vue 3D disponible"""
        artwork = self.get_object()
        has_3d = hasattr(artwork, 'view_3d') and artwork.view_3d.is_active

        return Response({
            'has_3d_view': has_3d,
            'artwork_id': str(artwork.id),
            'artwork_reference': artwork.reference_code
        })


# ==================== VISIT VIEWSET ====================
class VisitViewSet(viewsets.ModelViewSet):
    """API pour tracker les visites"""
    queryset = Visit.objects.all()
    serializer_class = VisitSerializer
    permission_classes = [AllowAny]
    pagination_class = StandardResultsSetPagination

    def get_serializer_class(self):
        if self.action == 'create':
            return VisitCreateSerializer
        return VisitSerializer

    def get_queryset(self):
        queryset = super().get_queryset()
        if self.request.user.is_authenticated:
            queryset = queryset.filter(user=self.request.user)
        return queryset.order_by('-visited_at')

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        visit = serializer.save()

        visit.artwork.view_count = F('view_count') + 1
        visit.artwork.save(update_fields=['view_count'])

        return Response(serializer.data, status=status.HTTP_201_CREATED)


# ==================== FAVORITE VIEWSET ====================
class FavoriteViewSet(viewsets.ModelViewSet):
    """API pour gérer les favoris"""
    queryset = Favorite.objects.all()
    serializer_class = FavoriteSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = StandardResultsSetPagination

    def get_serializer_class(self):
        if self.action == 'create':
            return FavoriteCreateSerializer
        return FavoriteSerializer

    def get_queryset(self):
        return Favorite.objects.filter(user=self.request.user).select_related('artwork').order_by('-created_at')

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        artwork = instance.artwork
        artwork.favorites_count = F('favorites_count') - 1
        artwork.save(update_fields=['favorites_count'])
        instance.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    @action(detail=False, methods=['post'])
    def toggle(self, request):
        """Toggle favori"""
        artwork_id = request.data.get('artwork')

        try:
            favorite = Favorite.objects.get(user=request.user, artwork_id=artwork_id)
            artwork = favorite.artwork
            artwork.favorites_count = F('favorites_count') - 1
            artwork.save(update_fields=['favorites_count'])
            favorite.delete()
            return Response({'status': 'removed'}, status=status.HTTP_200_OK)
        except Favorite.DoesNotExist:
            serializer = FavoriteCreateSerializer(data={'artwork': artwork_id}, context={'request': request})
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response({'status': 'added'}, status=status.HTTP_201_CREATED)


# ==================== COMMENT VIEWSET ====================
class CommentViewSet(viewsets.ModelViewSet):
    """API pour gérer les commentaires"""
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
    pagination_class = StandardResultsSetPagination

    def get_serializer_class(self):
        if self.action == 'create':
            return CommentCreateSerializer
        elif self.action == 'moderate':
            return CommentModerateSerializer
        return CommentSerializer

    def get_queryset(self):
        queryset = super().get_queryset()

        if not self.request.user.is_authenticated or self.request.user.role == 'visitor':
            queryset = queryset.filter(is_approved=True)

        artwork = self.request.query_params.get('artwork')
        if artwork:
            queryset = queryset.filter(artwork__id=artwork)

        return queryset.select_related('user', 'artwork').order_by('-created_at')

    @action(detail=True, methods=['post'], permission_classes=[IsAuthenticated, IsContentModeratorOrAdmin])
    def moderate(self, request, pk=None):
        """Modérer un commentaire"""
        comment = self.get_object()
        moderate_serializer = CommentModerateSerializer(data=request.data, context={'request': request})
        moderate_serializer.is_valid(raise_exception=True)

        action_type = moderate_serializer.validated_data['action']

        if action_type == 'approve':
            comment.is_approved = True
            comment.is_flagged = False
            comment.save()
            return Response({'status': 'approved'})
        elif action_type == 'reject':
            comment.delete()
            return Response({'status': 'rejected'}, status=status.HTTP_204_NO_CONTENT)
        elif action_type == 'flag':
            comment.is_flagged = True
            comment.save()
            return Response({'status': 'flagged'})


# ==================== STATISTICS VIEWSET ====================
class StatisticsViewSet(viewsets.ReadOnlyModelViewSet):
    """API pour les statistiques"""
    queryset = Statistics.objects.all()
    serializer_class = StatisticsSerializer
    permission_classes = [IsAuthenticated, IsContentModeratorOrAdmin]
    pagination_class = StandardResultsSetPagination

    @action(detail=False, methods=['get'])
    def dashboard(self, request):
        """Dashboard des statistiques"""
        today = timezone.now().date()
        today_stats = Statistics.objects.filter(date=today).first()

        week_ago = today - timedelta(days=7)
        week_stats = Statistics.objects.filter(date__gte=week_ago)

        total_visits = week_stats.aggregate(total=Count('total_visits'))
        avg_time = week_stats.aggregate(avg=Avg('avg_time_per_artwork'))

        return Response({
            'today': StatisticsSerializer(today_stats).data if today_stats else None,
            'last_7_days': {
                'total_visits': total_visits['total'],
                'avg_time_per_artwork': avg_time['avg'],
            },
            'top_artworks': self._get_top_artworks(7),
        })

    def _get_top_artworks(self, days=7):
        """Top œuvres"""
        from_date = timezone.now().date() - timedelta(days=days)
        top_artworks = Artwork.objects.filter(
            is_published=True,
            visits__visited_at__gte=from_date
        ).annotate(
            visits_count=Count('visits')
        ).order_by('-visits_count')[:10]

        return ArtworkListSerializer(top_artworks, many=True).data


# ==================== USER PROFILE VIEWSET ====================
class UserProfileViewSet(viewsets.ModelViewSet):
    """API pour gérer le profil utilisateur"""
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return User.objects.filter(id=self.request.user.id)

    @action(detail=False, methods=['get'])
    def me(self, request):
        """Profil de l'utilisateur connecté"""
        serializer = self.get_serializer(request.user)
        return Response(serializer.data)

    @action(detail=False, methods=['patch'])
    def update_preferences(self, request):
        """Mettre à jour les préférences"""
        user = request.user
        preferred_language = request.data.get('preferred_language')

        if preferred_language:
            user.preferred_language = preferred_language
            user.save()

        serializer = self.get_serializer(user)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """Statistiques personnelles"""
        user = request.user

        favorites_count = Favorite.objects.filter(user=user).count()
        visits_count = Visit.objects.filter(user=user).count()
        comments_count = Comment.objects.filter(user=user).count()

        favorite_categories = Favorite.objects.filter(user=user).values(
            'artwork__category__name'
        ).annotate(count=Count('id')).order_by('-count')[:5]

        return Response({
            'favorites_count': favorites_count,
            'visits_count': visits_count,
            'comments_count': comments_count,
            'favorite_categories': list(favorite_categories),
        })


def virtual_tour_js_debug(request):
    """Génère le JavaScript pour debug"""
    rooms = VirtualRoom.objects.filter(is_active=True).prefetch_related(
        'exits__to_room',
        'artwork_hotspots__artwork__translations'
    )

    rooms_list = []
    for room in rooms:
        room_data = {
            'id': str(room.id),
            'slug': room.slug if room.slug else 'no-slug',
            'name': room.name,
            'floor': room.floor if room.floor is not None else 0,
            'panorama': room.panorama_image.url if room.panorama_image else '',
            'ambientAudio': room.ambient_audio.url if room.ambient_audio else None,
            'isEntrance': room.is_entrance,
            'connections': [],
            'artworks': []
        }

        for exit in room.exits.all():
            room_data['connections'].append({
                'toRoomId': str(exit.to_room.id),
                'pitch': exit.hotspot_y if exit.hotspot_y is not None else 0,
                'yaw': exit.hotspot_x if exit.hotspot_x is not None else 0,
                'label': exit.label or 'Passage'
            })

        for hotspot in room.artwork_hotspots.all():
            trans = hotspot.artwork.translations.first()
            room_data['artworks'].append({
                'artworkId': str(hotspot.artwork.id),
                'title': trans.title if trans else hotspot.artwork.reference_code,
                'pitch': hotspot.hotspot_y if hotspot.hotspot_y is not None else 0,
                'yaw': hotspot.hotspot_x if hotspot.hotspot_x is not None else 0
            })

        rooms_list.append(room_data)

    # Générer le JavaScript valide
    js_code = f"const roomsData = {json.dumps(rooms_list, indent=2)};"

    return HttpResponse(js_code, content_type='text/javascript')


def virtual_tour_rooms_api(request):
    """API JSON pour les salles du tour virtuel"""
    rooms = VirtualRoom.objects.filter(is_active=True).prefetch_related(
        'exits__to_room',
        'artwork_hotspots__artwork__translations'
    )

    rooms_list = []
    for room in rooms:
        room_data = {
            'id': str(room.id),
            'slug': room.slug or 'room',
            'name': room.name,
            'floor': room.floor if room.floor is not None else 0,
            'panorama': request.build_absolute_uri(room.panorama_image.url) if room.panorama_image else '',
            'ambientAudio': request.build_absolute_uri(room.ambient_audio.url) if room.ambient_audio else None,
            'isEntrance': room.is_entrance,
            'connections': [],
            'artworks': []
        }

        for exit in room.exits.all():
            room_data['connections'].append({
                'toRoomId': str(exit.to_room.id),
                'pitch': float(exit.hotspot_y) if exit.hotspot_y is not None else 0,
                'yaw': float(exit.hotspot_x) if exit.hotspot_x is not None else 0,
                'label': exit.label or 'Passage'
            })

        for hotspot in room.artwork_hotspots.all():
            trans = hotspot.artwork.translations.first()
            room_data['artworks'].append({
                'artworkId': str(hotspot.artwork.id),
                'title': trans.title if trans else hotspot.artwork.reference_code,
                'pitch': float(hotspot.hotspot_y) if hotspot.hotspot_y is not None else 0,
                'yaw': float(hotspot.hotspot_x) if hotspot.hotspot_x is not None else 0
            })

        rooms_list.append(room_data)

    return JsonResponse(rooms_list, safe=False)

# ==================== VIRTUAL TOUR VIEWSETS ====================

class VirtualRoomViewSet(viewsets.ReadOnlyModelViewSet):
    """API pour les salles du tour virtuel"""
    from .models import VirtualRoom
    queryset = VirtualRoom.objects.filter(is_active=True)
    permission_classes = [AllowAny]
    lookup_field = 'slug'
    pagination_class = None

    def get_serializer_class(self):
        from .serializers import VirtualRoomSerializer
        return VirtualRoomSerializer

    @action(detail=False, methods=['get'])
    def entrance(self, request):
        """Récupère la salle d'entrée du musée"""
        entrance_room = self.queryset.filter(is_entrance=True).first()
        if entrance_room:
            serializer = self.get_serializer(entrance_room)
            return Response(serializer.data)
        return Response({'error': 'Pas de salle d\'entrée définie'}, status=404)

    @action(detail=False, methods=['get'])
    def map(self, request):
        """Carte complète du musée"""
        rooms = self.queryset.all()

        floors = {}
        for room in rooms:
            floor = room.floor
            if floor not in floors:
                floors[floor] = []
            floors[floor].append({
                'id': str(room.id),
                'name': room.name,
                'slug': room.slug,
                'artworks_count': room.artwork_hotspots.count()
            })

        return Response({'floors': floors})


class VirtualTourSessionViewSet(viewsets.ModelViewSet):
    """API pour les sessions de tour virtuel"""
    from .models import VirtualTourSession, RoomVisit, VirtualRoom
    queryset = VirtualTourSession.objects.all()
    permission_classes = [AllowAny]

    def get_serializer_class(self):
        from .serializers import VirtualTourSessionSerializer
        return VirtualTourSessionSerializer

    def get_queryset(self):
        if self.request.user.is_authenticated:
            return self.queryset.filter(user=self.request.user)
        return self.queryset.none()

    @action(detail=False, methods=['post'])
    def start(self, request):
        """Démarre une nouvelle session"""
        import uuid
        from .models import VirtualTourSession

        device_type = request.data.get('device_type', 'desktop')

        session = VirtualTourSession.objects.create(
            user=request.user if request.user.is_authenticated else None,
            session_key=request.session.session_key or str(uuid.uuid4()),
            device_type=device_type
        )

        serializer = self.get_serializer(session)
        return Response(serializer.data, status=201)

    @action(detail=True, methods=['post'])
    def visit_room(self, request, pk=None):
        """Enregistre la visite d'une salle"""
        from .models import VirtualRoom, RoomVisit

        session = self.get_object()
        room_id = request.data.get('room_id')
        duration = request.data.get('duration', 0)

        try:
            room = VirtualRoom.objects.get(id=room_id)
            RoomVisit.objects.create(
                session=session,
                room=room,
                duration=duration
            )
            return Response({'status': 'recorded'})
        except VirtualRoom.DoesNotExist:
            return Response({'error': 'Salle introuvable'}, status=404)

    @action(detail=True, methods=['post'])
    def end(self, request, pk=None):
        """Termine une session"""
        session = self.get_object()
        session.ended_at = timezone.now()

        if session.started_at:
            delta = session.ended_at - session.started_at
            session.duration = int(delta.total_seconds())

        session.save()

        serializer = self.get_serializer(session)
        return Response(serializer.data)


def home_view(request):
    """Page d'accueil du musée"""
    featured_artworks = Artwork.objects.filter(
        is_published=True,
        is_featured=True
    ).select_related('category').prefetch_related('translations')[:6]

    categories = Category.objects.annotate(
        artworks_count=Count('artworks', filter=Q(artworks__is_published=True))
    )

    # Œuvres les plus vues
    popular_artworks = Artwork.objects.filter(
        is_published=True
    ).order_by('-view_count')[:3]

    context = {
        'featured_artworks': featured_artworks,
        'categories': categories,
        'popular_artworks': popular_artworks,
        'total_artworks': Artwork.objects.filter(is_published=True).count(),
    }

    return render(request, 'home.html', context)


def artwork_list_view(request):
    """Liste de toutes les œuvres"""
    artworks = Artwork.objects.filter(is_published=True).select_related('category').prefetch_related('translations')

    # Filtres
    category_slug = request.GET.get('category')
    if category_slug:
        artworks = artworks.filter(category__slug=category_slug)

    search_query = request.GET.get('q')
    if search_query:
        lang = request.GET.get('lang', 'fr')
        artworks = artworks.filter(
            Q(reference_code__icontains=search_query) |
            Q(translations__title__icontains=search_query, translations__language=lang) |
            Q(translations__artist__icontains=search_query, translations__language=lang)
        ).distinct()

    # Pagination
    from django.core.paginator import Paginator
    paginator = Paginator(artworks, 12)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'artworks': page_obj,
        'categories': Category.objects.all(),
        'current_category': category_slug,
        'search_query': search_query,
    }

    return render(request, 'artworks/list.html', context)


def artwork_detail_view(request, slug):
    """Détail d'une œuvre - Accessible après scan QR"""
    artwork = get_object_or_404(
        Artwork.objects.select_related('category', 'created_by').prefetch_related(
            'translations',  # ✅ Supprimer '__language'
            'translations__audio_guides',  # ✅ Précharger aussi les audioguides
            'media',
            'exhibitions'
        ),
        id=slug,
        is_published=True
    )

    # Langue préférée
    lang_code = request.GET.get('lang', 'fr')

    # Charger toutes les langues actives
    available_languages = Language.objects.filter(
        is_active=True
    ).order_by('order').values_list('code', 'name')

    # Récupérer la traduction dans la langue demandée
    translation = artwork.translations.filter(language__code=lang_code).first()
    if not translation:
        translation = artwork.translations.filter(language__code='fr').first()

    # Récupérer TOUS les audioguides pour toutes les langues
    all_audio_guides = {}
    for trans in artwork.translations.all():
        audio = trans.audio_guides.first()
        if audio:
            # Obtenir le code de langue depuis la ForeignKey
            lang_key = trans.language.code if hasattr(trans.language, 'code') else trans.language
            all_audio_guides[lang_key] = audio

    # Audio guide de la langue courante
    audio_guide = all_audio_guides.get(lang_code)

    # Récupérer toutes les images
    images = artwork.media.filter(media_type='image').order_by('order')

    # Récupérer la vidéo (s'il y en a une)
    video = artwork.media.filter(media_type='video').first()

    # Vérifier si l'œuvre est en favoris (si connecté)
    is_favorited = False
    if request.user.is_authenticated:
        is_favorited = Favorite.objects.filter(
            user=request.user,
            artwork=artwork
        ).exists()

    # Incrémenter le compteur de vues
    artwork.view_count = F('view_count') + 1
    artwork.save(update_fields=['view_count'])
    artwork.refresh_from_db()

    # Enregistrer la visite
    Visit.objects.create(
        artwork=artwork,
        user=request.user if request.user.is_authenticated else None,
        ip_address=get_client_ip(request),
        user_agent=request.META.get('HTTP_USER_AGENT', ''),
        source='qr' if request.GET.get('qr') == '1' else 'web',
        language_viewed=lang_code
    )

    # Œuvres similaires
    related_artworks = Artwork.objects.filter(
        category=artwork.category,
        is_published=True
    ).exclude(id=artwork.id).select_related('category').prefetch_related('translations')[:3]

    # Commentaires approuvés
    comments = artwork.comments.filter(is_approved=True).select_related('user').order_by('-created_at')[:10]

    context = {
        'artwork': artwork,
        'translation': translation,
        'audio_guide': audio_guide,
        'all_audio_guides': all_audio_guides,
        'images': images,
        'video': video,
        'is_favorited': is_favorited,
        'related_artworks': related_artworks,
        'comments': comments,
        'current_lang': lang_code,
        'available_languages': available_languages,
        'qr_scan': request.GET.get('qr') == '1',
    }

    return render(request, 'artworks/detail.html', context)


def qr_scan_view(request):
    """Page de scan QR code"""
    return render(request, 'artworks/scan.html')


@login_required
@require_POST
def add_to_favorites(request, artwork_id):
    """Ajouter une œuvre aux favoris"""
    artwork = get_object_or_404(Artwork, id=artwork_id, is_published=True)

    favorite, created = Favorite.objects.get_or_create(
        user=request.user,
        artwork=artwork
    )

    if created:
        # Incrémenter le compteur
        artwork.favorites_count = F('favorites_count') + 1
        artwork.save(update_fields=['favorites_count'])
        artwork.refresh_from_db()

        messages.success(request, f'✓ "{artwork.reference_code}" ajouté à vos favoris')
    else:
        messages.info(request, f'Cette œuvre est déjà dans vos favoris')

    # Rediriger vers la page de l'œuvre au lieu de retourner JSON
    return redirect('artwork_detail', slug=artwork_id)


@login_required
@require_POST
def remove_from_favorites(request, artwork_id):
    """Retirer une œuvre des favoris"""
    artwork = get_object_or_404(Artwork, id=artwork_id)

    try:
        favorite = Favorite.objects.get(user=request.user, artwork=artwork)
        favorite.delete()

        # Décrémenter le compteur
        artwork.favorites_count = F('favorites_count') - 1
        artwork.save(update_fields=['favorites_count'])
        artwork.refresh_from_db()

        # Vérifier si c'est une requête AJAX
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or request.content_type == 'application/json':
            return JsonResponse({
                'status': 'removed',
                'message': 'Œuvre retirée de vos favoris',
                'favorites_count': artwork.favorites_count
            })
        else:
            messages.success(request, f'✓ Œuvre retirée de vos favoris')
            return redirect('favorites')

    except Favorite.DoesNotExist:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest' or request.content_type == 'application/json':
            return JsonResponse({
                'status': 'not_found',
                'message': 'Œuvre non trouvée dans vos favoris'
            }, status=404)
        else:
            messages.warning(request, 'Cette œuvre n\'était pas dans vos favoris')
            return redirect('favorites')

@login_required
def favorites_view(request):
    """Page affichant tous les favoris de l'utilisateur"""
    favorites = Favorite.objects.filter(
        user=request.user
    ).select_related('artwork__category').prefetch_related('artwork__translations').order_by('-created_at')

    # Pagination
    from django.core.paginator import Paginator
    paginator = Paginator(favorites, 12)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'favorites': page_obj,
        'total_favorites': favorites.count(),
    }

    return render(request, 'artworks/favorites.html', context)


@login_required
@require_POST
def add_comment(request, artwork_id):
    """Ajouter un commentaire à une œuvre"""
    artwork = get_object_or_404(Artwork, id=artwork_id, is_published=True)

    content = request.POST.get('content', '').strip()

    if not content:
        messages.error(request, 'Le commentaire ne peut pas être vide')
        return redirect('artwork_detail', slug=artwork_id)

    if len(content) < 10:
        messages.error(request, 'Le commentaire doit contenir au moins 10 caractères')
        return redirect('artwork_detail', slug=artwork_id)

    # Créer le commentaire (en attente de modération)
    Comment.objects.create(
        artwork=artwork,
        user=request.user,
        content=content,
        is_approved=False  # Nécessite modération
    )

    messages.success(request, 'Votre commentaire a été soumis et sera visible après modération')
    return redirect('artwork_detail', slug=artwork_id)


def category_view(request, slug):
    """Afficher toutes les œuvres d'une catégorie"""
    category = get_object_or_404(Category, slug=slug)

    artworks = Artwork.objects.filter(
        category=category,
        is_published=True
    ).select_related('category').prefetch_related('translations')

    # Pagination
    from django.core.paginator import Paginator
    paginator = Paginator(artworks, 12)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'category': category,
        'artworks': page_obj,
    }

    return render(request, 'artworks/category.html', context)


def exhibition_view(request, slug):
    """Afficher une exposition et ses œuvres"""
    exhibition = get_object_or_404(Exhibition, slug=slug, is_active=True)

    artworks = exhibition.artworks.filter(
        is_published=True
    ).select_related('category').prefetch_related('translations')

    context = {
        'exhibition': exhibition,
        'artworks': artworks,
        'is_ongoing': exhibition.is_ongoing(),
    }

    return render(request, 'artworks/exhibition.html', context)


def search_view(request):
    """Page de recherche"""
    query = request.GET.get('q', '')
    lang = request.GET.get('lang', 'fr')

    results = []

    if query:
        results = Artwork.objects.filter(
            Q(reference_code__icontains=query) |
            Q(translations__title__icontains=query, translations__language=lang) |
            Q(translations__description__icontains=query, translations__language=lang) |
            Q(translations__artist__icontains=query, translations__language=lang),
            is_published=True
        ).distinct().select_related('category').prefetch_related('translations')

    # Pagination
    from django.core.paginator import Paginator
    paginator = Paginator(results, 12)
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)

    context = {
        'query': query,
        'results': page_obj,
        'total_results': results.count() if query else 0,
    }

    return render(request, 'artworks/search.html', context)


def virtual_tour_view(request):
    """Page du tour virtuel 3D avec données réelles"""
    from .models import VirtualRoom

    # Charger toutes les salles actives
    rooms = VirtualRoom.objects.filter(is_active=True).prefetch_related(
        'exits__to_room',
        'artwork_hotspots__artwork__translations'
    ).order_by('floor', 'order')

    # DEBUG - Regardez votre terminal
    print(f"=== DEBUG VIRTUAL TOUR ===")
    print(f"Nombre de salles: {rooms.count()}")
    for room in rooms:
        print(f"  - {room.name} (entrance={room.is_entrance})")

    # Grouper par étage
    floors = {}
    for room in rooms:
        if room.floor not in floors:
            floors[room.floor] = []
        floors[room.floor].append(room)

    context = {
        'rooms': rooms,
        'floors': floors,
    }

    return render(request, 'artworks/virtual_tour.html', context)  # ← CORRECTION ICI


def virtual_tour_debug(request):
    """Vue de debug pour la visite virtuelle"""
    rooms = VirtualRoom.objects.filter(is_active=True)

    data = {
        'total_rooms': rooms.count(),
        'rooms': []
    }

    for room in rooms:
        data['rooms'].append({
            'id': str(room.id),
            'name': room.name,
            'floor': room.floor,
            'has_panorama': bool(room.panorama_image),
            'panorama_url': room.panorama_image.url if room.panorama_image else None,
            'has_audio': bool(room.ambient_audio),
            'is_entrance': room.is_entrance,
            'connections_count': room.exits.count(),
            'artworks_count': room.artwork_hotspots.count(),
        })

    return JsonResponse(data, json_dumps_params={'indent': 2})

def virtual_tour_debug(request):
    rooms = VirtualRoom.objects.filter(is_active=True)
    return JsonResponse({
        'rooms_count': rooms.count(),
        'rooms': [{
            'id': str(room.id),
            'name': room.name,
            'has_panorama': bool(room.panorama_image),
            'panorama_path': room.panorama_image.url if room.panorama_image else None,
        } for room in rooms]
    })
# ==================== FONCTIONS UTILITAIRES ====================

def get_client_ip(request):
    """Récupère l'IP du visiteur"""
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip


def artwork_3d_view(request, pk):
    """Vue 3D d'une œuvre"""
    artwork = get_object_or_404(Artwork, pk=pk, is_published=True)

    # Vérifier l'existence de view_3d
    if not hasattr(artwork, 'view_3d'):
        messages.warning(request, 'Cette œuvre ne dispose pas de vue 3D.')
        return redirect('artwork_detail', slug=pk)  # ✅ Utiliser le bon paramètre

    view_3d = artwork.view_3d

    if not view_3d.is_active:
        messages.warning(request, 'La vue 3D de cette œuvre est désactivée.')
        return redirect('artwork_detail', slug=pk)

    # Vérifier que l'image existe
    if not view_3d.panorama_image:
        messages.error(request, 'L\'image panoramique n\'est pas disponible.')
        return redirect('artwork_detail', slug=pk)

    lang = request.GET.get('lang', 'fr')
    translation = artwork.translations.filter(language=lang).first() or artwork.translations.first()

    context = {
        'artwork': artwork,
        'view_3d': view_3d,
        'translation': translation,
    }

    return render(request, 'artworks/artwork_3d.html', context)

@staff_member_required
def artwork_creation_wizard(request):
    """Assistant de création d'œuvre - Interface simplifiée"""

    if request.method == 'POST':
        try:
            # 1. Créer l'œuvre de base
            artwork = Artwork.objects.create(
                reference_code=request.POST.get('reference_code'),
                category_id=request.POST.get('category'),
                origin=request.POST.get('origin', ''),
                period=request.POST.get('period', ''),
                acquisition_date=request.POST.get('acquisition_date') or None,
                is_published=request.POST.get('is_published') == 'on',
                is_featured=request.POST.get('is_featured') == 'on',
                status='published' if request.POST.get('is_published') == 'on' else 'draft',
                created_by=request.user
            )

            # 2. Créer les traductions
            languages = ['fr', 'en', 'wo']
            for lang in languages:
                title = request.POST.get(f'title_{lang}')
                description = request.POST.get(f'description_{lang}')

                if title or description:  # Créer seulement si au moins un champ est rempli
                    translation = ArtworkTranslation.objects.create(
                        artwork=artwork,
                        language=lang,
                        title=title or artwork.reference_code,
                        description=description or '',
                        artist=request.POST.get(f'artist_{lang}', ''),
                        historical_context=request.POST.get(f'historical_context_{lang}', ''),
                        cultural_significance=request.POST.get(f'cultural_significance_{lang}', '')
                    )

                    # Générer l'audioguide si demandé
                    if request.POST.get('auto_generate_audio') == 'on':
                        generate_audio_guide.delay(str(translation.id))

            # 3. Gérer les images
            images = request.FILES.getlist('images')
            for i, image in enumerate(images):
                Media.objects.create(
                    artwork=artwork,
                    media_type='image',
                    file=image,
                    order=i
                )

            # 4. Gérer la vidéo
            if 'video' in request.FILES:
                Media.objects.create(
                    artwork=artwork,
                    media_type='video',
                    file=request.FILES['video'],
                    order=999
                )

            # 5. Créer la vue 3D si activée
            if request.POST.get('enable_3d') == 'on' and 'panorama_image' in request.FILES:
                Artwork3DView.objects.create(
                    artwork=artwork,
                    panorama_image=request.FILES['panorama_image'],
                    initial_yaw=float(request.POST.get('initial_yaw', 0)),
                    initial_pitch=float(request.POST.get('initial_pitch', 0)),
                    initial_fov=float(request.POST.get('initial_fov', 75)),
                    auto_rotate=request.POST.get('auto_rotate') == 'on',
                    auto_rotate_speed=float(request.POST.get('auto_rotate_speed', 2)),
                    ambient_audio=request.FILES.get('ambient_audio'),
                    is_active=True
                )

            # 6. Générer le QR code
            artwork.generate_qr_code()
            artwork.save(update_fields=['qr_code'])

            messages.success(
                request,
                f'Œuvre "{artwork.reference_code}" créée avec succès ! '
                f'Le QR code a été généré automatiquement.'
            )

            return redirect('admin:artworks_artwork_change', artwork.id)

        except Exception as e:
            messages.error(request, f'Erreur lors de la création : {str(e)}')
            return redirect('artwork_creation_wizard')

    # GET - Afficher le formulaire
    context = {
        'categories': Category.objects.all().order_by('name'),
        'title': 'Assistant de création d\'œuvre',
    }
    return render(request, 'admin/artwork_wizard.html', context)


def login_view(request):
    """Vue de connexion"""
    if request.user.is_authenticated:
        return redirect('home')

    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                messages.success(request, f'Bienvenue {user.username} !')
                next_url = request.POST.get('next') or request.GET.get('next') or 'home'
                return redirect(next_url)
        else:
            messages.error(request, 'Identifiants incorrects.')
    else:
        form = AuthenticationForm()

    return render(request, 'artworks/login.html', {'form': form})


def register_view(request):
    """Vue d'inscription avec activation email"""
    if request.user.is_authenticated:
        return redirect('home')

    if request.method == 'POST':
        username = request.POST.get('username')
        email = request.POST.get('email')
        password1 = request.POST.get('password1')
        password2 = request.POST.get('password2')
        first_name = request.POST.get('first_name', '')
        last_name = request.POST.get('last_name', '')
        preferred_language = request.POST.get('preferred_language', 'fr')

        # Validation
        errors = {}

        if User.objects.filter(username=username).exists():
            errors['username'] = ['Ce nom d\'utilisateur existe déjà.']

        if User.objects.filter(email=email).exists():
            errors['email'] = ['Cet email est déjà utilisé.']

        if password1 != password2:
            errors['password2'] = ['Les mots de passe ne correspondent pas.']

        if len(password1) < 8:
            errors['password1'] = ['Le mot de passe doit contenir au moins 8 caractères.']

        if errors:
            return render(request, 'artworks/register.html', {
                'form': {'errors': errors},
                'username': {'value': username},
                'email': {'value': email},
                'first_name': {'value': first_name},
                'last_name': {'value': last_name},
            })

        # Créer l'utilisateur DÉSACTIVÉ
        user = User.objects.create_user(
            username=username,
            email=email,
            password=password1,
            first_name=first_name,
            last_name=last_name,
            preferred_language=preferred_language,
            is_active=False,
            email_verified=False
        )

        # Envoyer l'email d'activation
        try:
            user.send_activation_email()
            # ✅ CORRECTION : Chemin correct du template
            return render(request, 'artworks/activation_sent.html', {'email': email})
        except Exception as e:
            import traceback
            print(traceback.format_exc())  # Afficher l'erreur complète dans la console
            messages.error(request, f'Erreur lors de l\'envoi : {str(e)}')
            user.delete()
            return redirect('register')

    return render(request, 'artworks/register.html', {})


def activate_account(request, token):
    """Active un compte utilisateur"""
    try:
        # Récupérer le token
        activation_token = ActivationToken.objects.select_related('user').get(token=token)

        # Vérifier l'expiration AVANT d'activer
        if not activation_token.is_valid():
            messages.error(
                request,
                'Ce lien d\'activation a expiré. Veuillez demander un nouveau lien.'
            )
            return redirect('resend_activation')

        # Activer l'utilisateur
        user = activation_token.user
        user.is_active = True
        user.email_verified = True
        user.save(update_fields=['is_active', 'email_verified'])

        # Supprimer le token utilisé
        activation_token.delete()

        # Connexion automatique
        login(request, user, backend='django.contrib.auth.backends.ModelBackend')

        messages.success(
            request,
            f'✓ Compte activé avec succès ! Bienvenue {user.username} !'
        )
        return redirect('home')

    except ActivationToken.DoesNotExist:
        messages.error(request, 'Lien d\'activation invalide ou déjà utilisé.')
        return redirect('login')
    except Exception as e:
        # Log l'erreur pour le debug
        import traceback
        print(f"Erreur activation: {traceback.format_exc()}")
        messages.error(request, 'Une erreur s\'est produite lors de l\'activation.')
        return redirect('login')


def resend_activation(request):
    """Renvoie l'email d'activation"""
    if request.method == 'POST':
        email = request.POST.get('email')

        try:
            user = User.objects.get(email=email, is_active=False)
            user.send_activation_email()
            messages.success(request, 'Un nouvel email d\'activation a été envoyé.')
            return redirect('login')
        except User.DoesNotExist:
            messages.error(request, 'Aucun compte inactif trouvé avec cet email.')

    return render(request, 'emails/resend_activation.html')
@login_required
def logout_view(request):
    """Vue de déconnexion"""
    logout(request)
    messages.success(request, 'Vous avez été déconnecté avec succès.')
    return redirect('home')