from rest_framework import status, viewsets, generics
from rest_framework.response import Response
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework_simplejwt.views import TokenObtainPairView
from django.contrib.auth.models import User
from .serializers import UsuarioSerializer, RegistroSerializer, CustomTokenObtainPairSerializer
from .permissions import IsAdminRole

class CustomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

class RegistroView(generics.CreateAPIView):
    queryset = User.objects.all()
    permission_classes = (AllowAny,)
    serializer_class = RegistroSerializer

class UsuarioViewSet(viewsets.ModelViewSet):
    queryset = User.objects.select_related('perfil').all().order_by('-date_joined')
    serializer_class = UsuarioSerializer
    permission_classes = [IsAuthenticated, IsAdminRole]
    
    @action(detail=True, methods=['patch'])
    def aprobar(self, request, pk=None):
        if hasattr(request.user, 'perfil') and request.user.perfil.rol == 'CONTADOR':
            return Response({"error": "No tiene permisos para aprobar registros."}, status=status.HTTP_403_FORBIDDEN)
        user = self.get_object()
        if hasattr(user, 'perfil'):
            user.perfil.aprobado = True
            user.perfil.save()
        return Response({"status": "Usuario aprobado correctamente"})

    @action(detail=True, methods=['patch'], url_path='cambiar-estado')
    def cambiar_estado(self, request, pk=None):
        user_to_change = self.get_object()
        
        # Regla de auto-protección
        if user_to_change.id == request.user.id:
            return Response({"error": "No puedes cambiar tu propio estado para evitar el auto-bloqueo."}, status=status.HTTP_400_BAD_REQUEST)
            
        executing_rol = request.user.perfil.rol if hasattr(request.user, 'perfil') else None
        target_rol = user_to_change.perfil.rol if hasattr(user_to_change, 'perfil') else None
        
        # Validar jerarquía
        if executing_rol == 'CONTADOR':
            if target_rol != 'AUXILIAR':
                return Response({"error": "No tienes permisos para cambiar el estado de este usuario."}, status=status.HTTP_403_FORBIDDEN)
        elif executing_rol == 'ADMINISTRADOR':
            if target_rol not in ['CONTADOR', 'AUXILIAR']:
                return Response({"error": "No tienes permisos para cambiar el estado de este usuario."}, status=status.HTTP_403_FORBIDDEN)
        else:
            return Response({"error": "Permisos insuficientes."}, status=status.HTTP_403_FORBIDDEN)
            
        new_status = not user_to_change.is_active
        user_to_change.is_active = new_status
        user_to_change.save()
        
        # Registrar evento en auditoría
        from contabilidad.models import AuditoriaLog
        accion_msg = f"{executing_rol} {request.user.username} {'habilitó' if new_status else 'inhabilitó'} al usuario {user_to_change.username}"
        AuditoriaLog.objects.create(
            usuario=request.user,
            accion=accion_msg
        )
        
        estado_str = "habilitado" if new_status else "inhabilitado"
        return Response({"status": f"Usuario {estado_str} con éxito.", "is_active": new_status})
        
    def destroy(self, request, *args, **kwargs):
        from contabilidad.models import AuditoriaLog
        from django.db.models import ProtectedError
        user_to_delete = self.get_object()
        username = user_to_delete.username
        
        aprobado = False
        if hasattr(user_to_delete, 'perfil'):
            aprobado = user_to_delete.perfil.aprobado
            
        if aprobado:
            accion_msg = f"El Administrador eliminó al usuario {username}"
        else:
            accion_msg = f"El Administrador eliminó la solicitud de registro del usuario {username}"
            
        try:
            res = super().destroy(request, *args, **kwargs)
            AuditoriaLog.objects.create(
                usuario=request.user,
                accion=accion_msg
            )
            return res
        except ProtectedError:
            user_to_delete.is_active = False
            user_to_delete.save()
            
            if hasattr(user_to_delete, 'perfil'):
                user_to_delete.perfil.aprobado = False
                user_to_delete.perfil.save()
                
            AuditoriaLog.objects.create(
                usuario=request.user,
                accion=f"El Administrador inactivó al usuario {username} por tener registros asociados."
            )
            
            return Response(
                {"detail": "El usuario no se puede eliminar físicamente por integridad contable. Ha sido desactivado e inhabilitado permanentemente."},
                status=status.HTTP_200_OK
            )

    @action(detail=False, methods=['put'], permission_classes=[IsAuthenticated])
    def perfil(self, request):
        user = request.user
        data = request.data
        
        user.first_name = data.get('first_name', user.first_name)
        user.last_name = data.get('last_name', user.last_name)
        user.email = data.get('email', user.email)
        
        current_password = data.get('current_password')
        new_password = data.get('new_password')
        
        if new_password:
            if not current_password or not user.check_password(current_password):
                return Response({"error": "La contraseña actual es incorrecta o no fue suministrada."}, status=status.HTTP_400_BAD_REQUEST)
            user.set_password(new_password)
            
        user.save()
        return Response(UsuarioSerializer(user).data)

    def partial_update(self, request, *args, **kwargs):
        from contabilidad.models import AuditoriaLog
        user_to_update = self.get_object()
        
        if user_to_update.id == request.user.id:
            return Response({"error": "No puedes cambiar tu propio rol desde este panel para evitar quedar bloqueado."}, status=status.HTTP_400_BAD_REQUEST)
            
        rol = request.data.get('rol')
        if rol:
            if hasattr(user_to_update, 'perfil'):
                user_to_update.perfil.rol = rol
                user_to_update.perfil.save()
                
                AuditoriaLog.objects.create(
                    usuario=request.user,
                    accion=f"El Administrador modificó el rol del usuario {user_to_update.username} a {rol}"
                )
        
        serializer = self.get_serializer(user_to_update, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)
        
    def create(self, request, *args, **kwargs):
        serializer = RegistroSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        
        if hasattr(user, 'perfil'):
            user.perfil.aprobado = True
            user.perfil.save()
        
        return Response(UsuarioSerializer(user).data, status=status.HTTP_201_CREATED)

from rest_framework.views import APIView

class SolicitarRestablecimientoView(APIView):
    permission_classes = [AllowAny]
    
    def post(self, request, *args, **kwargs):
        username = request.data.get('username')
        email = request.data.get('email')
        
        if not username or not email:
            return Response({"error": "Debe suministrar el nombre de usuario y el correo electrónico."}, status=status.HTTP_400_BAD_REQUEST)
            
        try:
            user = User.objects.get(username=username, email=email)
        except User.DoesNotExist:
            return Response({"error": "No se encontró ningún usuario activo con ese nombre y correo electrónico."}, status=status.HTTP_404_NOT_FOUND)
            
        from .models import SolicitudPassword
        # Si ya existe una solicitud no atendida, no duplicar
        SolicitudPassword.objects.get_or_create(usuario=user, atendida=False)
        
        return Response({"status": "Solicitud enviada al Administrador con éxito. Comuníquese con la gerencia para obtener su nueva clave."})

class RestablecerConfirmarView(APIView):
    permission_classes = [IsAuthenticated, IsAdminRole]
    
    def post(self, request, *args, **kwargs):
        if hasattr(request.user, 'perfil') and request.user.perfil.rol == 'CONTADOR':
            return Response({"error": "No tiene permisos para restablecer contraseñas."}, status=status.HTTP_403_FORBIDDEN)
        solicitud_id = request.data.get('solicitud_id')
        nueva_contrasena = request.data.get('nueva_contrasena')
        
        if not solicitud_id or not nueva_contrasena:
            return Response({"error": "Debe suministrar la solicitud y la nueva contraseña."}, status=status.HTTP_400_BAD_REQUEST)
            
        from .models import SolicitudPassword
        from contabilidad.models import AuditoriaLog
        try:
            solicitud = SolicitudPassword.objects.get(id=solicitud_id, atendida=False)
        except SolicitudPassword.DoesNotExist:
            return Response({"error": "La solicitud no existe o ya fue atendida."}, status=status.HTTP_404_NOT_FOUND)
            
        user = solicitud.usuario
        user.set_password(nueva_contrasena)
        user.save()
        
        solicitud.atendida = True
        solicitud.save()
        
        AuditoriaLog.objects.create(
            usuario=request.user,
            accion=f"El Administrador restableció la contraseña del usuario {user.username}"
        )
        
        return Response({"status": "Contraseña restablecida con éxito."})

class SolicitudesRestablecimientoView(APIView):
    permission_classes = [IsAuthenticated, IsAdminRole]
    
    def get(self, request, *args, **kwargs):
        from .models import SolicitudPassword
        solicitudes = SolicitudPassword.objects.filter(atendida=False).select_related('usuario')
        data = [{
            "id": s.id,
            "username": s.usuario.username,
            "email": s.usuario.email,
            "fecha_solicitud": s.fecha_solicitud.isoformat()
        } for s in solicitudes]
        return Response(data)
