from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework import exceptions
from rest_framework_simplejwt.tokens import AccessToken
from .models import Usuario

class AuthenticatedUserProxy:
    """
    Proxy ligero que envuelve tu modelo Usuario y expone is_authenticated=True
    además de delegar todos los atributos/metodos al objeto real.
    """
    def __init__(self, user):
        self._user = user

    def __getattr__(self, name):
        return getattr(self._user, name)

    @property
    def is_authenticated(self):
        return True

    def __str__(self):
        return str(self._user)

class CustomJWTAuthentication(BaseAuthentication):
    """
    Autenticador JWT que busca el usuario en el modelo Usuario (api_login.models.Usuario).
    Devuelve (AuthenticatedUserProxy(user), token) para que DRF reconozca is_authenticated.
    """
    def authenticate(self, request):
        auth = get_authorization_header(request).split()
        if not auth or auth[0].lower() != b'bearer':
            return None

        if len(auth) == 1:
            raise exceptions.AuthenticationFailed('Invalid token header. No credentials provided.')
        if len(auth) > 2:
            raise exceptions.AuthenticationFailed('Invalid token header')

        try:
            token = auth[1].decode()
        except UnicodeError:
            raise exceptions.AuthenticationFailed('Token decode error')

        try:
            payload = AccessToken(token)
        except Exception as e:
            raise exceptions.AuthenticationFailed(f'Token inválido: {str(e)}')

        user_id = payload.get('user_id') or payload.get('user') or payload.get('id')
        if not user_id:
            raise exceptions.AuthenticationFailed('Token no contiene user_id')

        # convertir a int si corresponde
        try:
            pk = int(user_id)
        except Exception:
            pk = user_id

        try:
            user = Usuario.objects.get(id=pk)
        except Usuario.DoesNotExist:
            raise exceptions.AuthenticationFailed('User not found')

        return (AuthenticatedUserProxy(user), token)