"""
sessions/serializers.py
========================
Serializers de sesiones, preguntas activas, respuestas y dudas.

Principio de mínima exposición:
  Los serializers de respuestas NO devuelven la opción correcta
  mientras la pregunta está activa — solo después de cerrarla.
  Esto evita filtrar la respuesta por la red antes de tiempo.
"""

from rest_framework import serializers
from django.utils import timezone

from sessions.models import Sesion, PreguntaSesion, PreguntaActiva, Respuesta, DudaAlumno
from questions.models import Pregunta
from shared.serializers.base import TimestampedSerializer, ReadOnlyModelSerializer


class SesionCreateSerializer(serializers.ModelSerializer):
    """Crear una nueva sesión de clase o exposición."""

    class Meta:
        model  = Sesion
        fields = [
            'id', 'seccion', 'titulo', 'tipo',
            'actividad_exposicion', 'temporada',
        ]
        read_only_fields = ['id']

    def validate(self, attrs):
        # Si es exposición, debe tener actividad_exposicion
        if attrs.get('tipo') == 'exposicion' and not attrs.get('actividad_exposicion'):
            raise serializers.ValidationError({
                'actividad_exposicion': 'Las sesiones de exposición requieren una actividad asociada.'
            })
        return attrs


class SesionSerializer(TimestampedSerializer):
    """Lectura de sesión con información resumida."""
    docente_nickname = serializers.CharField(source='docente.nickname', read_only=True)
    duracion_minutos = serializers.IntegerField(read_only=True)

    class Meta:
        model  = Sesion
        fields = [
            'id', 'seccion', 'docente', 'docente_nickname',
            'titulo', 'tipo', 'estado',
            'abierta_en', 'cerrada_en', 'duracion_minutos',
            'temporada', 'actividad_exposicion', 'grupo_activo',
            'created_at',
        ]
        read_only_fields = ['id', 'docente', 'estado', 'abierta_en', 'cerrada_en', 'created_at']


class PreguntaActivaPublicaSerializer(serializers.ModelSerializer):
    """
    Pregunta activa enviada al alumno por WebSocket / polling.
    NO incluye la respuesta correcta — eso va en PreguntaActivaResultadoSerializer.
    """
    enunciado   = serializers.CharField(source='pregunta.enunciado')
    tipo        = serializers.CharField(source='pregunta.tipo')
    tiempo_seg  = serializers.IntegerField(source='pregunta.tiempo_seg')
    tiempo_restante_ms = serializers.IntegerField(read_only=True)

    # Para múltiple: opciones sin marcar cuál es correcta
    opciones = serializers.SerializerMethodField()

    class Meta:
        model  = PreguntaActiva
        fields = [
            'id', 'sesion', 'orden',
            'enunciado', 'tipo', 'tiempo_seg', 'tiempo_restante_ms',
            'opciones',
            # Para arrastrar: pares mezclados aleatoriamente
        ]

    def get_opciones(self, obj) -> list:
        """Retorna opciones sin la bandera 'correcta'."""
        raw = obj.pregunta.opciones or []
        return [{'texto': o.get('texto', '')} for o in raw]


class PreguntaActivaResultadoSerializer(PreguntaActivaPublicaSerializer):
    """
    Extiende la pública con la respuesta correcta.
    Solo se usa DESPUÉS de cerrar la pregunta.
    """
    opciones_con_respuesta = serializers.SerializerMethodField()
    correcta_vf     = serializers.BooleanField(source='pregunta.correcta_vf')
    palabras_clave  = serializers.JSONField(source='pregunta.palabras_clave')
    pares           = serializers.JSONField(source='pregunta.pares')

    class Meta(PreguntaActivaPublicaSerializer.Meta):
        fields = PreguntaActivaPublicaSerializer.Meta.fields + [
            'opciones_con_respuesta', 'correcta_vf', 'palabras_clave', 'pares'
        ]

    def get_opciones_con_respuesta(self, obj) -> list:
        return obj.pregunta.opciones or []


class EnviarRespuestaSerializer(serializers.Serializer):
    """
    Validación de la respuesta enviada por el alumno.
    Los campos opcionales dependen del tipo de pregunta.
    """
    pregunta_activa_id = serializers.IntegerField()
    opcion_elegida     = serializers.IntegerField(required=False, allow_null=True)
    respuesta_vf       = serializers.BooleanField(required=False, allow_null=True)
    texto_respuesta    = serializers.CharField(required=False, allow_blank=True, default='')
    respuesta_json     = serializers.JSONField(required=False, allow_null=True)

    def validate_pregunta_activa_id(self, value):
        try:
            pa = PreguntaActiva.objects.select_related('pregunta', 'sesion').get(
                pk=value, estado='activa'
            )
        except PreguntaActiva.DoesNotExist:
            raise serializers.ValidationError('Pregunta no activa o no encontrada.')

        # Verificar que no expiró
        if pa.tiempo_restante_ms == 0:
            raise serializers.ValidationError('El tiempo de esta pregunta ya venció.')

        self.context['pregunta_activa'] = pa
        return value

    def validate(self, attrs):
        pa   = self.context.get('pregunta_activa')
        tipo = pa.pregunta.tipo if pa else None

        if tipo == 'multiple' and attrs.get('opcion_elegida') is None:
            raise serializers.ValidationError({'opcion_elegida': 'Requerido para selección múltiple.'})
        if tipo == 'vf' and attrs.get('respuesta_vf') is None:
            raise serializers.ValidationError({'respuesta_vf': 'Requerido para verdadero/falso.'})
        if tipo in ('corta', 'confuso', 'minuto') and not attrs.get('texto_respuesta', '').strip():
            raise serializers.ValidationError({'texto_respuesta': 'Requerido para este tipo de pregunta.'})
        if tipo == 'arrastrar' and not attrs.get('respuesta_json'):
            raise serializers.ValidationError({'respuesta_json': 'Requerido para arrastrar y soltar.'})

        return attrs


class RespuestaSerializer(ReadOnlyModelSerializer):
    class Meta:
        model  = Respuesta
        fields = [
            'id', 'pregunta_activa', 'alumno',
            'opcion_elegida', 'respuesta_vf', 'texto_respuesta', 'respuesta_json',
            'es_correcta', 'puntos', 'tiempo_ms', 'es_sospechosa',
            'created_at',
        ]


class DudaAlumnoSerializer(TimestampedSerializer):
    """
    Serializer de dudas. Respeta la privacidad del autor si es_anonima=True.
    El docente siempre ve el autor; los compañeros no si es anónima.
    """
    autor_visible = serializers.SerializerMethodField()

    class Meta:
        model  = DudaAlumno
        fields = [
            'id', 'sesion', 'autor_visible', 'texto',
            'es_anonima', 'votos', 'destacada',
            'respondida', 'respuesta_docente',
            'grupo_destino', 'visible_para_grupo',
            'created_at',
        ]
        read_only_fields = [
            'id', 'votos', 'destacada', 'respondida',
            'respuesta_docente', 'visible_para_grupo', 'created_at',
        ]

    def get_autor_visible(self, obj) -> dict | None:
        """
        Si es anónima y el solicitante es alumno → None.
        Si es docente → siempre retorna el autor.
        """
        request = self.context.get('request')
        if request and request.user.role == 'docente':
            return {'id': obj.alumno_id, 'nickname': obj.alumno.nickname}
        if obj.es_anonima:
            return None
        return {'id': obj.alumno_id, 'nickname': obj.alumno.nickname}


class EnviarDudaSerializer(serializers.Serializer):
    """Alumno envía una duda durante la sesión."""
    sesion_id      = serializers.IntegerField()
    texto          = serializers.CharField(min_length=3, max_length=500)
    es_anonima     = serializers.BooleanField(default=False)
    grupo_destino_id = serializers.IntegerField(required=False, allow_null=True)

    def validate_sesion_id(self, value):
        try:
            sesion = Sesion.objects.get(pk=value, estado='activa')
        except Sesion.DoesNotExist:
            raise serializers.ValidationError('Sesión no activa.')
        self.context['sesion'] = sesion
        return value


class ResponderDudaSerializer(serializers.Serializer):
    """Docente responde una duda y opcionalmente la agrega al FAQ."""
    respuesta      = serializers.CharField(min_length=3, max_length=2000)
    agregar_al_faq = serializers.BooleanField(default=True)
