
from django.db import transaction
from django.http import HttpResponse, JsonResponse
from django.contrib.auth.hashers import make_password
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework.decorators import action

from api import models, schemas, serializers
from logger.views import save_log_usuario

import json
import logging

class UsuarioViewSet(viewsets.ModelViewSet):
    queryset = models.Usuario.objects.all()
    serializer_class = serializers.UsuarioSerializer
    schema = schemas.UsuarioSchema()

    def retrieve(self, request, pk=None):
        data = super().retrieve(request, pk)
        return data

    def create(self, request):
        try:
            login = self.request.jwt_info['login']
            usuario_session = models.Usuario.objects.filter(login=login).first()

            with transaction.atomic():
                input = json.loads(request.body)

                persona = models.Persona.objects.filter(rut = input['rut']).first()
                id_tipo_tratamiento = input.get('id_tipo_tratamiento',None)

                tipo_tratamiento = None
                if id_tipo_tratamiento:
                    tipo_tratamiento = models.TipoTratamientoPersona.objects.filter(id_tipo_tratamiento = id_tipo_tratamiento).first()
                
                if persona == None:
                    persona = models.Persona(
                        rut = input['rut'],
                        dv = input['dv'],
                        nombres = input['nombres'],
                        apellido_a = input.get('apellido_a',None),
                        apellido_b = input.get('apellido_b',None),
                        email = input.get('email',None),
                        id_tipo_tratamiento = tipo_tratamiento
                    )
                    persona.save()
                else:
                    persona.nombres = input['nombres']
                    persona.apellido_a = input.get('apellido_a',None)
                    persona.apellido_b = input.get('apellido_b',None)
                    persona.email = input.get('email',None)
                    persona.id_tipo_tratamiento = tipo_tratamiento
                    persona.save()

                if persona == None:
                    raise ValueError('Persona no creada')

                rol = models.Rol.objects.filter(id_rol=input.get('id_rol',None)).first()
                if rol == None:
                    raise ValueError('Rol no encontrado')

                usuario = models.Usuario(
                    rut = persona,
                    login = input['login'],
                    id_rol = rol,
                    vigente = input.get('vigente', False),
                )
                usuario.save()

                if input['clave']:
                    logging.error('Modificar clave de usuario')
                    usuario.clave = make_password(input['clave'])
                    usuario.save()
            
                save_log_usuario(
                    accion_tabla='create',
                    rut_tabla=persona.rut,
                    login_tabla=usuario.login,
                    rut_ejecutor=usuario_session.rut.rut,
                    login_ejecutor=usuario_session.login
                )

                return Response({
                    'rut': persona.rut,
                    'dv': persona.dv,
                    'nombres': persona.nombres,
                    'apellido_a': persona.apellido_a,
                    'apellido_b': persona.apellido_b,
                    'email': persona.email,
                    'login': usuario.login,
                    'vigente': usuario.vigente,
                })
        
        except ValueError as ex:
            transaction.rollback()
            return HttpResponse(str(ex), status = 400)
        
        except Exception as ex:
            transaction.rollback()
            return HttpResponse(str(ex), status = 500)


    def partial_update(self, request, *args, **kwargs):
        input = json.loads(request.body)
        try:
            pk = input['rut']
            login = self.request.jwt_info['login']
            usuario_session = models.Usuario.objects.filter(login=login).first()

            with transaction.atomic():

                # validaciones se realiza a nivel del model
                persona = models.Persona.objects.filter(rut = pk).first()
                rol = models.Rol.objects.filter(id_rol = input.get('id_rol')).first()

                usuario = models.Usuario.objects.filter(rut = pk).first()
                usuario.vigente = input.get('vigente', False)
                usuario.superuser = input.get('superuser', False)
                usuario.id_rol = rol
                usuario.save()

                if 'clave' in input:
                    logging.error('Modificar clave de usuario')
                    usuario.clave = make_password(input['clave'])
                    usuario.save()

                save_log_usuario(
                    accion_tabla='update',
                    rut_tabla=persona.rut,
                    login_tabla=usuario.login,
                    rut_ejecutor=usuario_session.rut.rut,
                    login_ejecutor=usuario_session.login
                )
            
            return Response({
                'rut': persona.rut,
                'dv': persona.dv,
                'nombres': persona.nombres,
                'apellido_a': persona.apellido_a,
                'apellido_b': persona.apellido_b,
                'email': persona.email,
                'login': usuario.login,
                'vigente': usuario.vigente,
            })
        
        except ValueError as e:
            transaction.rollback()
            return HttpResponse(str(e), status = 400)
        
        except Exception as e:
            transaction.rollback()
            logging.error(e)
            return HttpResponse(str(e), status = 500)


    def destroy(self, request, pk=None):
        try:
            login = self.request.jwt_info['login']
            usuario_session = models.Usuario.objects.filter(login=login).first()
            usuario = models.Usuario.objects.filter(login=pk).first()
            data = super().destroy(request, usuario.rut.rut)

            save_log_usuario(
                accion_tabla='delete',
                rut_tabla=usuario.rut.rut,
                login_tabla=usuario.login,
                rut_ejecutor=usuario_session.rut.rut,
                login_ejecutor=usuario_session.login
            )

            return data
        except Exception as ex:
            return Response(str(ex), status=400)


    @action(detail=False, methods=['post'])
    def permisos(self, request):
        input = {}
        if request.body > b'':
            input = json.loads(request.body)

        login = request.jwt_info['login']
        usuario = models.Usuario.objects.filter(login=login).first()
        escritura = usuario.superuser == True

        if 'path' in input:
            path = input.get('path')
            aplicacion = models.Aplicacion.objects.filter(path_app=path).first()

            if escritura == False:
                rol_aplicacion = models.RolAplicacion.objects.filter(id_rol=usuario.id_rol, id_aplicacion=aplicacion.id_aplicacion).first()
                escritura = rol_aplicacion.solo_visualizar == False

            return JsonResponse({
                'path_app': path,
                'nombre_app': aplicacion.nombre_app,
                'escritura': escritura
            })
        else:
            registros = models.RolAplicacion.objects.filter(id_rol=usuario.id_rol)
            aplicaciones = []
            for registro in registros:
                if registro.id_aplicacion.vigente:
                    rol_app = models.RolAplicacion.objects.filter(id_rol=registro.id_rol, id_aplicacion=registro.id_aplicacion).first()
                    
                    aplicaciones.append({
                        'path_app': registro.id_aplicacion.path_app,
                        'nombre_app': registro.id_aplicacion.nombre_app,
                    })

            return JsonResponse({ "aplicaciones": aplicaciones })
