from rest_framework import serializers
from Auth.models import Profile
from GestionMessagerie.models import Messagerie, Conversation, ConversationParticipant, Message, MessageRead, UserPresence
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

class ProfileSimpleSerializer(serializers.ModelSerializer):
    """Sérialiseur simple pour les profils utilisateur"""
    class Meta:
        model = Profile
        fields = ['id', 'first_name', 'last_name', 'email']

class UserPresenceSerializer(serializers.ModelSerializer):
    """Sérialiseur pour la présence utilisateur"""
    user = ProfileSimpleSerializer(read_only=True)

    class Meta:
        model = UserPresence
        fields = ['user', 'status', 'last_seen', 'is_typing_in']

class MessageReadSerializer(serializers.ModelSerializer):
    """Sérialiseur pour les messages lus"""
    participant = ProfileSimpleSerializer(read_only=True)

    class Meta:
        model = MessageRead
        fields = ['participant', 'read_at']

class MessageSerializer(serializers.ModelSerializer):
    """Sérialiseur pour les messages instantanés"""
    sender = ProfileSimpleSerializer(read_only=True)
    read_by = MessageReadSerializer(many=True, read_only=True)
    attachment = serializers.SerializerMethodField()
    is_read = serializers.SerializerMethodField()

    class Meta:
        model = Message
        fields = ['id', 'conversation', 'sender', 'content', 'message_type', 'file_url',
                 'file_name', 'file_size', 'file_type', 'attachment',
                 'created_at', 'updated_at', 'is_edited', 'is_deleted', 'read_by', 'is_read']
        read_only_fields = ['id', 'created_at', 'updated_at']

    def get_attachment(self, obj):
        """Retourne les informations du fichier attaché sous forme d'objet"""
        if obj.file_url:
            return {
                'fileName': obj.file_name,
                'fileSize': obj.file_size,
                'fileType': obj.file_type,
                'fileUrl': obj.file_url,
            }
        return None

    def get_is_read(self, obj):
        """Détermine si le message est lu par l'utilisateur actuel"""
        user = self.context.get('user')
        if not user or not user.is_authenticated:
            return False

        # Si c'est le message de l'utilisateur lui-même, vérifier si quelqu'un d'autre l'a lu
        if obj.sender == user:
            # Pour les messages envoyés par l'utilisateur, vérifier si au moins un autre participant l'a explicitement lu
            # Utiliser le modèle MessageRead pour une vérification précise
            from .models import MessageRead
            other_participants = obj.conversation.participants.exclude(participant=user).filter(is_active=True)

            for participant in other_participants:
                # Vérifier si ce participant a explicitement lu ce message
                if MessageRead.objects.filter(message=obj, participant=participant.participant).exists():
                    return True

                # Fallback: vérifier last_read_at seulement si l'utilisateur était en ligne récemment
                # ou si last_read_at est postérieur à created_at (lecture explicite après réception)
                if (participant.last_read_at and
                    participant.last_read_at > obj.created_at):

                    # Vérifier la présence de l'utilisateur pour s'assurer qu'il était en ligne
                    try:
                        from .models import UserPresence
                        user_presence = UserPresence.objects.filter(user=participant.participant).first()

                        # Si l'utilisateur était en ligne récemment (dans les 5 minutes suivant le message)
                        # ou si last_read_at est bien après created_at (lecture délibérée)
                        time_diff = participant.last_read_at - obj.created_at
                        if (user_presence and user_presence.last_seen and
                            user_presence.last_seen >= obj.created_at) or time_diff.total_seconds() > 10:
                            return True
                    except:
                        # En cas d'erreur, continuer avec la logique conservative
                        pass

            return False
        else:
            # Pour les messages reçus, vérifier si l'utilisateur actuel l'a lu
            # D'abord vérifier dans MessageRead pour une lecture explicite
            from .models import MessageRead
            if MessageRead.objects.filter(message=obj, participant=user).exists():
                return True

            # Fallback: vérifier last_read_at du participant
            participant = obj.conversation.participants.filter(
                participant=user,
                is_active=True
            ).first()

            if participant and participant.last_read_at:
                # Seulement considérer comme lu si last_read_at est postérieur à created_at
                return participant.last_read_at > obj.created_at

            return False

class ConversationParticipantSerializer(serializers.ModelSerializer):
    """Sérialiseur pour les participants d'une conversation"""
    participant = ProfileSimpleSerializer(read_only=True)

    class Meta:
        model = ConversationParticipant
        fields = ['participant', 'joined_at', 'last_read_at', 'is_active']

class ConversationSerializer(serializers.ModelSerializer):
    """Sérialiseur pour les conversations"""
    participants = ConversationParticipantSerializer(many=True, read_only=True)
    last_message = serializers.SerializerMethodField()
    unread_count = serializers.SerializerMethodField()
    interlocuteur = serializers.SerializerMethodField()

    class Meta:
        model = Conversation
        fields = ['id', 'name', 'conversation_type', 'created_at', 'updated_at',
                 'last_activity', 'is_active', 'participants', 'last_message', 'unread_count', 'interlocuteur']
        read_only_fields = ['id', 'created_at', 'updated_at']

    def get_last_message(self, obj):
        last_message = obj.messages.filter(is_deleted=False).last()
        if last_message:
            return MessageSerializer(last_message).data
        return None

    def get_unread_count(self, obj):
        user = self.context.get('user')
        if not user or not user.is_authenticated:
            return 0

        participant = obj.participants.filter(participant=user).first()
        if not participant:
            return 0

        # Nouvelle logique : compter les messages qui ne sont PAS dans MessageRead
        # et qui ont été créés après last_read_at (ou tous si last_read_at est None)

        # Base query : messages de la conversation, excluant les propres messages et les supprimés
        # ET ne comptant que les messages textuels
        base_query = obj.messages.filter(
            is_deleted=False,
            message_type='text'  # Ne compter que les messages textuels
        ).exclude(sender=user)

        # Si l'utilisateur n'a pas de last_read_at, tous les messages sont non lus
        if not participant.last_read_at:
            unread_from_timestamp = base_query
        else:
            # Messages créés après le dernier moment de lecture
            unread_from_timestamp = base_query.filter(
                created_at__gt=participant.last_read_at
            )

        # Soustraire les messages explicitement marqués comme lus dans MessageRead
        from .models import MessageRead
        read_message_ids = MessageRead.objects.filter(
            participant=user,
            message__conversation=obj
        ).values_list('message_id', flat=True)

        # Compter les messages non lus = messages après last_read_at MOINS ceux explicitement lus
        unread_count = unread_from_timestamp.exclude(
            id__in=read_message_ids
        ).count()

        return unread_count

    def get_interlocuteur(self, obj):
        """Pour les conversations privées, retourne l'autre participant"""
        user = self.context.get('user')
        if not user or not user.is_authenticated or obj.conversation_type != 'private':
            return None

        # Trouver l'autre participant (pas l'utilisateur actuel)
        other_participant = obj.participants.filter(is_active=True).exclude(participant=user).first()
        if other_participant:
            return ProfileSimpleSerializer(other_participant.participant).data
        return None

class ConversationCreateSerializer(serializers.ModelSerializer):
    """Sérialiseur pour créer une conversation"""
    participant_ids = serializers.ListField(
        child=serializers.IntegerField(),
        write_only=True
    )

    class Meta:
        model = Conversation
        fields = ['name', 'conversation_type', 'participant_ids']

    def create(self, validated_data):
        participant_ids = validated_data.pop('participant_ids')
        conversation_type = validated_data.get('conversation_type', 'private')

        # Pour les conversations privées, ne pas utiliser de nom spécifique
        # Le nom sera géré côté frontend en affichant le nom de l'interlocuteur
        if conversation_type == 'private':
            validated_data['name'] = None

        conversation = super().create(validated_data)

        # Ajouter les participants
        participants = []
        for participant_id in participant_ids:
            try:
                participant = Profile.objects.get(id=participant_id)
                ConversationParticipant.objects.create(
                    conversation=conversation,
                    participant=participant
                )
                participants.append(participant)
            except Profile.DoesNotExist:
                continue

        # Notifier les participants via WebSocket de la nouvelle conversation
        try:
            from channels.layers import get_channel_layer
            from asgiref.sync import async_to_sync

            channel_layer = get_channel_layer()
            if channel_layer:
                # Envoyer à chaque participant avec le bon contexte
                for participant in participants:
                    # Sérialiser la conversation avec le contexte de ce participant
                    conversation_data = ConversationSerializer(conversation, context={'user': participant}).data

                    async_to_sync(channel_layer.group_send)(
                        f'user_{participant.id}',
                        {
                            'type': 'new_conversation_notification',
                            'conversation': conversation_data
                        }
                    )
        except Exception as e:
            # Log l'erreur mais ne pas interrompre la création de la conversation
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Erreur lors de la notification WebSocket de nouvelle conversation: {str(e)}")

        return conversation

# Ancien sérialiseur conservé pour compatibilité
class MessageLegacySerializer(serializers.ModelSerializer):
    destinataire_profil = serializers.SerializerMethodField()
    emetteur_profil = serializers.SerializerMethodField()
    class Meta:
        model = Messagerie
        fields = '__all__'
        read_only_fields = ['date_envoi']

    def get_destinataire_profil(self, obj):
        return obj.destinataire.email

    def get_emetteur_profil(self, obj):
        return obj.emetteur.email