import copy
import json

from app.entities import enums
# from app.businesslayer import log_save
from app.applicationlayer.utils import model_to_dict

from django.shortcuts import render
from rest_framework.response import Response
from app.entities import models

from django.db import transaction
from app.helper import decorators

from rest_framework import viewsets, status
from rest_framework.decorators import action

from app.applicationlayer.management.user import table_filters
from django_filters.rest_framework import DjangoFilterBackend
from app.applicationlayer import paginators

from app.applicationlayer import serializers as app_serializers
from . import serializers, table_filters

from django.conf import settings
from django.contrib.auth import authenticate

from app.helper.file_manager import FileHelper
from app.applicationlayer.utils import (
    CustomPagination, status_message_response, log_save, QuerySetHelper
)

from django.db.models import (Q, F, Sum, OuterRef, Subquery, Q, Case, When,
                              Value, Func, Count,
                              CharField,
                              IntegerField,
                              DecimalField,
                              BooleanField)
# Create your views here.


class UsersManagementViewSet(viewsets.ModelViewSet):
    """ViewSet for the Requisition"""
    queryset = models.User.objects.all()
    serializer_class = serializers.UserManagementSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_class = table_filters.UserManagementFilter
    pagination_class = CustomPagination


    @transaction.atomic
    def destroy(self, request, *args, **kwargs):
        
        instance = self.get_object()
        new_instance = model_to_dict(instance)
        instance.applications.remove()
        self.perform_destroy(instance)

        log_save(
            enums.LogEnum.DELETED.value,
            enums.LogEntitiesEnum.USER.value,
            new_instance['id'],
            new_instance,
            ''
        )

        return Response(status=status.HTTP_204_NO_CONTENT)

    @decorators.error_safe
    def list(self, request, *args, **kwargs):
        self.serializer_class = serializers.UserManagementRetreiveSerializer
        return super(UsersManagementViewSet, self).list(request)

    @decorators.error_safe
    def retrieve(self, request, *args, **kwargs):
        self.serializer_class = serializers.UserManagementRetreiveSerializer

        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

    @decorators.error_safe
    @transaction.atomic
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)

        pk = serializer.data['id']
        createdUser = models.User.objects.filter(id=pk).first()
        createdUser.set_password(settings.USER_DEFAULT_PASSWORD)
        createdUser.save()
        
        # LOG ADD
        log_save.log_save(
            enums.LogEnum.ADD.value,
            enums.LogEntitiesEnum.USER.value,
            model_to_dict(createdUser))

        return Response(serializer.data,
                        status=status.HTTP_201_CREATED,
                        headers=headers)

    @decorators.error_safe
    @transaction.atomic
    def perform_update(self, serializer):
        fromObj = copy.copy(serializer.instance)
        serializer.save()
        toObj = copy.copy(serializer.instance)
        log_save.log_save(
            enums.LogEnum.UPDATE.value,
            enums.LogEntitiesEnum.USER.value,
            model_to_dict(fromObj),
            model_to_dict(toObj))

    @action(detail=True,
            methods=['put'],
            url_path='upload-profile-picture',
            name="Uploads Profile Picture of User")
    @decorators.error_safe
    @transaction.atomic
    def UploadProfilePicture(self, request, pk=None):
        existingUser = models.User.objects.filter(id=pk).first()
        if existingUser:

            eximages = models.UserImage.objects.filter(user_id=pk)

            if (eximages):
                for item in eximages:
                    item.delete()
                    # DELETE FROM PHYSICAL
                    FileHelper.DeleteFile(path=item.image.path)

            self.serializer_class = app_serializers.UserImageSerializer

            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            self.perform_create(serializer)
            headers = self.get_success_headers(serializer.data)

            return Response(serializer.data,
                            status=status.HTTP_201_CREATED,
                            headers=headers)
        else:
            raise Exception('User not found')
        return Response(data={"detail": "Success"})

    @action(detail=True,
            methods=['put'],
            url_path='reset-password',
            name="Reset Password of User")
    @decorators.error_safe
    @transaction.atomic
    def ResetPassword(self, request, pk=None):
        existingUser = models.User.objects.filter(id=pk).first()
        if existingUser:
            existingUser.set_password(settings.USER_DEFAULT_PASSWORD)

            fromObj = copy.copy(existingUser)
            existingUser.save()
            toObj = copy.copy(existingUser)
            log_save.log_save(
                enums.LogEnum.UPDATE.value,
                enums.LogEntitiesEnum.ROBOT.value,
                model_to_dict(fromObj),
                model_to_dict(toObj))
        else:
            raise Exception('User not found')
        return Response(data={"detail": "Success"})

    @action(detail=True,
            methods=['put'],
            url_path='change-password',
            name="Change Password of User")
    @decorators.error_safe
    @transaction.atomic
    def ChangePassword(self, request, pk=None):
        self.serializer_class = serializers\
            .ChangePasswordSerializer

        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():

            form = copy.deepcopy(serializer.validated_data)

            if form['new_password'] != form['new_password_confirm']:
                raise Exception('Passwords must match')

            existingUser = models.User.objects.filter(id=pk).first()
            if existingUser:
                user = authenticate(
                    username=existingUser.username,
                    password=form['old_password'])
                if user:
                    existingUser.set_password(form['new_password_confirm'])

                    fromObj = copy.copy(existingUser)
                    existingUser.save()
                    toObj = copy.copy(existingUser)
                    log_save.log_save(
                        enums.LogEnum.UPDATE.value,
                        enums.LogEntitiesEnum.ROBOT.value,
                        model_to_dict(fromObj),
                        model_to_dict(toObj))

                    return Response(data={"detail": "Success"},
                                    status=200)
                else:
                    raise Exception("Invalid Old Password")
            else:
                raise Exception('User not found')
        else:
            serializer.is_valid(raise_exception=True)

        return Response(data={"detail": "Error"}, status=500)

    @action(detail=True,
            methods=['put'],
            url_path='add-special-permissions',
            name="Adds special permissions to user")
    @decorators.error_safe
    @transaction.atomic
    def UserSpecialPermissions(self, request, pk=None):

        user = models.User.objects.filter(id=pk).first()
        if not user:
            raise Exception('User not found')

        # CLEARES ALL USER'S SPECIAL PERMISSION'
        for i in user.special_permissions.all():
            i.delete()

        user.save()

        # LOAD NEW USER'S NEW SPECIAL PERMISSIONS
        form = copy.deepcopy(request.data)

        for spid in form['special_permissions']:

            sp = models.Permission.objects.filter(id=spid).first()

            if not sp:
                raise Exception(F"{spid} does not exists")

        return Response(data={"detail": "Success"}, status=200)

    # # Lists ALL Application Permissions (No Pagination)
    # @action(detail=False,
    #         methods=['get'],
    #         url_path='all-permissions',
    #         name="Lists all Application's Permissions")
    # @decorators.error_safe
    # def AllPermissions(self, request, *args, **kwargs):
    #     return Response(
    #         models.Permission.objects.values(
    #             permissionId=F('id'),
    #             permissionCode=F('code')
    #         )
    #     )
