from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.permissions import IsAuthenticated
from django.db import models
from .models import  Conversation, ConversationParticipant, Message, UserPresence
from Auth.models import Profile, ProfileRole
from GestionMessagerie.serializers import (
    ConversationSerializer, MessageSerializer,
    ConversationCreateSerializer, UserPresenceSerializer,
    ProfileSimpleSerializer
)
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from django.utils import timezone
import os
import uuid
import logging
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.db.models import Q

logger = logging.getLogger(__name__)

# ====================== MESSAGERIE INSTANTANÉE ======================

class InstantConversationListView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour lister les conversations instantanées d'un utilisateur
    """
    @swagger_auto_schema(
        operation_description="Liste les conversations instantanées d'un utilisateur",
        responses={200: ConversationSerializer(many=True)}
    )
    def get(self, request, user_id=None):
        try:
            # Utiliser l'utilisateur authentifié — ignorer user_id de l'URL (protection IDOR)
            user = request.user

            conversations = Conversation.objects.filter(
                participants__participant=user,
                participants__is_active=True,
                is_active=True
            ).distinct().order_by('-last_activity')

            serializer = ConversationSerializer(conversations, many=True, context={'user': user})
            return Response(serializer.data, status=status.HTTP_200_OK)
        except Profile.DoesNotExist:
            return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class InstantConversationCreateView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour créer une nouvelle conversation instantanée
    """
    @swagger_auto_schema(
        operation_description="Crée une nouvelle conversation instantanée",
        request_body=ConversationCreateSerializer,
        responses={201: ConversationSerializer}
    )
    def post(self, request):
        serializer = ConversationCreateSerializer(data=request.data)
        if serializer.is_valid():
            conversation = serializer.save()
            response_serializer = ConversationSerializer(conversation, context={'user': request.user})
            return Response(response_serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class InstantMessageListView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour lister les messages d'une conversation
    """
    @swagger_auto_schema(
        operation_description="Liste les messages d'une conversation",
        responses={200: MessageSerializer(many=True)}
    )
    def get(self, request, conversation_id):
        try:
            conversation = Conversation.objects.get(id=conversation_id)
            messages = conversation.messages.filter(is_deleted=False).order_by('created_at')

            # Utiliser l'utilisateur authentifié — ignorer user_id du paramètre (protection IDOR)
            user = request.user

            serializer = MessageSerializer(messages, many=True, context={'user': user})
            return Response(serializer.data, status=status.HTTP_200_OK)
        except Conversation.DoesNotExist:
            return Response({'error': 'Conversation not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception:
            return Response({'error': 'Erreur interne du serveur'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class InstantMessageCreateView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour envoyer un nouveau message instantané
    """
    @swagger_auto_schema(
        operation_description="Envoie un nouveau message instantané",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'conversation_id': openapi.Schema(type=openapi.TYPE_STRING, description='ID de la conversation'),
                'sender_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='ID de l\'expéditeur'),
                'content': openapi.Schema(type=openapi.TYPE_STRING, description='Contenu du message'),
                'message_type': openapi.Schema(type=openapi.TYPE_STRING, description='Type de message', default='text')
            },
            required=['conversation_id', 'sender_id', 'content']
        ),
        responses={201: MessageSerializer}
    )
    def post(self, request):
        try:
            conversation_id = request.data.get('conversation_id')
            content = request.data.get('content', '').strip()
            message_type = request.data.get('message_type', 'text')

            if not all([conversation_id, content]):
                return Response(
                    {'error': 'conversation_id and content are required'},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # Vérifier que la conversation existe
            conversation = Conversation.objects.get(id=conversation_id)

            # L'expéditeur est toujours l'utilisateur authentifié (protection IDOR)
            sender = request.user
            participant = ConversationParticipant.objects.filter(
                conversation=conversation,
                participant=sender,
                is_active=True
            ).first()

            if not participant:
                return Response(
                    {'error': 'You are not a participant in this conversation'},
                    status=status.HTTP_403_FORBIDDEN
                )

            # Récupérer les données de fichier si disponibles
            file_url = request.data.get('file_url')
            file_name = request.data.get('file_name')
            file_type = request.data.get('file_type')
            file_size = request.data.get('file_size')

            # Créer le message
            message = Message.objects.create(
                conversation=conversation,
                sender=sender,
                content=content,
                message_type=message_type,
                file_url=file_url,
                file_name=file_name,
                file_type=file_type,
                file_size=file_size
            )

            # Mettre à jour l'activité de la conversation
            conversation.last_activity = message.created_at
            conversation.save(update_fields=['last_activity'])

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

        except Conversation.DoesNotExist:
            return Response({'error': 'Conversation not found'}, status=status.HTTP_404_NOT_FOUND)
        except Profile.DoesNotExist:
            return Response({'error': 'Sender not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception:
            return Response({'error': 'Erreur interne du serveur'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class InstantMarkAsReadView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour marquer une conversation comme lue
    """
    @swagger_auto_schema(
        operation_description="Marque une conversation comme lue pour un utilisateur",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='ID de l\'utilisateur')
            },
            required=['user_id']
        ),
        responses={200: openapi.Response('Success')}
    )
    def post(self, request):
        try:
            # Utiliser l'utilisateur authentifié — ignorer user_id du body (protection IDOR)
            # conversation_id est lu depuis le body (pas depuis l'URL)
            conversation_id = request.data.get('conversation_id')
            if not conversation_id:
                return Response({'error': 'conversation_id requis'}, status=status.HTTP_400_BAD_REQUEST)
            participant = ConversationParticipant.objects.get(
                conversation_id=conversation_id,
                participant=request.user,
                is_active=True
            )

            participant.last_read_at = timezone.now()
            participant.save(update_fields=['last_read_at'])

            return Response({'status': 'success'}, status=status.HTTP_200_OK)

        except ConversationParticipant.DoesNotExist:
            return Response({'error': 'Participant not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception:
            return Response({'error': 'Erreur interne du serveur'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class UserPresenceView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour gérer la présence des utilisateurs
    """
    @swagger_auto_schema(
        operation_description="Met à jour le statut de présence d'un utilisateur",
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'status': openapi.Schema(type=openapi.TYPE_STRING, description='Statut de présence')
            },
            required=['status']
        ),
        responses={200: UserPresenceSerializer}
    )
    def post(self, request, user_id):
        try:
            user = Profile.objects.get(id=user_id)
            status_value = request.data.get('status')

            if status_value not in ['online', 'away', 'busy', 'offline']:
                return Response({'error': 'Invalid status'}, status=status.HTTP_400_BAD_REQUEST)

            presence, created = UserPresence.objects.get_or_create(user=user)
            presence.status = status_value
            presence.last_seen = timezone.now()
            presence.save()

            serializer = UserPresenceSerializer(presence)
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Profile.DoesNotExist:
            return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception:
            return Response({'error': 'Erreur interne du serveur'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @swagger_auto_schema(
        operation_description="Récupère le statut de présence d'un utilisateur",
        responses={200: UserPresenceSerializer}
    )
    def get(self, request, user_id):
        try:
            user = Profile.objects.get(id=user_id)
            presence, created = UserPresence.objects.get_or_create(user=user)

            if created:
                presence.status = 'offline'
                presence.save()

            serializer = UserPresenceSerializer(presence)
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Profile.DoesNotExist:
            return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)
        except Exception:
            return Response({'error': 'Erreur interne du serveur'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class FileUploadView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour l'upload de fichiers dans la messagerie instantanée
    """
    parser_classes = (MultiPartParser, FormParser)

    @swagger_auto_schema(
        operation_description="Upload un fichier pour la messagerie",
        manual_parameters=[
            openapi.Parameter('file', openapi.IN_FORM, description="Fichier à uploader", type=openapi.TYPE_FILE, required=True),
            openapi.Parameter('conversation_id', openapi.IN_FORM, description="ID de la conversation", type=openapi.TYPE_INTEGER, required=True),
            openapi.Parameter('sender_id', openapi.IN_FORM, description="ID de l'expéditeur", type=openapi.TYPE_INTEGER, required=True),
        ],
        responses={
            200: openapi.Response('Success', openapi.Schema(
                type=openapi.TYPE_OBJECT,
                properties={
                    'fileUrl': openapi.Schema(type=openapi.TYPE_STRING),
                    'fileName': openapi.Schema(type=openapi.TYPE_STRING),
                    'fileSize': openapi.Schema(type=openapi.TYPE_INTEGER),
                    'fileType': openapi.Schema(type=openapi.TYPE_STRING),
                }
            )),
            400: 'Bad Request',
            413: 'File too large',
            415: 'Unsupported file type'
        }
    )
    def post(self, request):
        try:
            file = request.FILES.get('file')
            conversation_id = request.data.get('conversation_id')

            if not file:
                return Response({'error': 'Aucun fichier fourni'}, status=status.HTTP_400_BAD_REQUEST)

            if not conversation_id:
                return Response({'error': 'conversation_id requis'}, status=status.HTTP_400_BAD_REQUEST)

            # Vérifier que la conversation existe et que l'utilisateur authentifié y participe (protection IDOR)
            try:
                conversation = Conversation.objects.get(id=conversation_id)
                sender = request.user

                # Vérifier que l'expéditeur participe à la conversation
                if not ConversationParticipant.objects.filter(
                    conversation=conversation,
                    participant=sender,
                    is_active=True
                ).exists():
                    return Response({'error': 'Accès non autorisé à cette conversation'}, status=status.HTTP_403_FORBIDDEN)

            except (Conversation.DoesNotExist, Profile.DoesNotExist):
                return Response({'error': 'Conversation ou utilisateur introuvable'}, status=status.HTTP_404_NOT_FOUND)

            # Valider le type de fichier
            allowed_types = [
                'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp',
                'application/pdf',
                'application/msword',
                'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                'application/vnd.ms-excel',
                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'text/plain'
            ]

            if file.content_type not in allowed_types:
                return Response({'error': 'Type de fichier non autorisé'}, status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)

            # Valider la taille du fichier (10MB max)
            max_size = 10 * 1024 * 1024  # 10MB
            if file.size > max_size:
                return Response({'error': 'Fichier trop volumineux (max 10MB)'}, status=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE)

            # Générer un nom de fichier unique
            file_extension = os.path.splitext(file.name)[1]
            unique_filename = f"{uuid.uuid4()}{file_extension}"

            # Chemin de stockage : messagerie/conversation_id/
            storage_path = f"messagerie/{conversation_id}/{unique_filename}"

            # Sauvegarder le fichier
            file_path = default_storage.save(storage_path, ContentFile(file.read()))

            # Générer l'URL du fichier
            file_url = default_storage.url(file_path)
            if not file_url.startswith('http'):
                # Construire l'URL complète si nécessaire
                file_url = request.build_absolute_uri(file_url)

            return Response({
                'fileUrl': file_url,
                'fileName': file.name,
                'fileSize': file.size,
                'fileType': file.content_type,
                'filePath': file_path
            }, status=status.HTTP_200_OK)

        except Exception:
            return Response({'error': "Erreur lors de l'upload"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class InstantRecipientSearchView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour rechercher des destinataires pour la messagerie instantanée
    """
    @swagger_auto_schema(
        operation_description="Recherche des destinataires pour la messagerie instantanée",
        manual_parameters=[
            openapi.Parameter('establishment_id', openapi.IN_QUERY, description="ID de l'établissement", type=openapi.TYPE_INTEGER, required=True),
            openapi.Parameter('q', openapi.IN_QUERY, description="Terme de recherche", type=openapi.TYPE_STRING, required=True)
        ],
        responses={200: ProfileSimpleSerializer(many=True)}
    )
    def get(self, request):
        try:
            establishment_id = request.query_params.get('establishment_id')
            search_query = request.query_params.get('q', '').strip()

            if not establishment_id:
                return Response({'error': 'establishment_id is required'}, status=status.HTTP_400_BAD_REQUEST)

            # Récupérer les IDs des profils actifs dans l'établissement
            profile_roles = ProfileRole.objects.filter(
                establishment_id=establishment_id,
                is_active=True
            ).values_list('profile_id', flat=True)

            # Rechercher les profils correspondants
            users = Profile.objects.filter(id__in=profile_roles)

            # Appliquer le filtre de recherche si un terme est fourni
            if search_query:
                users = users.filter(
                    Q(first_name__icontains=search_query) |
                    Q(last_name__icontains=search_query) |
                    Q(email__icontains=search_query)
                )

            # Exclure l'utilisateur actuel des résultats
            if request.user.is_authenticated:
                users = users.exclude(id=request.user.id)

            serializer = ProfileSimpleSerializer(users[:10], many=True)  # Limiter à 10 résultats
            return Response(serializer.data, status=status.HTTP_200_OK)

        except Exception as e:
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class InstantConversationDeleteView(APIView):
    permission_classes = [IsAuthenticated]

    """
    API pour supprimer (désactiver) une conversation instantanée
    """
    @swagger_auto_schema(
        operation_description="Supprime une conversation instantanée (désactivation soft)",
        responses={200: openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'success': openapi.Schema(type=openapi.TYPE_BOOLEAN),
                'message': openapi.Schema(type=openapi.TYPE_STRING)
            }
        )}
    )
    def delete(self, request, conversation_id):
        try:
            # Récupérer la conversation par son ID UUID
            conversation = Conversation.objects.filter(id=conversation_id).first()

            if not conversation:
                return Response({'error': 'Conversation not found'}, status=status.HTTP_404_NOT_FOUND)

            # Suppression simple : désactiver la conversation
            conversation.is_active = False
            conversation.save()

            return Response({
                'success': True,
                'message': 'Conversation deleted successfully'
            }, status=status.HTTP_200_OK)

        except Exception as e:
            logger.error(f"Error deleting conversation: {str(e)}")
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

