"""
questions/serializers.py
=========================
Serializers del banco de preguntas.
Incluye validación específica según el tipo de pregunta.
"""

import hashlib
import json
from rest_framework import serializers
from questions.models import Pregunta, ImportacionPreguntas
from shared.serializers.base import TimestampedSerializer
from shared.validators.fields import validate_json_question


class PreguntaSerializer(TimestampedSerializer):
    """Serializer de lectura/escritura de preguntas con validación por tipo."""

    class Meta:
        model  = Pregunta
        fields = [
            'id', 'asignatura', 'tipo', 'enunciado', 'unidad', 'tiempo_seg',
            'es_publica', 'valoraciones',
            # Campos opcionales según tipo:
            'opciones', 'correcta_vf', 'palabras_clave', 'pares', 'modo_arrastrar',
            'created_at', 'updated_at',
        ]
        read_only_fields = ['id', 'docente', 'valoraciones', 'created_at', 'updated_at']

    def validate(self, attrs):
        """Validación cruzada según el tipo de pregunta."""
        tipo = attrs.get('tipo') or (self.instance.tipo if self.instance else None)

        if tipo == 'multiple':
            opciones = attrs.get('opciones', [])
            if not opciones or len(opciones) < 2:
                raise serializers.ValidationError({
                    'opciones': 'Se requieren al menos 2 opciones para preguntas de selección múltiple.'
                })
            correctas = [o for o in opciones if o.get('correcta', False)]
            if len(correctas) != 1:
                raise serializers.ValidationError({
                    'opciones': 'Debe haber exactamente una opción marcada como correcta.'
                })

        elif tipo == 'vf':
            if attrs.get('correcta_vf') is None:
                raise serializers.ValidationError({
                    'correcta_vf': 'Se requiere indicar la respuesta correcta (verdadero/falso).'
                })

        elif tipo == 'corta':
            clave = attrs.get('palabras_clave', [])
            if not clave:
                raise serializers.ValidationError({
                    'palabras_clave': 'Se requiere al menos una palabra clave para respuesta corta.'
                })

        elif tipo == 'arrastrar':
            pares = attrs.get('pares', [])
            if not pares or len(pares) < 2:
                raise serializers.ValidationError({
                    'pares': 'Se requieren al menos 2 pares/elementos para arrastrar y soltar.'
                })
            if not attrs.get('modo_arrastrar'):
                raise serializers.ValidationError({
                    'modo_arrastrar': 'Debes especificar el modo: "asociar" u "ordenar".'
                })

        return attrs


class ImportarPreguntasSerializer(serializers.Serializer):
    """
    Serializer para la importación masiva de preguntas desde JSON.
    Valida el formato completo antes de importar cualquier pregunta.
    """

    archivo_json = serializers.JSONField()
    asignatura   = serializers.PrimaryKeyRelatedField(
        queryset=__import__('academic.models', fromlist=['Asignatura']).Asignatura.objects.all()
    )

    def validate_archivo_json(self, value):
        """Valida el formato JSON usando el validator compartido."""
        try:
            validate_json_question(value)
        except Exception as e:
            raise serializers.ValidationError(str(e))
        return value

    def validate(self, attrs):
        """Verificar que la asignatura pertenece al docente."""
        request = self.context.get('request')
        asignatura = attrs.get('asignatura')
        if request and asignatura and asignatura.owner != request.user:
            raise serializers.ValidationError({
                'asignatura': 'No puedes importar preguntas en asignaturas de otros docentes.'
            })
        return attrs

    def save(self, docente):
        """
        Procesa la importación:
          1. Calcular hash del JSON para detectar duplicados
          2. Iterar preguntas y crear las válidas
          3. Registrar la importación con log de errores
        
        Returns: ImportacionPreguntas con el resultado
        """
        data        = self.validated_data['archivo_json']
        asignatura  = self.validated_data['asignatura']
        preguntas   = data.get('preguntas', [])
        unidad      = data.get('unidad', '')

        # Hash del contenido para detectar re-importaciones
        json_str   = json.dumps(data, sort_keys=True, ensure_ascii=False)
        archivo_hash = hashlib.sha256(json_str.encode()).hexdigest()

        ok, errores_log = 0, []

        for i, p in enumerate(preguntas):
            try:
                pregunta = Pregunta(
                    asignatura  = asignatura,
                    docente     = docente,
                    tipo        = p['tipo'],
                    enunciado   = p['enunciado'],
                    unidad      = unidad,
                    tiempo_seg  = p.get('tiempo_segundos', 20),
                    es_publica  = p.get('publica', False),
                )

                # Mapear campos según tipo
                if p['tipo'] == 'multiple':
                    pregunta.opciones = p.get('opciones', [])
                elif p['tipo'] == 'vf':
                    pregunta.correcta_vf = p.get('correcta', False)
                elif p['tipo'] == 'corta':
                    claves = p.get('palabras_clave', [])
                    pregunta.palabras_clave = claves if isinstance(claves, list) else [claves]
                elif p['tipo'] == 'arrastrar':
                    pregunta.pares = p.get('pares', [])
                    pregunta.modo_arrastrar = p.get('modo', 'asociar')

                pregunta.full_clean()
                pregunta.save()
                ok += 1

            except Exception as e:
                errores_log.append(f'Pregunta {i+1}: {str(e)}')

        # Registrar la importación
        return ImportacionPreguntas.objects.create(
            docente       = docente,
            asignatura    = asignatura,
            archivo_hash  = archivo_hash,
            preguntas_ok  = ok,
            preguntas_err = len(errores_log),
            log_errores   = '\n'.join(errores_log),
        )
