"""
sessions/models.py
===================
Modelos para sesiones en vivo (clase y exposición), preguntas activadas,
respuestas de alumnos y preguntas de alumnos al docente.

Tipos de sesión:
  - 'clase':      sesión normal con preguntas del docente
  - 'exposicion': sesión donde grupos exponen y el público hace preguntas

La sesión es el corazón de la plataforma — conecta docente, alumnos,
preguntas y gamificación en tiempo real.
"""

from django.db import models
from django.conf import settings
from django.utils import timezone

from shared.mixins import TimestampedModel
from academic.models import Seccion, ActividadExposicion, Grupo
from questions.models import Pregunta


class Sesion(TimestampedModel):
    """
    Sesión de clase en vivo.
    
    Una sesión tiene un ciclo de vida:
      pendiente → activa → cerrada
    
    Durante 'activa' los alumnos pueden:
      - Responder preguntas activadas por el docente
      - Enviar dudas al docente
      - Ver el ranking en tiempo real
    
    Al 'cerrar' se genera automáticamente el acta de la sesión.
    """

    class Tipo(models.TextChoices):
        CLASE      = 'clase',      'Clase normal'
        EXPOSICION = 'exposicion', 'Sesión de exposición'

    class Estado(models.TextChoices):
        ESPERANDO = 'esperando', 'Esperando alumnos'
        ACTIVA    = 'activa',    'Activa'
        CERRADA   = 'cerrada',   'Cerrada'

    # ── Relaciones ──
    seccion = models.ForeignKey(
        Seccion,
        on_delete=models.CASCADE,
        related_name='sesiones',
        verbose_name='Sección'
    )
    docente = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='sesiones_creadas',
        verbose_name='Docente'
    )

    # ── Datos de la sesión ──
    titulo   = models.CharField(max_length=200, verbose_name='Título')
    tipo     = models.CharField(max_length=12, choices=Tipo.choices, default=Tipo.CLASE)
    estado   = models.CharField(max_length=10, choices=Estado.choices, default=Estado.ESPERANDO)

    # ── Fechas de ciclo de vida ──
    abierta_en = models.DateTimeField(null=True, blank=True, verbose_name='Abierta en')
    cerrada_en = models.DateTimeField(null=True, blank=True, verbose_name='Cerrada en')

    # ── Gamificación: temporada activa durante la sesión ──
    temporada = models.ForeignKey(
        'gamification.Temporada',
        null=True, blank=True,
        on_delete=models.SET_NULL,
        related_name='sesiones',
        verbose_name='Temporada'
    )

    # ── Para sesiones de exposición ──
    actividad_exposicion = models.ForeignKey(
        ActividadExposicion,
        null=True, blank=True,
        on_delete=models.SET_NULL,
        related_name='sesiones',
        verbose_name='Actividad de exposición'
    )
    grupo_activo = models.ForeignKey(
        Grupo,
        null=True, blank=True,
        on_delete=models.SET_NULL,
        related_name='sesiones_activas',
        verbose_name='Grupo exponiendo actualmente'
    )

    # ── Lista de preguntas preseleccionadas para la sesión ──
    preguntas_seleccionadas = models.ManyToManyField(
        Pregunta,
        through='PreguntaSesion',
        related_name='sesiones',
        blank=True,
        verbose_name='Preguntas de la sesión'
    )

    class Meta(TimestampedModel.Meta):
        verbose_name = 'Sesión'
        verbose_name_plural = 'Sesiones'
        db_table = 'sessions_sesion'
        indexes = [
            models.Index(fields=['seccion', 'estado']),
            models.Index(fields=['docente', 'estado']),
        ]

    def __str__(self):
        return f'{self.titulo} [{self.estado}]'

    def abrir(self):
        """Cambia el estado a 'activa' y registra la hora de apertura."""
        self.estado     = self.Estado.ACTIVA
        self.abierta_en = timezone.now()
        self.save(update_fields=['estado', 'abierta_en'])

    def cerrar(self):
        """
        Cierra la sesión y registra la hora.
        Post-cierre: el signal dispara generación del acta.
        """
        self.estado    = self.Estado.CERRADA
        self.cerrada_en = timezone.now()
        self.save(update_fields=['estado', 'cerrada_en'])

    @property
    def duracion_minutos(self) -> int | None:
        """Duración de la sesión en minutos. None si no está cerrada."""
        if self.abierta_en and self.cerrada_en:
            delta = self.cerrada_en - self.abierta_en
            return int(delta.total_seconds() / 60)
        return None


class PreguntaSesion(TimestampedModel):
    """
    Tabla intermedia entre Sesion y Pregunta.
    Agrega el orden de la pregunta en la sesión.
    """

    sesion   = models.ForeignKey(Sesion, on_delete=models.CASCADE)
    pregunta = models.ForeignKey(Pregunta, on_delete=models.CASCADE)
    orden    = models.PositiveSmallIntegerField(default=0, verbose_name='Orden')

    class Meta:
        unique_together = [['sesion', 'pregunta']]
        ordering = ['orden']
        db_table = 'sessions_preguntasesion'


class PreguntaActiva(TimestampedModel):
    """
    Pregunta que el docente activó durante una sesión.
    Existe durante el tiempo de respuesta y se cierra al vencer el tiempo.
    
    Es el centro del flujo en tiempo real:
      docente.activar_pregunta() → crea PreguntaActiva → WebSocket push a alumnos
      tiempo vence → estado='cerrada' → se calculan puntos
    """

    class Estado(models.TextChoices):
        ACTIVA  = 'activa',  'Activa (recibiendo respuestas)'
        CERRADA = 'cerrada', 'Cerrada'

    sesion   = models.ForeignKey(
        Sesion,
        on_delete=models.CASCADE,
        related_name='preguntas_activas'
    )
    pregunta = models.ForeignKey(
        Pregunta,
        on_delete=models.CASCADE,
        related_name='activaciones'
    )
    orden       = models.PositiveSmallIntegerField(default=0)
    estado      = models.CharField(max_length=10, choices=Estado.choices, default=Estado.ACTIVA)
    activada_en = models.DateTimeField(auto_now_add=True)
    expira_en   = models.DateTimeField(verbose_name='Expira en')

    class Meta(TimestampedModel.Meta):
        verbose_name = 'Pregunta activa'
        verbose_name_plural = 'Preguntas activas'
        db_table = 'sessions_preguntaactiva'
        indexes = [models.Index(fields=['sesion', 'estado'])]

    def __str__(self):
        return f'PreguntaActiva {self.id} [{self.estado}] en sesión {self.sesion_id}'

    @property
    def tiempo_restante_ms(self) -> int:
        """Milisegundos restantes. 0 si ya expiró."""
        delta = (self.expira_en - timezone.now()).total_seconds()
        return max(0, int(delta * 1000))

    def cerrar(self):
        """Cierra la pregunta. El estado no puede volver a 'activa'."""
        self.estado = self.Estado.CERRADA
        self.save(update_fields=['estado'])


class Respuesta(TimestampedModel):
    """
    Respuesta de un alumno a una PreguntaActiva.
    
    Una respuesta por alumno por pregunta activa.
    Se valida el tiempo en el servidor — el frontend no puede mentir
    porque se calcula desde activada_en y el timestamp de la respuesta.
    
    Seguridad anti-trampa:
      - es_sospechosa: True si el tiempo_ms es demasiado pequeño para
        preguntas de respuesta corta o desarrollo
      - El middleware RateLimit previene múltiples respuestas del mismo usuario
    """

    pregunta_activa = models.ForeignKey(
        PreguntaActiva,
        on_delete=models.CASCADE,
        related_name='respuestas'
    )
    alumno = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='respuestas'
    )

    # ── Contenido de la respuesta (según tipo de pregunta) ──
    # Para múltiple: índice de la opción elegida
    opcion_elegida = models.PositiveSmallIntegerField(null=True, blank=True)
    # Para V/F: true/false
    respuesta_vf   = models.BooleanField(null=True, blank=True)
    # Para corta/confuso/minuto: texto libre
    texto_respuesta = models.TextField(blank=True)
    # Para arrastrar: JSON con el orden/asociación elegido
    respuesta_json = models.JSONField(null=True, blank=True)

    # ── Evaluación ──
    es_correcta   = models.BooleanField(null=True, blank=True)
    puntos        = models.SmallIntegerField(default=0)

    # ── Tiempo de respuesta (calculado en servidor) ──
    # Tiempo en ms desde que se activó la pregunta hasta que llegó la respuesta
    tiempo_ms = models.PositiveIntegerField(
        default=0,
        verbose_name='Tiempo de respuesta (ms)',
        help_text='Calculado en el servidor: timestamp_respuesta - activada_en'
    )

    # ── Anti-trampa ──
    es_sospechosa = models.BooleanField(
        default=False,
        verbose_name='Respuesta sospechosa',
        help_text='True si el tiempo de respuesta fue anormalmente rápido'
    )

    class Meta(TimestampedModel.Meta):
        verbose_name = 'Respuesta'
        verbose_name_plural = 'Respuestas'
        db_table = 'sessions_respuesta'
        # Un alumno solo puede responder una vez por pregunta activa
        unique_together = [['pregunta_activa', 'alumno']]
        indexes = [models.Index(fields=['pregunta_activa', 'alumno'])]

    def __str__(self):
        return f'Respuesta de alumno {self.alumno_id} a PA {self.pregunta_activa_id}'


class DudaAlumno(TimestampedModel):
    """
    Pregunta/duda enviada por un alumno durante una sesión.
    El docente puede verla, destacarla y responderla.
    La respuesta queda guardada en el FAQ de la asignatura.
    
    Privacidad:
      - Si es_anonima=True: otros alumnos no ven quién la envió
      - El docente SIEMPRE ve quién la envió (is_anonima no oculta nada al docente)
    """

    sesion = models.ForeignKey(
        Sesion,
        on_delete=models.CASCADE,
        related_name='dudas'
    )
    alumno = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='dudas'
    )
    texto      = models.TextField(verbose_name='Texto de la duda')
    es_anonima = models.BooleanField(
        default=False,
        verbose_name='Anónima para compañeros',
        help_text='El docente siempre ve el autor. Los compañeros no si es True.'
    )
    votos      = models.PositiveSmallIntegerField(default=0, verbose_name='Upvotes')
    destacada  = models.BooleanField(
        default=False,
        verbose_name='Destacada por docente',
        help_text='Al destacar, el alumno recibe la insignia FILOSOFO'
    )
    respondida  = models.BooleanField(default=False)
    respuesta_docente = models.TextField(
        blank=True,
        verbose_name='Respuesta del docente',
        help_text='Si tiene respuesta, se agrega automáticamente al FAQ'
    )

    # Para sesiones de exposición: la duda va dirigida al grupo expositor
    grupo_destino = models.ForeignKey(
        Grupo,
        null=True, blank=True,
        on_delete=models.SET_NULL,
        related_name='dudas_recibidas',
        verbose_name='Grupo al que va dirigida (exposición)'
    )
    visible_para_grupo = models.BooleanField(
        default=False,
        verbose_name='Visible para el grupo expositor',
        help_text='El docente activa esto para mostrarla al grupo que expone'
    )

    class Meta(TimestampedModel.Meta):
        verbose_name = 'Duda de alumno'
        verbose_name_plural = 'Dudas de alumnos'
        db_table = 'sessions_dudaalumno'
        ordering = ['-votos', '-created_at']

    def __str__(self):
        return f'Duda de {self.alumno_id} en sesión {self.sesion_id}'
