
import sys

from rest_framework.response import Response
from rest_framework.decorators import api_view
from django.db import transaction
from rest_framework.permissions import (
    AllowAny, 
    IsAuthenticated
)

from rest_framework import status
from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate
from django.contrib.auth.models import User

from django.views.decorators.csrf import csrf_exempt


from rest_framework.decorators import (
    permission_classes, 
    authentication_classes
)
from rest_framework.authentication import (
    SessionAuthentication, 
    BasicAuthentication, 
    TokenAuthentication
)

from customer import journal

from account.models import UserProfile
#from .decorators import define_usage
from account.api.serializers import (
    RegistrationSerializer, 
    UserProfileSerializer, 
    UserSerializer
)
from account import tools as AccountTools

from account.api import errorcode

CURRENT_APP = 'ACCOUNT'

@transaction.atomic
@api_view(['POST',])
def registration_view(request):
    ACTION = 'USER_REGISTRATION'
    if request.method == 'POST':
        try:
            serializer = RegistrationSerializer(data=request.data)
            resp = {} 
            if serializer.is_valid():
                customerprofile = serializer.save()
                
                resp['code'] = errorcode.OK_RESPONSE_CODE
                resp['errormsg'] = ''

                data = {}
                data['email'] = customerprofile.user.email
                data['last_name'] = customerprofile.user.last_name
                data['first_name'] = customerprofile.user.first_name
                data['customer_name'] = customerprofile.customer.customer_name
                
                resp['data'] = data

                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'User registration --> ' + json.dumps(data),
                    journal.JOURNAL_OPERATION_OK, 
                    request
                )
                return Response(
                    resp, 
                    status=status.HTTP_200_OK)
            else:
                resp['code'] = errorcode.BAD_MESSAGE_FORMAT

                errormsg = ''
                for key in  serializer.errors:
                    if errormsg != '':
                        errormsg = errormsg + ', '
                    errormsg = errormsg + serializer.errors[key]

                resp['errormsg'] = errormsg
                resp['data'] = {}

                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'User registration error --> ' + errormsg,
                    journal.JOURNAL_OPERATION_ERROR, 
                    request
                )

                return Response(
                    resp, 
                    status=status.HTTP_400_BAD_REQUEST)            
            
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User registration error --> System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY, 
                request
            )
            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@api_view(['POST'])
@permission_classes((AllowAny,))
def api_signin(request):
    ACTION = 'USER_SIGNIN'
    if request.method == 'POST':
        try:
            try:
                #print('request data = ', request.data)
                username = request.data['username']
                password = request.data['password']
            except:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Please provide correct username and password ',
                    journal.JOURNAL_OPERATION_ERROR, 
                    request
                )
                return Response({
                    'code':errorcode.BAD_MESSAGE_FORMAT, 
                    'errormsg': 'Please provide correct username and password', 
                    'data':{}
                    },
                    status=status.HTTP_400_BAD_REQUEST)
            user = authenticate(username=username, password=password)
            if user is not None:
                token, _ = Token.objects.get_or_create(user=user)
                seralize_user = UserSerializer(user)
                #print('seralize_user', seralize_user, token)
                data = seralize_user.data
                data['token'] = token.key

                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'User Login --> ' + request.data['username'],
                    journal.JOURNAL_OPERATION_OK, 
                    request
                )
                return Response({
                    'code': errorcode.OK_RESPONSE_CODE, 
                    'errormsg':'', 
                    'data':data
                    },
                    status=status.HTTP_200_OK)
            else:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Invalid Login or Parssword  --> ' + request.data['username'],
                    journal.JOURNAL_OPERATION_ERROR, 
                    request
                )
                return Response({
                    'code': errorcode.INVALID_CREDENTIALS, 
                    'errormsg':'Invalid Login or Parssword',
                    'data':request.data
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'Login error --> System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY, 
                request
            )

            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@csrf_exempt
@api_view(['GET',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def users_list(request):
    ACTION = 'USER_LIST'
    if request.method == 'GET':
        try:
            if not request.user.is_staff:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'A not staff user want the list of users',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only an administrator can see the list of users", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)

            try:
                userprofile = UserProfile.objects.get(user=request.user)
            except UserProfile.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Unknown profile.',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"Unknown profile.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)

            userprofiles = UserProfile.objects.select_related('user').filter(customer=userprofile.customer)
            serializer = UserProfileSerializer(userprofiles, many=True)
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User list return',
                journal.JOURNAL_OPERATION_OK,
                request
            )

            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 
                "errormsg":"", 
                "data":serializer.data
                },
                status=status.HTTP_200_OK)
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User list error --> System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )
            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@transaction.atomic
@api_view(['POST',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def activate_user(request):
    ACTION = 'USER_ACTIVATION'
    if request.method == 'POST':
        try:
            if not request.user.is_staff:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    "Only an administrator can see the list of users.",
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only an administrator can see the list of users.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
            try:
                user = User.objects.get(user=request.data['user'])
            except User.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    "Unknown User.",
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"Unknown User.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED) 

            if not AccountTools.isMyCompagnyUser(request.user, user):
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    "User not in my compagny --> " + user + ' : ' + request.user,
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.IS_NOT_IN_COMPAGNY, 
                    'errormsg':"User not in my compagny --> " + user + ' : ' + request.user, 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)

            user.is_active = True
            user.save()
            seralize_user = UserSerializer(user)

            journal.addRow(
                CURRENT_APP,
                ACTION,
                "User activated.",
                journal.JOURNAL_OPERATION_OK,
                request
            )

            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 
                "errormsg":"", 
                "data":seralize_user.data
                },
                status=status.HTTP_200_OK)
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )
            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@transaction.atomic
@api_view(['POST',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def deactivate_user(request):
    ACTION='USER_DEACTIVATION'
    if request.method == 'POST':
        try:
            if not request.user.is_staff:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'A nonstaff member want to deactivate a user',
                    journal.JOURNAL_OPERATION_WARNING,
                    request
                )

                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only an administrator can see the list of users", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
            try:
                user = User.objects.get(user=request.data['user'])
            except User.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Unknown User want to deactivate a user',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"Unknown User.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)  

            if not AccountTools.isMyCompagnyUser(request.user, user):
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Cannot deactivate a user not in my compagny.',
                    journal.JOURNAL_OPERATION_WARNING,
                    request
                )

                return Response({
                    "code":errorcode.IS_NOT_IN_COMPAGNY, 
                    'errormsg':"User not in my compagny.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)

            user.is_active = False
            user.save()
            seralize_user = UserSerializer(user)
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User deactivated --> ' + user,
                journal.JOURNAL_OPERATION_OK,
                request
            )

            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 
                "errormsg":"", 
                "data":seralize_user.data
                },
                status=status.HTTP_200_OK)
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )

            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@transaction.atomic
@api_view(['POST',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def set_user_is_staff(request):
    ACTION='USER_SET_STAFF'
    if request.method == 'POST':
        try:
            if not request.user.is_superuser:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Only a supper user can set a user as staff member --> ' + request.user,
                    journal.JOURNAL_OPERATION_WARNING,
                    request
                )
                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only the supper user can set a user as staff member", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
            try:
                user = User.objects.get(user=request.data['user'])
            except User.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'This user doest not exist. and want to set an other user as a staff member',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"This user doest not exist.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)  

            if not AccountTools.isMyCompagnyUser(request.user, user):
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'This User not in my compagny. Cannot set him as a staff member --> ' + user,
                    journal.JOURNAL_OPERATION_WARNING,
                    request
                )

                return Response({
                    "code":errorcode.IS_NOT_IN_COMPAGNY, 
                    'errormsg':"User not in my compagny.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)

            user.is_staff = True
            user.save()
            seralize_user = UserSerializer(user)

            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User set as staff member --> ' + user,
                journal.JOURNAL_OPERATION_OK,
                request
            )

            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 
                "errormsg":"", 
                "data":seralize_user.data
                },
                status=status.HTTP_200_OK)
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )

            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@transaction.atomic
@api_view(['POST',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def unset_user_is_staff(request):
    ACTION='USER_UNSET_STAFF'
    if request.method == 'POST':
        try:
            if not request.user.is_superuser:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Only a supper user can remove a user from a staff member  --> ' + request.user,
                    journal.JOURNAL_OPERATION_WARNING,
                    request
                )
                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only the supper user can set a user as staff member", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
            try:
                user = User.objects.get(user=request.data['user'])
            except User.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'An unkown user want to remove a user from a staff member  --> ' + request.user,
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"This user does not exist.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)  

            if not AccountTools.isMyCompagnyUser(request.user, user):
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Want to remove a user not in my comagny from the list of staff member  --> ' + user,
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.IS_NOT_IN_COMPAGNY, 
                    'errormsg':"User not in my compagny.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)

            user.is_staff = False
            user.save()
            seralize_user = UserSerializer(user)

            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User removed from the list of staff member  --> ' + user,
                journal.JOURNAL_OPERATION_OK,
                request
            )

            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 
                "errormsg":"", 
                "data":seralize_user.data
                },
                status=status.HTTP_200_OK)
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )
            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@transaction.atomic
@api_view(['POST',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def delete_user(request):
    ACTION='USER_DELETE'
    if request.method == 'POST':
        try:
            if not request.user.is_superuser:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Only a supper user can delete a user.',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only a supper user can delete a user.",
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
            try:
                user = User.objects.get(id=request.data['user'])
            except User.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Cannot delete this user because he does not exist --> ' + str(request.data['user']),
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"This user does not exist.",
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)  
            if user.is_superuser:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Cannot delete the supper user.',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response(
                    {"code":errorcode.CANNOT_DELETE_SUPPER_USER, 
                    'errormsg':"Cannot delete the supper user.",
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED) 

            if not AccountTools.isMyCompagnyUser(request.user, user):
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    'Cannot delete a user not in my compagne.',
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response(
                    {"code":errorcode.IS_NOT_IN_COMPAGNY, 
                    'errormsg':"User not in my compagny.",
                    "data":{}
                    }, 
                    status=status.HTTP_401_UNAUTHORIZED)

            user.delete()
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'User deleted.',
                journal.JOURNAL_OPERATION_OK,
                request
            )

            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 'errormsg':""},
                status=status.HTTP_200_OK)  
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )
            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()),
                "data":{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

@transaction.atomic
@api_view(['POST',])
@authentication_classes((SessionAuthentication, BasicAuthentication, TokenAuthentication))
@permission_classes((IsAuthenticated,))
def set_supper_user(request):
    ACTION='USER_SET_SUPERUSER'
    if request.method == 'POST':
        try:
            if not request.user.is_superuser:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    "Only the supper user can define an  other one as a supper user.",
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.PERMISSION_DENIED, 
                    "errormsg":"Only the supper user can define a supper user.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)
            
            logged_user = request.user
            try:
                supperuser = User.objects.get(id=request.data['user'])
            except User.DoesNotExist:
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    "The user you want to set a the supper user is not nkown.",
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )
                return Response({
                    "code":errorcode.UNKNOWN_PROFILE, 
                    'errormsg':"This user does not exist.", 
                    "data":{}
                    },
                    status=status.HTTP_401_UNAUTHORIZED)  
            
            if not AccountTools.isMyCompagnyUser(logged_user, supperuser):
                journal.addRow(
                    CURRENT_APP,
                    ACTION,
                    "The user you want to set a the supper user is not in your compagny --> " + supperuser,
                    journal.JOURNAL_OPERATION_ERROR,
                    request
                )

                return Response({
                    "code":errorcode.IS_NOT_IN_COMPAGNY, 
                    'errormsg':"User not in my compagny.", 
                    "data":{}},
                    status=status.HTTP_401_UNAUTHORIZED)

            logged_user.is_superuser = False
            logged_user.save()
            supperuser.is_superuser = True
            supperuser.save()
            journal.addRow(
                CURRENT_APP,
                ACTION,
                "New supper user set -->  " + supperuser,
                journal.JOURNAL_OPERATION_OK,
                request
            )
            return Response({
                "code":errorcode.OK_RESPONSE_CODE, 
                'errormsg':"", 
                "data":{}},
                status=status.HTTP_200_OK)  
        except Exception as error:
            journal.addRow(
                CURRENT_APP,
                ACTION,
                'System ERROR -> ' + str(sys.exc_info()),
                journal.JOURNAL_OPERATION_EMERGENCY,
                request
            )

            return  Response({
                "code":errorcode.SERVER_ERROR, 
                'errormsg':'System ERROR -> ' + str(sys.exc_info()), 
                'data':{}
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR)

