import uuid

from requests import Response
from rest_framework import serializers, viewsets
from django.contrib.auth import get_user_model
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny

from .models import (
    Language, Category, CategoryTranslation, Exhibition, ExhibitionTranslation,
    Artwork, ArtworkTranslation, Media, AudioGuide, Visit, Favorite, Comment, Statistics, VirtualRoom,
    VirtualTourSession, RoomVisit, Artwork3DView, ArtworkDetailPoint
)

User = get_user_model()


# ==================== USER SERIALIZERS ====================
class UserSerializer(serializers.ModelSerializer):
    """Serializer pour les utilisateurs"""

    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'role', 'date_joined', 'is_active', 'preferred_language']
        read_only_fields = ['id', 'date_joined']


class UserRegistrationSerializer(serializers.ModelSerializer):
    """Serializer pour l'inscription"""
    password = serializers.CharField(write_only=True, min_length=8)
    password_confirm = serializers.CharField(write_only=True)

    class Meta:
        model = User
        fields = ['username', 'email', 'password', 'password_confirm', 'preferred_language']

    def validate(self, data):
        if data['password'] != data['password_confirm']:
            raise serializers.ValidationError("Les mots de passe ne correspondent pas")
        return data

    def create(self, validated_data):
        validated_data.pop('password_confirm')
        user = User.objects.create_user(**validated_data)
        return user


# ==================== LANGUAGE SERIALIZERS ====================
class LanguageSerializer(serializers.ModelSerializer):
    """Serializer pour les langues"""
    translations_count = serializers.SerializerMethodField()

    class Meta:
        model = Language
        fields = ['id', 'code', 'name', 'native_name', 'is_active', 'translations_count']

    def get_translations_count(self, obj):
        return obj.get_translations_count()


# ==================== CATEGORY SERIALIZERS ====================
class CategoryTranslationSerializer(serializers.ModelSerializer):
    """Serializer pour les traductions de catégories"""

    class Meta:
        model = CategoryTranslation
        fields = ['id', 'language', 'name', 'description']


class CategorySerializer(serializers.ModelSerializer):
    """Serializer pour les catégories"""
    translations = CategoryTranslationSerializer(many=True, read_only=True)
    artworks_count = serializers.SerializerMethodField()
    icon_url = serializers.SerializerMethodField()

    class Meta:
        model = Category
        fields = ['id', 'name', 'slug', 'icon_url', 'translations', 'artworks_count', 'order']

    def get_artworks_count(self, obj):
        return obj.get_artworks().count()

    def get_icon_url(self, obj):
        if obj.icon:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.icon.url) if request else obj.icon.url
        return None


# ==================== EXHIBITION SERIALIZERS ====================
class ExhibitionTranslationSerializer(serializers.ModelSerializer):
    """Serializer pour les traductions d'expositions"""

    class Meta:
        model = ExhibitionTranslation
        fields = ['id', 'language', 'title', 'description']


class ExhibitionSerializer(serializers.ModelSerializer):
    """Serializer pour les expositions"""
    translations = ExhibitionTranslationSerializer(many=True, read_only=True)
    is_ongoing = serializers.SerializerMethodField()
    artworks_count = serializers.SerializerMethodField()

    class Meta:
        model = Exhibition
        fields = ['id', 'title', 'slug', 'start_date', 'end_date', 'is_active',
                  'is_ongoing', 'translations', 'artworks_count', 'created_at']

    def get_is_ongoing(self, obj):
        return obj.is_ongoing()

    def get_artworks_count(self, obj):
        return obj.get_artworks().count()


# ==================== MEDIA SERIALIZERS ====================
class MediaSerializer(serializers.ModelSerializer):
    """Serializer pour les médias"""
    file_url = serializers.SerializerMethodField()
    thumbnail_url = serializers.SerializerMethodField()

    class Meta:
        model = Media
        fields = ['id', 'media_type', 'file_url', 'thumbnail_url', 'caption',
                  'size', 'order', 'language', 'uploaded_at']

    def get_file_url(self, obj):
        if obj.file:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.file.url) if request else obj.file.url
        return None

    def get_thumbnail_url(self, obj):
        if obj.thumbnail:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.thumbnail.url) if request else obj.thumbnail.url
        return None


# ==================== AUDIO GUIDE SERIALIZERS ====================
class AudioGuideSerializer(serializers.ModelSerializer):
    """Serializer pour les guides audio"""
    audio_url = serializers.SerializerMethodField()
    duration_formatted = serializers.SerializerMethodField()
    language = serializers.CharField(source='artwork_translation.language', read_only=True)

    class Meta:
        model = AudioGuide
        fields = ['id', 'audio_url', 'duration', 'duration_formatted',
                  'narrator', 'language', 'created_at']

    def get_audio_url(self, obj):
        if obj.audio_file:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.audio_file.url) if request else obj.audio_file.url
        return None

    def get_duration_formatted(self, obj):
        return obj.get_duration_formatted()


# ==================== ARTWORK TRANSLATION SERIALIZERS ====================
class ArtworkTranslationSerializer(serializers.ModelSerializer):
    """Serializer pour les traductions d'œuvres"""
    audio_guides = AudioGuideSerializer(many=True, read_only=True)
    is_complete = serializers.SerializerMethodField()

    class Meta:
        model = ArtworkTranslation
        fields = ['id', 'language', 'title', 'description', 'historical_context',
                  'cultural_significance', 'artist', 'audio_guides', 'is_complete',
                  'created_at', 'updated_at']

    def get_is_complete(self, obj):
        return obj.is_complete()


# ==================== ARTWORK SERIALIZERS ====================
class ArtworkListSerializer(serializers.ModelSerializer):
    """Serializer léger pour la liste d'œuvres"""
    category_name = serializers.CharField(source='category.name', read_only=True)
    main_image = serializers.SerializerMethodField()
    qr_code_url = serializers.SerializerMethodField()
    title = serializers.SerializerMethodField()

    class Meta:
        model = Artwork
        fields = ['id', 'reference_code', 'title', 'category_name', 'main_image',
                  'qr_code_url', 'is_featured', 'view_count', 'favorites_count',
                  'status', 'created_at']

    def get_main_image(self, obj):
        media = obj.media.filter(media_type='image', order=0).first()
        if media and media.file:
            request = self.context.get('request')
            return request.build_absolute_uri(media.file.url) if request else media.file.url
        return None

    def get_qr_code_url(self, obj):
        if obj.qr_code:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.qr_code.url) if request else obj.qr_code.url
        return None

    def get_title(self, obj):
        # Récupère le titre dans la langue préférée de l'utilisateur
        lang = self.context.get('language', 'fr')
        try:
            translation = obj.translations.get(language=lang)
            return translation.title
        except ArtworkTranslation.DoesNotExist:
            try:
                return obj.translations.get(language='fr').title
            except ArtworkTranslation.DoesNotExist:
                return obj.reference_code


# ==================== VISIT SERIALIZERS ====================
class VisitSerializer(serializers.ModelSerializer):
    """Serializer pour les visites"""
    artwork_title = serializers.CharField(source='artwork.reference_code', read_only=True)

    class Meta:
        model = Visit
        fields = ['id', 'artwork', 'artwork_title', 'source', 'visited_at']
        read_only_fields = ['id', 'visited_at']


class VisitCreateSerializer(serializers.ModelSerializer):
    """Serializer pour créer une visite"""

    class Meta:
        model = Visit
        fields = ['artwork', 'source']

    def create(self, validated_data):
        request = self.context.get('request')
        if request:
            validated_data['user'] = request.user if request.user.is_authenticated else None
            validated_data['ip_address'] = self.get_client_ip(request)
            validated_data['user_agent'] = request.META.get('HTTP_USER_AGENT', '')
            validated_data['session_id'] = request.session.session_key
        return super().create(validated_data)

    def get_client_ip(self, request):
        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


# ==================== FAVORITE SERIALIZERS ====================
class FavoriteSerializer(serializers.ModelSerializer):
    """Serializer pour les favoris"""
    artwork_detail = ArtworkListSerializer(source='artwork', read_only=True)

    class Meta:
        model = Favorite
        fields = ['id', 'artwork', 'artwork_detail', 'created_at']
        read_only_fields = ['id', 'created_at']


class FavoriteCreateSerializer(serializers.ModelSerializer):
    """Serializer pour créer un favori"""

    class Meta:
        model = Favorite
        fields = ['artwork']

    def validate(self, data):
        request = self.context.get('request')
        if Favorite.objects.filter(user=request.user, artwork=data['artwork']).exists():
            raise serializers.ValidationError("Cette œuvre est déjà dans vos favoris")
        return data

    def create(self, validated_data):
        request = self.context.get('request')
        validated_data['user'] = request.user

        # Incrémenter le compteur de favoris
        artwork = validated_data['artwork']
        artwork.favorites_count += 1
        artwork.save(update_fields=['favorites_count'])

        return super().create(validated_data)


# ==================== COMMENT SERIALIZERS ====================
class CommentSerializer(serializers.ModelSerializer):
    """Serializer pour les commentaires"""
    user_info = serializers.SerializerMethodField()

    class Meta:
        model = Comment
        fields = ['id', 'artwork', 'user_info', 'content', 'is_approved',
                  'is_flagged', 'created_at', 'updated_at']
        read_only_fields = ['id', 'is_approved', 'is_flagged', 'created_at', 'updated_at']

    def get_user_info(self, obj):
        return {
            'id': obj.user.id,
            'username': obj.user.username,
            'role': obj.user.role
        }


class CommentCreateSerializer(serializers.ModelSerializer):
    """Serializer pour créer un commentaire"""

    class Meta:
        model = Comment
        fields = ['artwork', 'content']

    def validate_content(self, value):
        if len(value) < 10:
            raise serializers.ValidationError("Le commentaire doit contenir au moins 10 caractères")
        if len(value) > 1000:
            raise serializers.ValidationError("Le commentaire ne doit pas dépasser 1000 caractères")
        return value

    def create(self, validated_data):
        request = self.context.get('request')
        validated_data['user'] = request.user
        # Les commentaires nécessitent une approbation par défaut
        validated_data['is_approved'] = False
        return super().create(validated_data)


class CommentModerateSerializer(serializers.Serializer):
    """Serializer pour modérer un commentaire"""
    action = serializers.ChoiceField(choices=['approve', 'reject', 'flag'])

    def validate(self, data):
        request = self.context.get('request')
        if request.user.role not in ['content_moderator', 'museum_admin']:
            raise serializers.ValidationError("Vous n'avez pas les permissions pour modérer")
        return data


# ==================== STATISTICS SERIALIZERS ====================
class StatisticsSerializer(serializers.ModelSerializer):
    """Serializer pour les statistiques"""
    most_viewed_artwork_info = serializers.SerializerMethodField()

    class Meta:
        model = Statistics
        fields = ['id', 'date', 'total_visits', 'unique_visitors', 'qr_scans',
                  'most_viewed_artwork_info', 'avg_time_per_artwork']

    def get_most_viewed_artwork_info(self, obj):
        if obj.most_viewed_artwork:
            return {
                'id': obj.most_viewed_artwork.id,
                'reference_code': obj.most_viewed_artwork.reference_code,
                'view_count': obj.most_viewed_artwork.view_count
            }
        return None


# ==================== ANALYTICS SERIALIZERS ====================
class AnalyticsSerializer(serializers.Serializer):
    """Serializer pour les analytics avancées"""
    period = serializers.ChoiceField(choices=['day', 'week', 'month', 'year'])
    start_date = serializers.DateField(required=False)
    end_date = serializers.DateField(required=False)


class PopularArtworksSerializer(serializers.Serializer):
    """Serializer pour les œuvres populaires"""
    artwork = ArtworkListSerializer()
    view_count = serializers.IntegerField()
    favorites_count = serializers.IntegerField()
    comments_count = serializers.IntegerField()
    score = serializers.FloatField()


# ==================== SEARCH SERIALIZERS ====================
class SearchSerializer(serializers.Serializer):
    """Serializer pour la recherche"""
    query = serializers.CharField(required=True, min_length=2)
    language = serializers.ChoiceField(choices=['fr', 'en', 'wo'], default='fr')
    category = serializers.UUIDField(required=False)
    period = serializers.CharField(required=False)
    exhibition = serializers.UUIDField(required=False)


# ==================== BULK OPERATIONS SERIALIZERS ====================
class BulkArtworkUpdateSerializer(serializers.Serializer):
    """Serializer pour les mises à jour en masse"""
    artwork_ids = serializers.ListField(child=serializers.UUIDField())
    action = serializers.ChoiceField(choices=['publish', 'unpublish', 'feature', 'unfeature', 'archive'])

    def validate_artwork_ids(self, value):
        if len(value) == 0:
            raise serializers.ValidationError("Au moins une œuvre doit être sélectionnée")
        if len(value) > 100:
            raise serializers.ValidationError("Maximum 100 œuvres à la fois")
        return value


class VirtualRoomSerializer(serializers.ModelSerializer):
    panorama_url = serializers.SerializerMethodField()
    thumbnail_url = serializers.SerializerMethodField()
    ambient_audio_url = serializers.SerializerMethodField()
    connections = serializers.SerializerMethodField()
    artwork_hotspots = serializers.SerializerMethodField()
    artworks_count = serializers.SerializerMethodField()

    class Meta:
        model = VirtualRoom
        fields = ['id', 'name', 'slug', 'description', 'floor', 'order',
                  'panorama_url', 'thumbnail_url', 'ambient_audio_url',
                  'connections', 'artwork_hotspots', 'artworks_count',
                  'is_entrance', 'created_at']

    def get_panorama_url(self, obj):
        if obj.panorama_image:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.panorama_image.url) if request else obj.panorama_image.url
        return None

    def get_thumbnail_url(self, obj):
        if obj.thumbnail:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.thumbnail.url) if request else obj.thumbnail.url
        return None

    def get_ambient_audio_url(self, obj):
        if obj.ambient_audio:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.ambient_audio.url) if request else obj.ambient_audio.url
        return None

    def get_connections(self, obj):
        connections = obj.exits.all()
        return [{
            'to_room_id': conn.to_room.id,
            'to_room_name': conn.to_room.name,
            'to_room_slug': conn.to_room.slug,
            'hotspot_x': conn.hotspot_x,
            'hotspot_y': conn.hotspot_y,
            'label': conn.label,
            'icon': conn.icon
        } for conn in connections]

    def get_artwork_hotspots(self, obj):
        hotspots = obj.artwork_hotspots.filter(is_active=True).select_related('artwork')
        return [{
            'artwork_id': hs.artwork.id,
            'artwork_reference': hs.artwork.reference_code,
            'hotspot_x': hs.hotspot_x,
            'hotspot_y': hs.hotspot_y,
            'animation_type': hs.animation_type
        } for hs in hotspots]

    def get_artworks_count(self, obj):
        return obj.artwork_hotspots.filter(is_active=True).count()


class VirtualTourSessionSerializer(serializers.ModelSerializer):
    rooms_visited_list = serializers.SerializerMethodField()

    class Meta:
        model = VirtualTourSession
        fields = ['id', 'started_at', 'duration', 'rooms_visited_list',
                  'artworks_viewed', 'device_type']
        read_only_fields = ['started_at']

    def get_rooms_visited_list(self, obj):
        return list(obj.rooms_visited.values_list('name', flat=True))


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

    @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):
        """Retourne la carte complète du musée"""
        rooms = self.queryset.all()

        # Organiser par étage
        floors = {}
        for room in rooms:
            floor = room.floor
            if floor not in floors:
                floors[floor] = []
            floors[floor].append({
                'id': room.id,
                'name': room.name,
                'slug': room.slug,
                'thumbnail': self.get_serializer(room).data['thumbnail_url'],
                'artworks_count': room.artwork_hotspots.count()
            })

        return Response({'floors': floors})


class VirtualTourSessionViewSet(viewsets.ModelViewSet):
    """API pour les sessions de tour virtuel"""
    queryset = VirtualTourSession.objects.all()
    serializer_class = VirtualTourSessionSerializer
    permission_classes = [AllowAny]

    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 de tour virtuel"""
        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"""
        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"""
        from django.utils import timezone

        session = self.get_object()
        session.ended_at = timezone.now()

        # Calculer la durée totale
        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)


class ArtworkDetailPointSerializer(serializers.ModelSerializer):
    detail_image_url = serializers.SerializerMethodField()

    class Meta:
        model = ArtworkDetailPoint
        fields = ['id', 'title', 'description', 'pitch', 'yaw', 'point_type',
                  'detail_image_url', 'order']

    def get_detail_image_url(self, obj):
        if obj.detail_image:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.detail_image.url) if request else obj.detail_image.url
        return None


class Artwork3DViewSerializer(serializers.ModelSerializer):
    detail_points = ArtworkDetailPointSerializer(many=True, read_only=True)
    panorama_url = serializers.SerializerMethodField()
    ambient_audio_url = serializers.SerializerMethodField()

    class Meta:
        model = Artwork3DView
        fields = ['id', 'panorama_url', 'initial_yaw', 'initial_pitch', 'initial_fov',
                  'allow_zoom', 'allow_rotation', 'show_controls', 'auto_rotate',
                  'auto_rotate_speed', 'ambient_audio_url', 'detail_points', 'is_active']

    def get_panorama_url(self, obj):
        if obj.panorama_image:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.panorama_image.url) if request else obj.panorama_image.url
        return None

    def get_ambient_audio_url(self, obj):
        if obj.ambient_audio:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.ambient_audio.url) if request else obj.ambient_audio.url
        return None

class ArtworkDetailSerializer(serializers.ModelSerializer):
    """Serializer complet pour le détail d'une œuvre"""
    category = CategorySerializer(read_only=True)
    translations = ArtworkTranslationSerializer(many=True, read_only=True)
    media = MediaSerializer(many=True, read_only=True)
    exhibitions = ExhibitionSerializer(many=True, read_only=True)
    qr_code_url = serializers.SerializerMethodField()
    statistics = serializers.SerializerMethodField()
    is_favorited = serializers.SerializerMethodField()
    comments_count = serializers.SerializerMethodField()

    class Meta:
        model = Artwork
        fields = ['id', 'reference_code', 'category', 'origin', 'period',
                  'acquisition_date', 'status', 'is_published', 'is_featured',
                  'view_count', 'favorites_count', 'translations', 'media',
                  'exhibitions', 'qr_code_url', 'statistics', 'is_favorited',
                  'comments_count', 'created_at', 'updated_at']

    def get_qr_code_url(self, obj):
        if obj.qr_code:
            request = self.context.get('request')
            return request.build_absolute_uri(obj.qr_code.url) if request else obj.qr_code.url
        return None

    def get_statistics(self, obj):
        return obj.get_statistics()

    def get_is_favorited(self, obj):
        request = self.context.get('request')
        if request and request.user.is_authenticated:
            return Favorite.objects.filter(user=request.user, artwork=obj).exists()
        return False

    def get_comments_count(self, obj):
        return obj.comments.filter(is_approved=True).count()

    view_3d = Artwork3DViewSerializer(read_only=True)
    has_3d_view = serializers.SerializerMethodField()

    class Meta:
        model = Artwork
        fields = ['id', 'reference_code', 'category', 'origin', 'period',
                  'acquisition_date', 'status', 'is_published', 'is_featured',
                  'view_count', 'favorites_count', 'translations', 'media',
                  'exhibitions', 'qr_code_url', 'statistics', 'is_favorited',
                  'comments_count', 'view_3d', 'has_3d_view', 'created_at', 'updated_at']

    def get_has_3d_view(self, obj):
        return hasattr(obj, 'view_3d') and obj.view_3d.is_active