"""
users/views/auth.py
====================
Vistas de autenticación: login, refresh, logout y registro.

Todas las vistas de auth son públicas (AllowAny) excepto logout.
El throttling específico de auth está en security/middleware.py.
"""

import logging
from django.utils import timezone
from datetime import timedelta
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework_simplejwt.views import TokenRefreshView
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt.exceptions import TokenError

from users.serializers.auth import (
    CustomTokenObtainSerializer,
    RegisterDocenteSerializer,
    RegisterAlumnoSerializer,
)
from shared.utils.responses import success_response, error_response

logger = logging.getLogger('eduplay')


class LoginView(APIView):
    """
    POST /api/v1/auth/login/
    
    Autentica un usuario con email + contraseña.
    Retorna access token (15 min) y refresh token (7 días).
    
    Seguridad:
      - Rate limiting: 5 intentos / 10 min por IP (middleware)
      - Bloqueo: 5 intentos fallidos → cuenta bloqueada 30 min
      - Auditoría: todo login se registra en security_audit
    """
    permission_classes = [AllowAny]

    def post(self, request):
        serializer = CustomTokenObtainSerializer(data=request.data)

        if not serializer.is_valid():
            return error_response(
                message='Credenciales inválidas',
                errors=serializer.errors,
                status_code=401
            )

        data = serializer.validated_data
        logger.info(f'Login exitoso: user_id={data["user"]["id"]} role={data["user"]["role"]}')

        return success_response(
            data=data,
            message='Sesión iniciada exitosamente'
        )


class RefreshTokenView(TokenRefreshView):
    """
    POST /api/v1/auth/refresh/
    
    Renueva el access token usando el refresh token.
    simplejwt maneja la rotación automática del refresh token.
    """
    pass


class LogoutView(APIView):
    """
    POST /api/v1/auth/logout/
    
    Invalida el refresh token del usuario (blacklist).
    El access token seguirá siendo válido hasta su expiración (15 min),
    pero no se podrá renovar.
    
    Requiere: Authorization: Bearer <access_token>
    Body: { "refresh": "<refresh_token>" }
    """
    permission_classes = [IsAuthenticated]

    def post(self, request):
        refresh_token = request.data.get('refresh')
        if not refresh_token:
            return error_response(message='Refresh token requerido', status_code=400)

        try:
            token = RefreshToken(refresh_token)
            token.blacklist()
        except TokenError as e:
            return error_response(message='Token inválido o ya expirado', status_code=400)

        # Limpiar session_token del usuario
        request.user.session_token = None
        request.user.save(update_fields=['session_token'])

        logger.info(f'Logout: user_id={request.user.id}')
        return success_response(message='Sesión cerrada exitosamente')


class RegisterDocenteView(APIView):
    """
    POST /api/v1/auth/register/docente/
    
    Registra un nuevo docente. La cuenta queda pendiente de aprobación
    por el administrador. El docente recibe un email de confirmación.
    """
    permission_classes = [AllowAny]

    def post(self, request):
        serializer = RegisterDocenteSerializer(data=request.data)

        if not serializer.is_valid():
            return error_response(
                message='Datos de registro inválidos',
                errors=serializer.errors,
                status_code=422
            )

        user = serializer.save()

        # TODO: Enviar email de confirmación al docente
        # TODO: Notificar al admin que hay una solicitud pendiente
        logger.info(f'Nuevo docente registrado: user_id={user.id}')

        return success_response(
            data={'user_id': user.id, 'status': 'pending'},
            message='Solicitud enviada. El administrador revisará tu cuenta en 24-48 horas.',
            status_code=201
        )


class RegisterAlumnoView(APIView):
    """
    POST /api/v1/auth/register/alumno/
    
    Registra un nuevo alumno usando un token de registro único
    generado por su docente. El token se invalida tras el primer uso.
    """
    permission_classes = [AllowAny]

    def post(self, request):
        serializer = RegisterAlumnoSerializer(data=request.data)

        if not serializer.is_valid():
            return error_response(
                message='Error en el registro',
                errors=serializer.errors,
                status_code=422
            )

        user = serializer.save()
        logger.info(f'Nuevo alumno registrado: user_id={user.id}')

        # Generar tokens de acceso inmediatamente para que pueda entrar
        refresh = RefreshToken.for_user(user)
        refresh['role'] = user.role

        return success_response(
            data={
                'access':  str(refresh.access_token),
                'refresh': str(refresh),
                'user': {
                    'id':       user.id,
                    'role':     user.role,
                    'nickname': user.nickname,
                }
            },
            message='¡Cuenta creada exitosamente! Ya puedes iniciar sesión.',
            status_code=201
        )
