
from django.contrib.auth import logout
from rest_framework.permissions import IsAuthenticated
from rest_framework.filters import SearchFilter
from  users.serializers import *
from rest_framework import viewsets
from rest_framework.views import APIView
from django.contrib.auth import get_user_model
from users.models import * 
from users.helper import * 
from organisations.models import * 
from rest_framework_jwt.views import ObtainJSONWebToken
from datetime import datetime 
from django.utils import timezone
from rest_framework.response import Response
from rest_framework import status
from questbanker_api.utils import get_current_user,get_logged_in_user_key
from django.db.models import Q
from users.audit_log_helper import *
from general.permissions import *
from exservices.exservices_helper import send_otp_pin, validate_working_hours
from .rate_limiting import rate_limit_otp
import random
from django.contrib.auth import authenticate
from django.contrib.auth.hashers import check_password
from rest_framework.permissions import AllowAny
from django.core.cache import cache
import hashlib
from customers.serializers import *
from customers.models import *
from customers.helper import *
from organisations.models import *
from mmbanking.models import *
from exservices.exservices_helper import *
from license.helpers import get_organisation_access_state
# from django.utils import timezone


class StaffUsersView(APIView):
    def get(self,request, format=None):
        data  = []
        staff =  []
        filter_array = {}
        organisation_id = get_current_user(self.request, 'organisation_id', 1)
        search = request.GET.get('search',None)
        filter_array["is_active"] = True
        filter_array["staff_organisation__id"] = organisation_id
        if search:
            staff = Staff.objects.filter((Q(name__icontains=search) | Q(staff_number__icontains=search)),is_active=True,staff_organisation__id= organisation_id).order_by('-id')
        else:
            staff = Staff.objects.filter(is_active=True,staff_organisation__id= organisation_id).order_by('-id')
        if staff:
            for stf in staff:
                user = get_user_model().objects.filter(user_staff__id=stf.id).first()
                user_branch    = None
                user_id        = None
                is_user_active = None
                username    = ''
                user_role   = ''
                branch_name = ''
                if user:
                    user_id        = user.id
                    user_branch    = user.user_organisation_branch.id
                    is_user_active = user.is_active
                    username       = user.username
                    branch_name    = user.user_organisation_branch.name
                    role = UserAssignedRole.objects.filter(user__id=user_id).first()
                    if role:
                        user_role = role.assigned_role.role_name

                data.append(
                {
                    "id":stf.id,
                    "date_added":stf.date_added,
                    "name":stf.name,
                    "phone_number":stf.phone_number,
                    "email":stf.email,
                    "dob":stf.dob,
                    "nin":stf.nin,
                    "passport_number":stf.passport_number,
                    "nationality":stf.nationality,
                    "gender":stf.gender,
                    "marital_status":stf.marital_status,
                    "occupation":stf.occupation,
                    "staff_number":stf.staff_number,
                    "status":stf.status,
                    "is_active":stf.is_active,
                    "staff_organisation":stf.staff_organisation.id,
                    "user_branch":user_branch,
                    "user_branch_name":branch_name,
                    "user_id":user_id,
                    "is_user_active":is_user_active,
                    "username":username,
                    "profile_url":stf.profile_url,
                    "user_role":user_role
                })
        return Response(data)

class StaffView(viewsets.ModelViewSet):
    serializer_class = StaffSerializer

    def get_queryset(self):
        id  = self.request.query_params.get('id')
        organisationid = get_current_user(self.request, 'organisation_id', 1)
        organisation   = Organisation.objects.get(id=organisationid)
        staff_number   = self.request.query_params.get('staff_number')

        if staff_number:
            return Staff.objects.filter(staff_organisation=organisation,staff_number=staff_number,is_active=True)

        if id:
            queryset = Staff.objects.filter(id=id,staff_organisation=organisation,is_active=True)
        else:
            queryset = Staff.objects.filter(staff_organisation=organisation,is_active=True).all()
        return queryset

    def perform_create(self, serializer):
        organisationid  = get_current_user(self.request, 'organisation_id', 1)
        organisation    = Organisation.objects.get(id=organisationid)
        request_data    = self.request.data
        identity_type   = request_data.get('identity_type')
        nin             = ''
        passport_number = ''

        if identity_type == 'passport':
            passport_number = request_data.get('identity_number')
        else:
            nin = request_data.get('identity_number')
            
        staff = serializer.save(name=request_data.get('name'), staff_organisation = organisation,
        staff_added_by = self.request.user,passport_number = passport_number,nin = nin)
        
        # Send SMS notification for new staff registration
        self.send_staff_registration_sms(staff, organisation) 
    
    def send_staff_registration_sms(self, staff, organisation):
        """
        Send SMS notification to new staff member
        """
        try:
            from exservices.exservices_helper import send_sms, format_phone_number
            
            # Get staff phone number if available
            staff_phone = None
            if hasattr(staff, 'phone_number') and staff.phone_number:
                staff_phone = staff.phone_number
            elif hasattr(staff, 'other_phone') and staff.other_phone:
                staff_phone = staff.other_phone
            
            if staff_phone:
                # Format the phone number
                formatted_phone = format_phone_number(staff_phone)
                
                # Create SMS message
                message = f"Dear {staff.name}, Welcome to {organisation.name}! You have been registered as a staff member on QBcore. Please contact your administrator for login credentials. Thank you."
                
                # Send SMS
                sms_result = send_sms(formatted_phone, message)
                
                if sms_result.get('status'):
                    print(f"SMS sent successfully to {formatted_phone} for staff {staff.name}")
                else:
                    print(f"Failed to send SMS to {formatted_phone}: {sms_result.get('comment', 'Unknown error')}")
            else:
                print(f"No phone number found for staff {staff.name}, SMS not sent")
                
        except Exception as e:
            print(f"Error sending SMS for staff {staff.name}: {str(e)}")
        
                
           
    def perform_update(self, serializer):
        request_data = self.request.data
        action       = request_data.get('action')
        branch_id    = get_current_user(self.request, 'organisation_branch_id', 1)
        branch       = OrganisationBranch.objects.get(id=branch_id)
        reason       = ''
        staff_id     = self.kwargs.get('pk',self.kwargs.get('id'))
        staff        = Staff.objects.get(pk=staff_id)
        old_details  = StaffSerializer(staff,read_only=True).data
        action_perform = ''
        if action == 'DELETE':
            action_perform = 'delete_staff'
            reason = request_data.get('delete_reson','')
            staff  = serializer.save()
            if staff:
                staff.is_active = False
                staff.save()
                message = 'Deleted staff details for: '+staff.name
        else:
            action_perform = 'update_staff'
            staff = serializer.save()
            message = 'Updated staff details for: '+staff.name
            
        new_details = StaffSerializer(staff,read_only=True).data
        add_system_audit_trail('staff_management',action_perform,message,reason,old_details,new_details,self.request.user,branch)
    
class UserView(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    filter_backends = (SearchFilter, )
    search_fields = ('user_staff__name','username')

    def get_queryset(self):
        
        organisationid = get_current_user(self.request, 'organisation_id', 1)
        organisation   = Organisation.objects.get(id=organisationid)
        staffid        = self.request.query_params.get('staffid')

        if staffid:
            queryset = User.objects.filter(user_staff__id=staffid)
        else:
            queryset = User.objects.filter(user_staff__staff_organisation = organisation).all()
        return queryset
        
    def perform_create(self, serializer):
        
        branchid  = self.request.data.get('user_organisation_branch_id')
        if not branchid:
            branchid = get_current_user(self.request, 'organisation_branch_id', 1) 

        branch    = OrganisationBranch.objects.get(id=branchid)
        id        = self.request.data.get('id')
        username  = self.request.data.get('username')
        role_id   = self.request.data.get('user_role')
        saveUser  = None
        
        if id == 0:
            staff_id   = self.request.data.get('staff_id')
            user_staff = Staff.objects.get(id=staff_id)
            password   = self.request.data.get('password')
            saveUser   = serializer.save(username=username,password=password,user_staff=user_staff,user_organisation_branch=branch,user_added_by=self.request.user.id) 
            if saveUser:
                 saveUser.set_password(password)
                 saveUser.save()
                 if role_id:
                    user_role = UserRole.objects.get(id=role_id) 
                    user_assigned_role_field={"assigned_role":user_role,"assigned_role_added_by":self.request.user,"user":saveUser,"is_active":True}
                    UserAssignedRole.objects.create(**user_assigned_role_field)
                
                 # Send SMS notification for new user registration
                 self.send_user_registration_sms(saveUser, password, branch)
    
    def send_user_registration_sms(self, user, password, branch):
        """
        Send SMS notification to new user with their credentials
        """
        try:
            from exservices.exservices_helper import send_sms, format_phone_number
            
            # Get staff phone number if available
            staff_phone = None
            if hasattr(user.user_staff, 'phone_number') and user.user_staff.phone_number:
                staff_phone = user.user_staff.phone_number
            elif hasattr(user.user_staff, 'other_phone') and user.user_staff.other_phone:
                staff_phone = user.user_staff.other_phone
            
            if staff_phone:
                # Format the phone number
                formatted_phone = format_phone_number(staff_phone)
                
                # Create SMS message
                organization_name = branch.branch_organisation.name
                message = f"Dear {user.user_staff.name}, {organization_name} has registered you on QBcore. Your username is {user.username} and password is {password}. Thank you."
                
                # Send SMS
                sms_result = send_sms(formatted_phone, message)
                
                if sms_result.get('status'):
                    print(f"SMS sent successfully to {formatted_phone} for user {user.username}")
                else:
                    print(f"Failed to send SMS to {formatted_phone}: {sms_result.get('comment', 'Unknown error')}")
            else:
                print(f"No phone number found for staff {user.user_staff.name}, SMS not sent")
                
        except Exception as e:
            print(f"Error sending SMS for user {user.username}: {str(e)}")
    
    def perform_update(self, serializer):
        branchid  = self.request.data.get('user_organisation_branch')
        password  = self.request.data.get('password')
        role_id   = self.request.data.get('assigned_role')
        change_password    = self.request.data.get('change_password')
        user_assigned_role = None
        old_role_id  = 0
        user_role    = None
        reason       = ''
        message      = ''
        user_id      = self.kwargs.get('pk',self.kwargs.get('id'))
        old_user     = User.objects.get(pk=user_id)
        old_user_details = UserSerializer(old_user,read_only=True).data
        branch       = OrganisationBranch.objects.get(id=branchid)
        old_role     = UserAssignedRole.objects.filter(user=old_user).first()
        old_role_details = UserAssignedRoleSerializer(old_role,read_only=True).data
        saveUser         = serializer.save(user_organisation_branch_id=branchid,user_added_by=self.request.user.id)
       
        if old_role:
            old_role_id = old_role.assigned_role.id
        
        if(old_user_details['user_organisation_branch'] != saveUser.user_organisation_branch):
            message = 'Updated User Assigned Branch For: '+saveUser.user_staff.name
            add_system_audit_trail('user_management','user_update',message,reason,{"user_organisation_branch":saveUser.user_organisation_branch.name},{"user_organisation_branch":saveUser.user_organisation_branch.name},self.request.user,branch)
        
        if(old_user_details['is_active'] != saveUser.is_active):
            message = 'Updated User Account Status For: '+saveUser.user_staff.name
            add_system_audit_trail('user_management','user_update',message,reason,{"is_active":saveUser.is_active},{"is_active":saveUser.is_active},self.request.user,branch)
        
        if (old_user_details['assigned_days'] != saveUser.assigned_days):
            message = 'Updated User Assigned days For: '+saveUser.user_staff.name
            add_system_audit_trail('user_management','user_update',message,'',{"assigned_days":saveUser.assigned_days},{"assigned_days":saveUser.assigned_days},self.request.user,branch)

        if(old_user_details['two_fa_status'] != saveUser.two_fa_status):
            message = 'Updated User 2FA Status For: '+saveUser.user_staff.name
            add_system_audit_trail('user_management','user_update',message,'',{"two_fa_status":old_user.two_fa_status},{"two_fa_status":saveUser.two_fa_status},self.request.user,branch)
        
        if(old_user_details['username'] != saveUser.username):
            message = 'Updated User Name For: '+saveUser.user_staff.name
            add_system_audit_trail('user_management','user_update',message,'',{"username":old_user.username},{"two_fa_status":saveUser.username},self.request.user,branch)
        

        if  saveUser and change_password == True:
            message = 'Updated User Password For: '+saveUser.user_staff.name
            add_system_audit_trail('user_management','user_update',message,'',{},{},self.request.user,branch)
            saveUser.set_password(password)
            saveUser.save()
        
        if role_id:
            user_role = UserRole.objects.get(id=self.request.data.get('assigned_role'))
            
        user_assigned_role = UserAssignedRole.objects.filter(user=saveUser).first()
        if user_assigned_role:
            if user_role:
                user_assigned_role.assigned_role = user_role
            user_assigned_role.user = saveUser
            user_assigned_role.assigned_role_added_by = self.request.user
            user_assigned_role.save()
        else:
            if user_role:
                user_assigned_role_field={"assigned_role":user_role,"assigned_role_added_by":self.request.user,"user":saveUser,"is_active":True}
                user_assigned_role = UserAssignedRole.objects.create(**user_assigned_role_field)

        if (old_role_id > 0) and (old_role_id != user_assigned_role.assigned_role.id) and user_assigned_role:
            message          = 'Updated User Role for: '+saveUser.user_staff.name
            new_role_details = UserAssignedRoleSerializer(user_assigned_role,read_only=True).data
            add_system_audit_trail('user_management','user_role_update',message,reason,old_role_details,new_role_details,self.request.user,branch)

class ActivateUserAccountView(APIView):

    def post(self, request):
        '''
        Activate/ De-Activate User Account
        '''
        request_data = request.data
        accounts     = request_data.get('accounts') 
        is_active    = request_data.get('is_active') 
        if accounts:
            if len(accounts) > 0:
                for id in accounts:
                    user = User.objects.get(id=id)
                    user.is_active = is_active
                    user.save()
        return Response({"message":"Users updated successfully"}, status=status.HTTP_200_OK)
       
class UserAssignedRoleView(viewsets.ModelViewSet):
    serializer_class = UserAssignedRoleSerializer
    def get_queryset(self):
        user_id  = self.request.query_params.get('user_id',None)
        if user_id:
            queryset = UserAssignedRole.objects.filter(user__id=user_id)
            return queryset
        else:
            queryset = UserAssignedRole.objects.all()
            return queryset
        
    def perform_create(self, serializer):
        assigned_role   = self.request.data.get('assigned_role')
        username  = self.request.data.get('username')
        user_id   = self.request.data.get('user')
        branchid  = self.request.data.get('user_organisation_branch_id')
        
        if not branchid:
            branchid = get_current_user(self.request, 'organisation_branch_id', 1) 

        user_role = UserRole.objects.get(id=assigned_role) 
        user = User.objects.get(id=user_id)
        user.user_organisation_branch = OrganisationBranch.objects.get(id=branchid)
        
        if user.username != username:
            user.username = username
        user.save()
        user_assigned_role = UserAssignedRole.objects.filter(user=user).first()
        
        if user_assigned_role:
            user_assigned_role.is_active = True
            user_assigned_role.assigned_role = user_role
            user_assigned_role.assigned_role_added_by = self.request.user
            user_assigned_role.save()
        else:
            serializer.save(assigned_role_added_by=self.request.user) 

class RolesAssignedUsersView(APIView):
    def get(self,request, format=None):
        users_data =  []
        role_id = request.GET.get('role_id',0)
        user_ids = UserAssignedRole.objects.filter(assigned_role__id=role_id).values('user_id')
        users = get_user_model().objects.filter(id__in=user_ids)
        
        if users:
                serializer = UserSerializer(users, many=True)
                users_data = serializer.data
        return Response({
            "count": len(users_data),
            "results": users_data
        })

class RestAPIJWT(ObtainJSONWebToken):
    def post(self, request, *args, **kwargs):
        # Extract user credentials from the request
        username = request.data.get('username')
        password = request.data.get('password')

        # Authenticate the user
        user = authenticate(username=username, password=password)
        if user:
            organisation = getattr(getattr(user, 'user_organisation_branch', None), 'branch_organisation', None)
            access_state = get_organisation_access_state(organisation=organisation, force_sync=True)
            if not access_state['allowed']:
                return Response({
                    "status": False,
                    "message": access_state['message']
                }, status=status.HTTP_403_FORBIDDEN)

            # Serialize the user data to access `with_in_working_hours`
            user_role = None
            user_current_role = UserAssignedRole.objects.filter(user=user).first()
            if user_current_role:
                user_role = user_current_role.assigned_role

            with_in_working_hours = validate_working_hours(user, user_role)
            if not with_in_working_hours:
                return Response({
                    "error": "Login not allowed outside of organisation working hours."
                }, status=status.HTTP_403_FORBIDDEN)

        # Proceed with the standard JWT token generation
        response = super().post(request, *args, **kwargs)
        return response

class VerifyOTPView(APIView):
    permission_classes = [AllowAny, IsPostOnly]
    
    @rate_limit_otp(max_requests=10, window_minutes=15)
    def post(self, request, format=None):
        pin = request.data.get('pin')
        action = request.data.get('action')
        user = request.user
        user_session = None

        if not user or not user.is_authenticated:
            return Response({"status": False, "message": "Authentication required."}, status=status.HTTP_401_UNAUTHORIZED)

        if action not in ['send_otp', 'verify_otp']:
            return Response({"status": False, "message": "Invalid action."}, status=status.HTTP_400_BAD_REQUEST)

        auth_header = request.META.get('HTTP_AUTHORIZATION', '')
        token = None
        if auth_header and ' ' in auth_header:
            token = auth_header.split(' ', 1)[1].strip()
        elif auth_header:
            token = auth_header.strip()

        if not token:
            return Response({"status": False, "message": "Authorization token required."}, status=status.HTTP_401_UNAUTHORIZED)

        user_session = UserSession.objects.filter(user=user, session_token=token).first()
        if not user_session:
            return Response({"status": False, "message": "Invalid or expired session."}, status=status.HTTP_401_UNAUTHORIZED)

        otp_cache_key = f"login_otp_{user.id}_{hashlib.md5(token.encode()).hexdigest()}"

        if action == 'send_otp':
            # Check if user is locked
            if user.is_otp_locked():
                return Response({"status":False,"message":"Account temporarily locked. Try again later."})

            now = timezone.now()
            pin_expires_at = user._normalize_dt(user.pin_expires_at)
            cached_otp = cache.get(otp_cache_key)
            existing_otp_valid = False
            if cached_otp is not None:
                existing_otp_valid = True
            elif pin_expires_at and now < pin_expires_at:
                existing_otp_valid = True

            if existing_otp_valid:
                staff_phone = getattr(user.user_staff, "phone_number", None)
                if not staff_phone:
                    return Response({"status":False,"message":"User phone number is missing."}, status=status.HTTP_400_BAD_REQUEST)
                return Response({
                    "status": True,
                    "message": "OTP already sent. Please check SMS.",
                    "telephone": staff_phone
                })
            
            # Check rate limiting
            if not user.can_request_otp():
                return Response({"status":False,"message":"Please wait before requesting another OTP."})
            
            # Generate and send OTP
            pin = random.randint(pow(10, 3), pow(10, 4) - 1)
            user.set_otp(pin)
            user.last_otp_request = timezone.now()
            user.save(update_fields=['last_otp_request'])
            cache.set(otp_cache_key, str(pin), 5 * 60)

            staff_phone = getattr(user.user_staff, "phone_number", None)
            if not staff_phone:
                return Response({"status":False,"message":"User phone number is missing."}, status=status.HTTP_400_BAD_REQUEST)
            
            subscriber_data = {
                "sms_type":None,
                "charge":0,
                "charged_to":'sacco',
                "telephone":staff_phone,
                "recieved_by":user.id,
                "is_subscribed":False,
                "debit_chart":None, 
                "free_sms":0,
                "sms_unique_key":'',
                "recieved_by_type":'User',
                "reciever_name":user.user_staff.name,
                "sent_by":user,
                "branch":user.user_organisation_branch,
                "message":f'Your login OTP is: {pin}. Valid for 5 minutes. Do not share.\nQuest Banker'
            }
            sms_data = send_otp_pin(subscriber_data)
            if not sms_data.get("status"):
                return Response({
                    "status": False,
                    "message": sms_data.get("comment", "Failed to send OTP. Please try again.")
                })
            # Keep backward-compatible payload expected by existing frontend logic.
            return Response({"status":True,"message":"","telephone":staff_phone})
        
        if action == 'verify_otp':
            otp_input = ''.join(ch for ch in str(pin or '') if ch.isdigit())
            if otp_input == '':
                return Response({"status":False,"message":"OTP pin is required."}, status=status.HTTP_400_BAD_REQUEST)

            # Check if user is locked
            if user.is_otp_locked():
                user_session.allow_access = False
                user_session.save(update_fields=["allow_access"])
                return Response({"status":False,"message":"Account temporarily locked. Try again later."})
            
            # Verify OTP
            cached_otp = cache.get(otp_cache_key)
            is_verified = False
            if cached_otp is not None:
                is_verified = (otp_input == str(cached_otp))
            else:
                # Fallback to DB verification for compatibility.
                is_verified = user.verify_otp(otp_input)

            if is_verified:
                user.reset_otp_attempts()
                user_session.allow_access = True
                user_session.save(update_fields=["allow_access"])
                cache.delete(otp_cache_key)
                return Response({"status":True,"message":"OTP verified successfully"})

            user.increment_otp_attempts()
            user_session.allow_access = False
            user_session.save(update_fields=["allow_access"])
            if user.is_otp_locked():
                return Response({"status":False,"message":"Too many failed attempts. Account locked for 15 minutes."})
            attempts_left = max(0, 5 - user.otp_attempts)
            return Response({"status":False,"message":f"Invalid OTP. {attempts_left} attempts remaining."})

class LockUserAccountView(APIView):
    permission_classes = [AllowAny, IsPostOnly]
    
    def post(self, request, format=None):
        user_session = None
        res_status   = False
        action       = request.data.get('action')

        if action == 'lock_account':
            data = {"user__id": self.request.user.id}
            if request.META.get('HTTP_AUTHORIZATION', None):
                token = self.request.META.get('HTTP_AUTHORIZATION').split(' ')[1]        
                data['session_token'] = token
                user_session = UserSession.objects.filter(**data).first()
                if user_session:
                    res_status = True 
                    user_session.is_locked = True
                    user_session.save()
                

        if action == 'unlock_account':
            username = request.data.get("username")
            password = request.data.get("password")
            correct  = False

            try:
                user = User.objects.get(username=username)
                correct = check_password(password, user.password)
            except User.DoesNotExist:
                # Handle the case where the user does not exist
                return Response({"status":False})
            
            if correct:
                data = {"user__id": self.request.user.id}
                if request.META.get('HTTP_AUTHORIZATION', None):
                    token = self.request.META.get('HTTP_AUTHORIZATION').split(' ')[1]        
                    data['session_token'] = token
                    user_session = UserSession.objects.filter(**data).first()
                    if user_session:
                        res_status = True 
                        user_session.is_locked = False
                        user_session.save()

        return Response({"status":res_status})
     

class LogOutUserView(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request):
        user_sessions = UserSession.objects.filter(user=request.user)
        if user_sessions:
                for user_session in user_sessions:
                    if user_session.session_token == get_logged_in_user_key():
                        user_session.delete()
        logout(request) 
        return Response({"message":"successfully logged out"}, status=status.HTTP_200_OK)

class ChangePasswordViewSet(APIView):
    '''
    change password view
    {"old_password":"","new_password":""}
    '''
    def get_object(self, queryset=None):
        return self.request.user

    def put(self, request, *args, **kwargs):
        self.object = self.get_object()
        serializer = ChangePasswordSerializer(data=request.data)

        if serializer.is_valid():
            # Check old password
            old_password = serializer.data.get("old_password")
            if not self.object.check_password(old_password):
                return Response({"message":"Wrong old password."}, 
                                status=status.HTTP_400_BAD_REQUEST)

            # set_password also hashes the password that the user will get
            self.object.set_password(serializer.data.get("new_password"))
            if not self.object.updated_password:
                self.object.updated_password = True
            self.object.save()
            return Response({"message":"change successfully"},status=status.HTTP_201_CREATED)
        return Response({"message":"Wrong credentials"}, status=status.HTTP_400_BAD_REQUEST)
    
    
class ResetPasswordView(APIView):

    def get_object(self, queryset=None):
        return self.request.user
    '''
    Reset password view
    '''
    def post(self, request, *args, **kwargs):
        user_id = request.GET.get('user_id', None)
        new_password = request.data.get('new_password')

        if user_id:
            user = User.objects.get(id=user_id)
        else:
            return Response({"message": "User with this ID does not exist."}, status=status.HTTP_404_NOT_FOUND)

        user.set_password(new_password)
        user.pass_reset_date = timezone.now()
        user.save()

        return Response({"message": "Password has been reset successfully."}, status=status.HTTP_200_OK)

class AuditCategoryView(viewsets.ModelViewSet):
    serializer_class = AuditCategorySerializer
    def get_queryset(self):
        parent_list = AuditCategory.objects.filter(parent_id = None).values_list('id', flat=True)
        return AuditCategory.objects.all().exclude(id__in=parent_list)
    
class SystemAuditLogAPIView(APIView):
    
    def get(self,request, format=None):
        audit_logs   = []
        q_filters    = {}
        # request_data = self.request.query_params

        start_date = request.GET.get('start',None)
        end_date   = request.GET.get('end',None)
        user_id    = request.GET.get('user_id',None)
        branch_id  = request.GET.get('branch_id',None)
        category   = request.GET.get('category',None)
        page       = request.GET.get('page',None)
        search     = request.GET.get('search',None)
        page_size  = request.GET.get('page_size',None)

        start_date = make_aware(datetime.strptime(start_date + ' 00:00', '%Y-%m-%d %H:%M'))
        end_date   = make_aware(datetime.strptime(end_date + ' 23:59', '%Y-%m-%d %H:%M'))
        organisationid = get_current_user(self.request, 'organisation_id', 1)

        q_filters['start_date']      = start_date
        q_filters['end_date']        = end_date
        q_filters['user_id']         = user_id
        q_filters['branch_id']       = branch_id
        q_filters['category']        = category
        q_filters['search']          = search
        q_filters['page']            = page
        q_filters['page_size']       = page_size
        q_filters['organisation_id'] = organisationid

        query_set  = retrieve_audit_trails(q_filters)
        results    = query_set["results"]
        
        if len(results) > 0:
            for res in results:
              res['old_details'] =  dict_to_custom_array(update_audit_details(json.loads(res['old_details']),res['action'])) if res['old_details'] else []
              res['new_details'] = dict_to_custom_array(update_audit_details(json.loads(res['new_details']),res['action'])) if res['new_details'] else []
              audit_logs.append(res)
        return Response({
            "count":query_set["count"],
            "results": audit_logs
        })

class PublicMemberRegistration(APIView):
    serializer_class = CustomerSerializer
    authentication_classes = []  # Disable authentication for this view
    permission_classes = []      # Allow public access to this view

    def post(self, request, format=None):
        requestData= self.request.data
        member_number = generate_member_number(requestData.get("branchId"))
        user = User.objects.filter(user_organisation_branch_id=int(requestData.get("branchId"))).first()
        customer = Customer(name=requestData.get('name'), member_number= member_number, telephone=requestData.get('telephone'), gender=requestData.get('gender') , customer_branch_id=int(requestData.get("branchId")), branch_customer_type_id=requestData.get('branch_customer_type'), customer_added_by_id=user.id, customer_officer_id=user.id, date_added=timezone.now() )
        customer.save()    

        pin = random.randint(pow(10, 3), pow(10, 4) - 1)

        activateMM = MobileBankingSubscription(customer_id=customer.id, pin=pin, active=True,telephone_no=requestData.get('telephone'), added_by=user)
        activateMM.save();
        if activateMM:
            sms_text = "Dear "+customer.name.capitalize()+", Welcome to "+" Organisation" + \
                    " mobile banking\n Dial *284*55#. Access MEM NO: " + \
                    customer.member_number+" PIN: "+str(pin)
            send_mm_pin(activateMM, sms_text,user)

        member = GroupMembership(group_id=int(requestData.get('groupId')), member_id=customer.id, role="Member", added_by_id=user.id)
        member.save()

        serializer = self.serializer_class(customer)
        return Response(serializer.data, status=status.HTTP_201_CREATED)
