from usuarios.permissions import IsClubAdmin, IsClubStaff, is_admin
from datetime import timedelta, datetime

from django.db import IntegrityError
from django.db.models import Count, Q
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from marshmallow.fields import Boolean
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework_simplejwt. exceptions import TokenError
from .models import Usuarios, TipoUsuario, Equipos
import json
import urllib.error
import urllib.request
from django.conf import settings
COOKIE_ACCESS_NAME = "access_token"
COOKIE_REFRESH_NAME = "refresh_token"


@swagger_auto_schema(
    method='get',
    operation_description="Obtener los detalles de todos los usuarios",
    tags=["Usuarios"],
    security=[{'Bearer': []}],
    responses={
        200: openapi.Response(
            description="Lista de usuarios",
            examples={
                "application/json": [
                    {
                        "id": 1,
                        "name": "Juan Pérez",
                        "username": "juanp",
                        "email": "juan@example.com",
                        "tipo": "Administrador",
                    },
                    {
                        "id": 2,
                        "name": "María López",
                        "username": "mlópez",
                        "email": "maria@example.com",
                        "tipo": "Cliente",
                    },
                ]
            },
        ),
        400: openapi.Response(description="Ocurrió un error al listar usuarios"),
    },
)
@api_view(['GET'])
@permission_classes([IsClubStaff])
def listar(request, tipo=None):
    qs = Usuarios.objects.select_related('tipo').all()

    if tipo is not None:
        qs = qs.filter(tipo__id=tipo)
    else:
        # 2) Si no vino por ruta, miramos query param ?tipo=...
        tipo_q = request.GET.get('tipo')
        if tipo_q:
            try:
                qs = qs.filter(tipo__id=int(tipo_q))
            except ValueError:
                qs = qs.filter(tipo__description__icontains=tipo_q)
    rows = qs.values('id', 'name', 'username', 'email', 'tipo__description', 'tipo__id')
    data = [
        {
            "id": r['id'],
            "name": r['name'],
            "username": r['username'],
            "email": r['email'],
            "tipo": r.get('tipo__description'),
            "tipo_id": r.get('tipo__id'),
        } for r in rows
    ]
    return JsonResponse(data, safe=False, status=200)

@swagger_auto_schema(
    method='get',
    operation_description="Obtener los equipos",
    tags=["Equipos"],
    security=[{'Bearer': []}],
    responses={
        200: openapi.Response(
            description="Lista de equipos",
            examples={
                "application/json": [
                    {
                        "id": 1,
                        "description": "Wildcats",
                        "category": "OPEN COED ",
                        "level": "5 NT"
                    }
                ]
            },
        ),
        400: openapi.Response(description="Ocurrió un error al listar equipos"),
    },
)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def listarEquipos(request):
    equipos = Equipos.objects.annotate(
        members_count=Count("usersteams", filter=Q(usersteams__idUser__isnull=False))
    )
    data = [
        {
            "id": equipo.id,
            "description": equipo.description,
            "category": equipo.category,
            "level": equipo.level,
            "division": equipo.division,
            "color": equipo.color,
            "members_count": equipo.members_count
        }
        for equipo in equipos
    ]
    return JsonResponse(data, safe=False, status=status.HTTP_200_OK)

@swagger_auto_schema(
    method='post',
    operation_description="Agregar un nuevo usuario",
    tags=["Usuarios"],
    security=[{'Bearer': []}],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            "name": openapi.Schema(type=openapi.TYPE_STRING, description="Nombre del usuario"),
            "username": openapi.Schema(type=openapi.TYPE_STRING, description="Nombre de usuario"),
            "email": openapi.Schema(type=openapi.TYPE_STRING, description="Email del usuario"),
            "password": openapi.Schema(type=openapi.TYPE_STRING, description="Contraseña del usuario"),
            "tipo_id": openapi.Schema(type=openapi.TYPE_INTEGER, description="ID del tipo de usuario"),
        },
        required=["name", "username", "email", "password", "tipo_id"],
    ),
    responses={
        201: openapi.Response(description="Usuario creado exitosamente"),
        404: openapi.Response(description="Tipo de usuario no encontrado"),
        400: openapi.Response(description="Solicitud inválida"),
    },
)

@api_view(['POST'])
@permission_classes([IsClubAdmin])
@csrf_exempt
def add(request):
    try:
        body = json.loads(request.body)

        name = body.get("name")
        username = body.get("username")
        email = body.get("email")
        password = body.get("password")
        tipo_id = body.get("tipo_id")

        if not all([name, username, email, password, tipo_id]):
            return Response({"message": "Todos los campos son obligatorios"}, status=400)

        try:
            tipo = TipoUsuario.objects.get(id=tipo_id)
        except TipoUsuario.DoesNotExist:
            return JsonResponse({"error": "El tipo de usuario no existe"}, status=404)

        try:
            usuario = Usuarios(name=name, username=username, email=email, tipo=tipo)
            usuario.set_password(password)
            usuario.save()
        except IntegrityError as e:
            if 'email' in str(e):  # Analiza el mensaje de error para identificar el campo duplicado
                return JsonResponse({"error": f"El email '{email}' ya está registrado"}, status=400)
            elif 'username' in str(e):  # Opcional: Maneja duplicidad para otro campo
                return JsonResponse({"error": f"El username '{username}' ya está registrado"}, status=400)
            else:
                return JsonResponse({"error": "Error de base de datos: Restricción de unicidad"}, status=400)
        except Exception as e:
            return JsonResponse({"error": f"Error inesperado: {str(e)}"}, status=500)

        return JsonResponse(
            {
                "message": "Usuario creado exitosamente",
                "usuario": {
                    "id": usuario.id,
                    "name": usuario.name,
                    "username": usuario.username,
                    "email": usuario.email,
                    "tipo": usuario.tipo.description,
                },
            },
            status=201,
        )
    except json.JSONDecodeError:
        return JsonResponse({"error": "Solicitud inválida"}, status=400)

@swagger_auto_schema(
    method='post',
    operation_description="Agregar un nuevo equipo",
    tags=["Equipos"],
    security=[{'Bearer': []}],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            "description": openapi.Schema(type=openapi.TYPE_STRING, description="Description del equipo"),
            "category": openapi.Schema(type=openapi.TYPE_STRING, description="Categoria del equipo"),
            "level": openapi.Schema(type=openapi.TYPE_STRING, description="Nivel del equipo"),
            "division": openapi.Schema(type=openapi.TYPE_STRING, description="División del equipo (Novice, Prep, Elite)")
        },
        required=["description", "category", "level"],
    ),
    responses={
        201: openapi.Response(description="Equipo creado exitosamente"),
        400: openapi.Response(description="Solicitud inválida"),
    },
)

@api_view(['POST'])
@permission_classes([IsClubAdmin])
@csrf_exempt
def addTeam(request):
    try:
        body = json.loads(request.body)

        description = body.get("description")
        category = body.get("category")
        level = body.get("level")
        color = body.get("color")
        division = body.get("division") or None

        if not all([description, category, level, color]):
            return Response({"message": "Todos los campos son obligatorios"}, status=400)

        try:
            equipo = Equipos.objects.create(
                description=description,
                category=category,
                level=level,
                division=division,
                color=color
            )
        except Exception as e:
            return JsonResponse({"error": f"Error inesperado: {str(e)}"}, status=500)

        return JsonResponse(
            {
                "message": "Equipo creado exitosamente",
                "equipo": {
                    "id": equipo.id,
                    "description": equipo.description,
                    "category": equipo.category,
                    "level": equipo.level,
                    "division": equipo.division,
                    "color": equipo.color
                },
            },
            status=201,
        )
    except json.JSONDecodeError:
        return JsonResponse({"error": "Solicitud inválida"}, status=400)

@swagger_auto_schema(
    method='put',
    operation_description="Actualizar un usuario por ID",
    tags=["Usuarios"],
    security=[{'Bearer': []}],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            "name": openapi.Schema(type=openapi.TYPE_STRING, description="Nombre del usuario"),
            "username": openapi.Schema(type=openapi.TYPE_STRING, description="Nombre de usuario"),
            "email": openapi.Schema(type=openapi.TYPE_STRING, description="Email del usuario"),
            "password": openapi.Schema(type=openapi.TYPE_STRING, description="Contraseña del usuario"),
            "tipo_id": openapi.Schema(type=openapi.TYPE_INTEGER, description="ID del tipo de usuario"),
        },
    ),
    responses={
        200: openapi.Response(description="Usuario actualizado exitosamente"),
        404: openapi.Response(description="Usuario no encontrado"),
    },
)
@api_view(['PUT'])
@permission_classes([IsAuthenticated])
@csrf_exempt
def edit(request, id):
    try:
        # Un usuario puede editar su propio perfil; editar a otros es solo para administradores
        if not (is_admin(request.user) or request.user.id == id):
            return JsonResponse({"error": "No tienes permisos para editar este usuario"}, status=403)

        usuario = Usuarios.objects.get(id=id)
        body = json.loads(request.body)

        if "name" in body:
            usuario.name = body["name"]
        if "username" in body and is_admin(request.user):
            usuario.username = body["username"]
        if "email" in body:
            usuario.email = body["email"]
        if body.get("password"):
            usuario.set_password(body["password"])
        if "tipo_id" in body and is_admin(request.user):
            try:
                tipo = TipoUsuario.objects.get(id=body["tipo_id"])
                usuario.tipo = tipo
            except TipoUsuario.DoesNotExist:
                return JsonResponse({"error": "El tipo de usuario especificado no existe"}, status=404)

        usuario.save()
        return JsonResponse(
            {
                "message": "Usuario actualizado exitosamente",
                "usuario": {
                    "id": usuario.id,
                    "name": usuario.name,
                    "username": usuario.username,
                    "email": usuario.email,
                    "tipo": usuario.tipo.description if usuario.tipo else None,
                },
            },
            status=200,
        )
    except Usuarios.DoesNotExist:
        return JsonResponse({"error": "Usuario no encontrado"}, status=404)

@swagger_auto_schema(
    method='put',
    operation_description="Actualizar un equipo por ID",
    tags=["Equipos"],
    security=[{'Bearer': []}],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            "description": openapi.Schema(type=openapi.TYPE_STRING, description="Descripción del equipo"),
            "category": openapi.Schema(type=openapi.TYPE_STRING, description="Categoría del equipo"),
            "level": openapi.Schema(type=openapi.TYPE_STRING, description="Nivel del equipo"),
            "division": openapi.Schema(type=openapi.TYPE_STRING, description="División del equipo (Novice, Prep, Elite)")
        },
    ),
    responses={
        200: openapi.Response(description="Equipo actualizado exitosamente"),
        404: openapi.Response(description="Equipo no encontrado"),
    },
)
@api_view(['PUT'])
@permission_classes([IsClubAdmin])
@csrf_exempt
def editTeam(request, id):
    try:
        equipo = Equipos.objects.get(id=id)
        body = json.loads(request.body)

        if "description" in body:
            equipo.description = body["description"]
        if "category" in body:
            equipo.category = body["category"]
        if "level" in body:
            equipo.level = body["level"]
        if "division" in body:
            equipo.division = body["division"] or None
        if "color" in body:
            equipo.color = body["color"]

        equipo.save()
        return Response(
            {
                "message": "Equipo actualizado exitosamente",
                "equipo": {
                    "id": equipo.id,
                    "description": equipo.description,
                    "category": equipo.category,
                    "level": equipo.level,
                    "division": equipo.division,
                    "color": equipo.color
                },
            },
            status=200,
        )
    except Equipos.DoesNotExist:
        return Response({"error": "Equipo no encontrado"}, status=404)

@swagger_auto_schema(
    method='delete',
    operation_description="Eliminar un usuario por ID",
    tags=["Usuarios"],
    security=[{'Bearer': []}],
    responses={
        200: openapi.Response(description="Usuario eliminado exitosamente"),
        404: openapi.Response(description="Usuario no encontrado"),
    },
)
@api_view(['DELETE'])
@permission_classes([IsClubAdmin])
def delete(request, id):
    try:
        usuario = Usuarios.objects.get(id=id)
        usuario.delete()
        return JsonResponse({"message": "Usuario eliminado exitosamente"}, status=200)
    except Usuarios.DoesNotExist:
        return JsonResponse({"error": "Usuario no encontrado"}, status=404)

@swagger_auto_schema(
    method='delete',
    operation_description="Eliminar un equipo por ID",
    tags=["Equipos"],
    security=[{'Bearer': []}],
    responses={
        200: openapi.Response(description="Equipo eliminado exitosamente"),
        404: openapi.Response(description="Equipo no encontrado"),
    },
)
@api_view(['DELETE'])
@permission_classes([IsClubAdmin])
def deleteTeam(request, id):
    try:
        equipo = Equipos.objects.get(id=id)
        equipo.delete()
        return Response({"message": "Equipo eliminado exitosamente"}, status=200)
    except Equipos.DoesNotExist:
        return Response({"error": "Equipo no encontrado"}, status=404)



def _set_jwt_cookies(resp: JsonResponse, access: str, refresh: str | None = None, remember_me: Boolean = False):
    # Ajusta flags desde settings o por entorno
    secure = getattr(settings, "JWT_COOKIE_SECURE", True)
    samesite = getattr(settings, "JWT_COOKIE_SAMESITE", "None")  # "None" si front y API están en dominios distintos
    domain = getattr(settings, "JWT_COOKIE_DOMAIN", None)

    max_age_access = 86400 if remember_me else 900  # 1 día o 15 min
    max_age_refresh = 432000 if remember_me else 86400  # 5 días o 1 día

    resp.set_cookie(
        key=COOKIE_ACCESS_NAME,
        value=access,
        max_age=max_age_access,             # 1 hora
        httponly=True,
        secure=secure,
        samesite=samesite,
        path="/",
        domain=domain,
    )
    if refresh:
        resp.set_cookie(
            key=COOKIE_REFRESH_NAME,
            value=refresh,
            max_age=max_age_refresh,  # 14 días
            httponly=True,
            secure=secure,
            samesite=samesite,
            path="/",
            domain=domain,
        )

def _delete_jwt_cookies(resp: JsonResponse):
    secure = getattr(settings, "JWT_COOKIE_SECURE", not settings.DEBUG)
    samesite = getattr(settings, "JWT_COOKIE_SAMESITE", "Lax")
    domain = getattr(settings, "JWT_COOKIE_DOMAIN", None)
    # Algunos navegadores exigen mismos atributos de borrado
    resp.delete_cookie(COOKIE_ACCESS_NAME, path="/", domain=domain, samesite=samesite)
    resp.delete_cookie(COOKIE_REFRESH_NAME, path="/", domain=domain, samesite=samesite)

def _iam_username(request):
    """Consulta /auth/me del BFF con las cookies del navegador y devuelve el usuario (sin puntos) o None."""
    cookie = request.META.get("HTTP_COOKIE")
    if not cookie:
        return None
    req = urllib.request.Request(settings.IAM_ME_URL, headers={"Cookie": cookie, "Accept": "application/json"})
    try:
        with urllib.request.urlopen(req, timeout=settings.IAM_TIMEOUT_SECONDS) as res:
            data = json.loads(res.read().decode("utf-8"))
    except (urllib.error.URLError, ValueError):
        return None
    if not isinstance(data, dict):
        return None
    # El BFF devuelve los datos del usuario dentro de "profile"
    profile = data.get("profile") if isinstance(data.get("profile"), dict) else {}
    preferred = profile.get("preferred_username") or data.get("preferred_username")
    return preferred.replace(".", "") if preferred else None

def _iam_local_bypass(request):
    """Solo desarrollo: omite el IAM si IAM_LOCAL_BYPASS está activo y la API se usa desde localhost."""
    if not getattr(settings, "IAM_LOCAL_BYPASS", False):
        return False
    host = request.get_host().split(":")[0]
    return host in getattr(settings, "IAM_LOCAL_BYPASS_HOSTS", ())

@swagger_auto_schema(
    method='post',
    operation_description="Login",
    tags=["Auth"],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            'username': openapi.Schema(type=openapi.TYPE_STRING, description="Nombre de usuario"),
            'remember_me': openapi.Schema(type=openapi.TYPE_BOOLEAN, description="Mantener la sesión iniciada"),
        },
        required=['username']
    ),
    responses={
        200: openapi.Response(
            description="Inicio de sesión completo",
            examples={
                "application/json": {
                    "message": "Inicio de sesión exitoso",
                    "access_token": "<access_token>",
                    "refresh_token": "<refresh_token>"
                }
            },
        ),
        401: openapi.Response(description="Credenciales incorrectas"),
    },
)
@api_view(['POST'])
@permission_classes([AllowAny])
def login(request):
    username = request.data.get("username")
    remember_me = request.data.get("remember_me")

    # La contraseña la valida la pasarela de acceso (IAM); aquí se confirma esa sesión y que el usuario exista
    if not username:
        return Response({"error": "Credenciales incorrectas"}, status=status.HTTP_401_UNAUTHORIZED)

    if (
        getattr(settings, "IAM_VERIFY_LOGIN", True)
        and not _iam_local_bypass(request)
        and _iam_username(request) != username
    ):
        return Response({"error": "Sesión del IAM inválida o no corresponde al usuario"}, status=status.HTTP_401_UNAUTHORIZED)

    user = Usuarios.objects.select_related('tipo').filter(username=username, is_active=True).first()


    if user is not None:
        # Iniciar sesión
        refresh = RefreshToken.for_user(user)
        refresh_str = str(refresh)

        now = datetime.now()


        # Configurar duración de la sesión
        if not remember_me:
            # Sesión expira al cerrar el navegador
            access_lifetime = timedelta(minutes=15)
            refresh_lifetime = timedelta(days=1)
            refresh.access_token.set_exp(lifetime=access_lifetime)
            refresh.set_exp(lifetime=refresh_lifetime)

        else:
            # Sesión dura 30 días (en segundos)
            access_lifetime = timedelta(days=1)
            refresh_lifetime = timedelta(days=30)
            refresh.access_token.set_exp(lifetime=access_lifetime)
            refresh.set_exp(lifetime=refresh_lifetime)

        access_expires_at = now + access_lifetime
        refresh_expires_at = now + refresh_lifetime
        max_age_access = 86400 if remember_me else 900  # 1 día o 15 min
        max_age_refresh = 432000 if remember_me else 86400  # 5 días o 1 día

        resp = Response({
            "message": "Inicio de sesión exitoso",
            # Ya no necesitas devolver los tokens en el body si usarás cookies:
            "usuario": {
                "id": user.id,
                "name": user.name,
                "username": user.username,
                "email": user.email,
                "tipo": user.tipo.description if user.tipo else None,
                "tipo_id": user.tipo.id if user.tipo else None,
            },
            'token_info': {
                'access_token_expires_in': max_age_access,  # Segundos
                'refresh_token_expires_in': max_age_refresh,  # Segundos
                'access_token_expires_at': access_expires_at.isoformat(),  # ISO format
                'refresh_token_expires_at': refresh_expires_at.isoformat(),  # ISO format
                'remember_me': remember_me,
            }
        }, status=status.HTTP_200_OK)

        _set_jwt_cookies(resp, access=str(refresh.access_token), refresh=refresh_str, remember_me=remember_me)

        return resp  # Redirigir a página principal
    else:
        return Response({"error": "Credenciales incorrectas"}, status=status.HTTP_401_UNAUTHORIZED)
    #if not user:

@swagger_auto_schema(
    method='post',
    operation_description="Logout que invalida el token de refresco",
    tags=["Auth"],
    security=[{'Bearer': []}],
    request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties={
            'refresh_token': openapi.Schema(type=openapi.TYPE_STRING, description="Token de refresco a invalidar"),
        },
        required=['refresh_token']
    ),
    responses={
        200: openapi.Response(description="Logout exitoso"),
        400: openapi.Response(description="Token de refresco inválido"),
    },
)
@api_view(['POST'])
@csrf_exempt
@permission_classes([AllowAny])
def logout(request):
    refresh_token = request.COOKIES.get('refresh_token')
    if refresh_token:
        # Agregar token a la blacklist
        token = RefreshToken(refresh_token)
        token.blacklist()
    resp = Response({"ok": True})
    _delete_jwt_cookies(resp)
    return resp

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def me(request):
    # Con autenticador por cookie, request.user ya estará poblado
    try:
        u = request.user
        return Response(
            {"id": u.id, "name": u.name, "username": u.username, "email": u.email, "tipo_id": u.tipo.id if u.tipo else None, },
            status=status.HTTP_200_OK)
    except Exception as e:
        return Response({"message": e})

@api_view(['POST'])
@permission_classes([AllowAny])
def refresh_token_view(request):
    """
    Refrescar access token usando refresh token de la cookie
    """
    print("\n" + "=" * 50)
    print("🔄 REFRESH TOKEN REQUEST")
    print("=" * 50)

    # ✅ Leer refresh token de la cookie
    refresh_token = request.COOKIES.get(COOKIE_REFRESH_NAME)

    print(f"🔍 Refresh token recibido: {refresh_token[: 20] if refresh_token else 'None'}...")
    print(f"📦 Todas las cookies: {list(request.COOKIES.keys())}")

    if not refresh_token:
        print("❌ No se encontró refresh token en las cookies\n")
        return Response(
            {'error': 'No se encontró refresh token'},
            status=status.HTTP_401_UNAUTHORIZED
        )

    try:
        # ✅ Validar y refrescar token
        refresh = RefreshToken(refresh_token)
        new_access_token = str(refresh.access_token)

        print(f"✅ Nuevo access token generado: {new_access_token[: 20]}...")

        # ✅ Verificar si era un token de "Recuérdame" (por duración)
        exp_timestamp = refresh['exp']
        exp_date = datetime.fromtimestamp(exp_timestamp)
        now = datetime.now()
        days_remaining = (exp_date - now).days

        remember_me = days_remaining > 7
        print(f"📅 Días restantes del refresh token: {days_remaining}")
        print(f"🔐 Remember me: {remember_me}")

        # ✅ Configurar duración de cookies según "Recuérdame"
        if remember_me:
            max_age_access = 86400  # 1 día
            max_age_refresh = 432000  # 5 días
            access_lifetime = timedelta(days=1)
            refresh_lifetime = timedelta(days=5)
        else:
            max_age_access = 900  # 15 minutos
            max_age_refresh = 86400  # 1 día
            access_lifetime = timedelta(minutes=15)
            refresh_lifetime = timedelta(days=1)

        # ✅ Configuración de seguridad
        secure = getattr(settings, 'JWT_COOKIE_SECURE', not settings.DEBUG)
        samesite = getattr(settings, 'JWT_COOKIE_SAMESITE', 'Lax')
        domain = getattr(settings, 'JWT_COOKIE_DOMAIN', None)
        access_expires_at = now + access_lifetime
        refresh_expires_at = now + refresh_lifetime

        # ✅ Preparar respuesta
        response = Response({
            'message': 'Token refrescado',
            'token_info': {
                'access_token_expires_in': max_age_access,  # Segundos
                'refresh_token_expires_in': max_age_refresh,  # Segundos
                'access_token_expires_at': access_expires_at.isoformat(),  # ISO format
                'refresh_token_expires_at': refresh_expires_at.isoformat(),  # ISO format
                'remember_me': remember_me,
            }
        }, status=status.HTTP_200_OK)

        # ✅ Guardar NUEVO access token en cookie
        response.set_cookie(
            key=COOKIE_ACCESS_NAME,
            value=new_access_token,  # ← Nuevo access token
            max_age=max_age_access,
            httponly=True,
            secure=secure,
            samesite=samesite,
            path="/",
            domain=domain,
        )
        print(f"💾 Access token guardado en cookie (max_age={max_age_access}s)")

        # ✅ OPCIONAL: Renovar también el refresh token (rotación)
        # Si tienes ROTATE_REFRESH_TOKENS=True, genera uno nuevo
        if getattr(settings, 'ROTATE_REFRESH_TOKENS', False):
            new_refresh_token = str(refresh)
            response.set_cookie(
                key=COOKIE_REFRESH_NAME,
                value=new_refresh_token,  # ← Nuevo refresh token
                max_age=max_age_refresh,
                httponly=True,
                secure=secure,
                samesite=samesite,
                path="/",
                domain=domain,
            )
            print(f"💾 Refresh token renovado en cookie (max_age={max_age_refresh}s)")

        # ✅ Si NO rotas refresh tokens, mantener el mismo
        # (No es necesario volver a guardarlo, ya está en la cookie)

        print("✅ Refresh exitoso\n")
        return response

    except TokenError as e:
        print(f"❌ Error al validar refresh token:  {e}")
        print(f"   Tipo:  {type(e).__name__}\n")
        return Response(
            {'error': 'Token inválido o expirado'},
            status=status.HTTP_401_UNAUTHORIZED
        )
    except Exception as e:
        print(f"❌ Error inesperado: {e}\n")
        return Response(
            {'error': 'Error interno del servidor'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )