"""
users/views/users.py
=====================
Vistas de gestión de usuarios: docentes, alumnos, tokens de registro.
"""

import logging
from datetime import timedelta

from django.utils import timezone
from rest_framework.views import APIView
from rest_framework.generics import ListAPIView
from rest_framework import status

from users.models import CustomUser, PerfilDocente, PerfilAlumno, RegistrationToken
from users.serializers.users import (
    DocenteListSerializer,
    AlumnoListSerializer,
    UserProfileSerializer,
)
from academic.models import Seccion, Inscripcion
from shared.permissions import IsAdmin, IsApprovedDocente
from rest_framework.permissions import IsAuthenticated
from shared.utils.responses import success_response, error_response
from shared.utils.tokens import TokenService
from shared.pagination import StandardPagination
from django.conf import settings

logger = logging.getLogger('eduplay')


class MeView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        serializer = UserProfileSerializer(request.user)
        return success_response(data=serializer.data)

    def patch(self, request):
        serializer = UserProfileSerializer(request.user, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return success_response(data=serializer.data, message='Perfil actualizado.')
        return error_response(message='Datos inválidos.', errors=serializer.errors, status_code=400)


class DocenteListView(ListAPIView):
    serializer_class   = DocenteListSerializer
    permission_classes = [IsAdmin]
    pagination_class   = StandardPagination

    def get_queryset(self):
        qs = CustomUser.objects.filter(
            role='docente'
        ).select_related('perfil_docente').order_by('-created_at')

        is_approved = self.request.query_params.get('is_approved')
        if is_approved is not None:
            qs = qs.filter(is_approved=is_approved.lower() == 'true')

        is_active = self.request.query_params.get('is_active')
        if is_active is not None:
            qs = qs.filter(is_active=is_active.lower() == 'true')

        return qs


class DocenteApproveView(APIView):
    permission_classes = [IsAdmin]

    def post(self, request, pk):
        try:
            docente = CustomUser.objects.get(pk=pk, role='docente')
        except CustomUser.DoesNotExist:
            return error_response(message='Docente no encontrado.', status_code=404)

        docente.is_approved = True
        docente.is_active   = True
        docente.save(update_fields=['is_approved', 'is_active'])

        try:
            perfil = docente.perfil_docente
            perfil.aprobado_por = request.user
            perfil.aprobado_en  = timezone.now()
            perfil.save(update_fields=['aprobado_por', 'aprobado_en'])
        except Exception:
            pass

        logger.info(f'Docente id={pk} aprobado por admin id={request.user.id}')
        return success_response(message='Docente aprobado exitosamente.')


class DocenteRejectView(APIView):
    permission_classes = [IsAdmin]

    def post(self, request, pk):
        try:
            docente = CustomUser.objects.get(pk=pk, role='docente')
        except CustomUser.DoesNotExist:
            return error_response(message='Docente no encontrado.', status_code=404)

        motivo = request.data.get('motivo', '')
        docente.is_active = False
        docente.save(update_fields=['is_active'])

        try:
            perfil = docente.perfil_docente
            perfil.motivo_rechazo = motivo
            perfil.save(update_fields=['motivo_rechazo'])
        except Exception:
            pass

        return success_response(message='Solicitud rechazada.')


class AlumnoListView(ListAPIView):
    serializer_class   = AlumnoListSerializer
    permission_classes = [IsAuthenticated]
    pagination_class   = StandardPagination

    def get_queryset(self):
        user = self.request.user
        qs = CustomUser.objects.filter(
            role='alumno'
        ).select_related('perfil_alumno').order_by('-created_at')

        if user.role == 'docente':
            qs = qs.filter(
                inscripciones__seccion__asignatura__owner=user,
                inscripciones__activo=True
            ).distinct()

        is_active = self.request.query_params.get('is_active')
        if is_active is not None:
            qs = qs.filter(is_active=is_active.lower() == 'true')

        return qs


# ─────────────────────────────────────────────────────────────
# TOKENS DE REGISTRO
# ─────────────────────────────────────────────────────────────

class GenerateRegistrationTokenView(APIView):
    """
    POST /api/v1/users/tokens/registration/
    Genera un token de registro para que un alumno pueda crear su cuenta.
    Opcionalmente asocia el token a una sección específica.
    """
    permission_classes = [IsApprovedDocente]

    def post(self, request):
        expiry_hours = getattr(settings, 'SECURITY_CONFIG', {}).get(
            'REGISTRATION_CODE_EXPIRY_HOURS', 72
        )

        # Sección opcional — si se provee, el alumno quedará inscrito automáticamente
        seccion_id = request.data.get('seccion_id')
        seccion    = None

        if seccion_id:
            try:
                seccion = Seccion.objects.get(
                    pk=seccion_id,
                    asignatura__owner=request.user
                )
            except Seccion.DoesNotExist:
                return error_response(
                    message='Sección no encontrada o no tienes permiso sobre ella.',
                    status_code=400
                )

        token_plain, token_hash = TokenService.generate_registration_token()

        reg_token = RegistrationToken.objects.create(
            docente    = request.user,
            token_hash = token_hash,
            expires_at = timezone.now() + timedelta(hours=expiry_hours),
            seccion    = seccion,
        )

        logger.info(
            f'Token de registro generado por docente_id={request.user.id}'
            + (f' para seccion_id={seccion_id}' if seccion_id else '')
        )

        return success_response(
            data={
                'token':      token_plain,
                'expires_in': f'{expiry_hours} horas',
                'seccion':    seccion.nombre if seccion else None,
                'warning':    'Guarda este código — no se puede recuperar después.',
            },
            message='Token de registro generado.',
            status_code=201
        )


class RegistrationTokenListView(ListAPIView):
    """
    GET /api/v1/users/tokens/registration/list/
    Lista los tokens generados por el docente autenticado,
    con información del alumno que los usó.
    """
    permission_classes = [IsApprovedDocente]
    pagination_class   = StandardPagination

    def get(self, request):
        tokens = RegistrationToken.objects.filter(
            docente=request.user
        ).select_related(
            'used_by', 'used_by__perfil_alumno', 'seccion', 'seccion__asignatura'
        ).order_by('-created_at')

        data = []
        for t in tokens:
            alumno = None
            if t.used_by:
                try:
                    nombre = t.used_by.perfil_alumno.nombre_completo
                except Exception:
                    nombre = f'Alumno #{t.used_by.id}'
                alumno = {
                    'id':     t.used_by.id,
                    'nombre': nombre,
                }

            data.append({
                'id':         t.id,
                'estado':     'usado' if t.is_used else ('expirado' if t.is_expired else 'activo'),
                'seccion':    {'id': t.seccion.id, 'nombre': t.seccion.nombre, 'asignatura': t.seccion.asignatura.nombre} if t.seccion else None,
                'alumno':     alumno,
                'created_at': t.created_at,
                'expires_at': t.expires_at,
                'used_at':    t.used_at,
            })

        return success_response(data=data)


class InscribirAlumnoView(APIView):
    """
    POST /api/v1/users/alumnos/inscribir/
    El docente inscribe manualmente a un alumno en una de sus secciones.
    Útil cuando el alumno no puede registrarse solo.
    """
    permission_classes = [IsApprovedDocente]

    def post(self, request):
        alumno_id  = request.data.get('alumno_id')
        seccion_id = request.data.get('seccion_id')

        if not alumno_id or not seccion_id:
            return error_response(
                message='Se requieren alumno_id y seccion_id.',
                status_code=400
            )

        # Verificar que la sección pertenece al docente
        try:
            seccion = Seccion.objects.get(
                pk=seccion_id,
                asignatura__owner=request.user
            )
        except Seccion.DoesNotExist:
            return error_response(
                message='Sección no encontrada o no tienes permiso.',
                status_code=404
            )

        # Verificar que el alumno existe
        try:
            alumno = CustomUser.objects.get(pk=alumno_id, role='alumno')
        except CustomUser.DoesNotExist:
            return error_response(
                message='Alumno no encontrado.',
                status_code=404
            )

        # Crear o reactivar inscripción
        inscripcion, created = Inscripcion.objects.get_or_create(
            alumno=alumno,
            seccion=seccion,
            defaults={'activo': True}
        )

        if not created and not inscripcion.activo:
            inscripcion.activo = True
            inscripcion.save(update_fields=['activo'])

        if created or not inscripcion.activo:
            msg = f'Alumno inscrito en {seccion.nombre}.'
        else:
            msg = f'El alumno ya estaba inscrito en {seccion.nombre}.'

        return success_response(
            data={
                'inscripcion_id': inscripcion.id,
                'alumno':  {'id': alumno.id},
                'seccion': {'id': seccion.id, 'nombre': seccion.nombre},
            },
            message=msg,
            status_code=201
        )
