from django.shortcuts import render, redirect
from django.views import View
from django.contrib.auth.models import User
from django.contrib import messages,auth
from django.http import HttpResponse

from codesofy_lib.custom_config import rename_file,set_user_profile,get_standard_text_input,set_menu_items,get_privilleges,is_authorized,validate_email
from codesofy_lib.custom_config import validate_telephone,validate_mobile,is_super_admin,validate_password,get_max_image_file_size_in_bytes,get_global_master_details
from codesofy_lib.master_details import JobRole,PerPageSelector,UserAccountStatus

from .models import SystemRole, UserProfile, Privilege, MainFeature, SubFeature
from organizationmanagement.models import Country, Branch
from django.db import transaction, IntegrityError
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.db.models import RestrictedError
from django.views.decorators.cache import cache_control
from django.utils.decorators import method_decorator
from django.http import JsonResponse
import json

import os
import math
from io import BytesIO
from PIL import Image
import re
import base64
from binascii import a2b_base64
from django.core.files.uploadedfile import InMemoryUploadedFile
import sys

# Create your views here.

menu_item = "user_management"


def get_active_counsellors():
    counsellors = UserProfile.objects.filter(user__is_active=True)
    return counsellors

def set_sub_menu_item(sub_menu_item,context):
    context = set_menu_items(menu_item,sub_menu_item,context)
    return context


def get_local_master_details():

    context = get_global_master_details()
    countries = Country.objects.all()
    branches = []

    if (len(countries) > 0):

        first_country = countries[0]
        branches = Branch.objects.filter(country=first_country)

    system_roles = SystemRole.objects.all()

    context["countries"] = countries
    context["branches"] = branches
    context["system_roles"] = system_roles
    

    return context


def get_local_master_details_for_user_details():
    context = get_local_master_details()

    job_roles = JobRole.to_list_for_reports()
    user_account_statuses = UserAccountStatus.to_list_for_reports()

    context["job_roles"] = job_roles
    context["user_account_statuses"] = user_account_statuses

    return context


def get_local_master_details_for_add_update_user():

    context = get_local_master_details()

    job_roles = JobRole.to_list()
   
    context["job_roles"] = job_roles
  
    return context


def validate_inputs(request):
        
        username = request.POST['username']
        password = request.POST['password']
        re_typed_password = request.POST['re_typed_password']
        email = request.POST.get('email')
        mobile = request.POST.get('mobile')
        telephone = request.POST.get('telephone')

        first_name = request.POST['first_name']
        last_name = request.POST['last_name']

        if (not username) or (not password) or (not first_name) or (not last_name):
            messages.error(request,"Backend Validation Failed! Please fill the required fileds")
            return False
        elif ' ' in username:
            messages.error(request,"Backend Validation Failed! Username cannot contain spaces")
            return False
        elif not validate_password(password):
            messages.error(request,"Backend Validation Failed! Password doesn't meet the password complexity requirement")
            return False
        elif first_name.strip()=='':
            messages.error(request,"Backend Validation Failed! Empty First Name")
            return False
        elif last_name.strip()=='':
            messages.error(request,"Backend Validation Failed! Empty Last Name")
            return False
        elif (not re_typed_password):
            messages.error(request,"Backend Validation Failed! Please re-type the password")
            return False
        elif not (password == re_typed_password):
            messages.error(request,"Backend Validation Failed! Mismatch Passwords")
            return False
        elif(mobile and not validate_mobile(mobile)):
            messages.error(request,"Backend Validation Failed! Invalid Mobile Number")
            return False
        elif(telephone and not validate_telephone(telephone)):
            messages.error(request,"Backend Validation Failed! Invalid Mobile Number")
            return False
        elif email and not validate_email(email):
            messages.error(request,"Backend Validation Failed! Invalid Email ID")
            return False
        else:
            return True
        
def validate_inputs_for_update(request):
        

        username = request.POST['username']
        first_name = request.POST['first_name']
        last_name = request.POST['last_name']
        email = request.POST.get('email')
        mobile = request.POST.get('mobile')
        telephone = request.POST.get('telephone')

        if (not username) or (not first_name) or (not last_name):
            messages.error(request,"Backend Validation Failed! Please fill the required fileds")
            return False
        elif ' ' in username:
            messages.error(request,"Backend Validation Failed! Username cannot contain spaces")
            return False
        elif first_name.strip()=='':
            messages.error(request,"Backend Validation Failed! Empty First Name")
            return False
        elif last_name.strip()=='':
            messages.error(request,"Backend Validation Failed! Empty Last Name")
            return False
        elif(mobile and not validate_mobile(mobile)):
            messages.error(request,"Backend Validation Failed! Invalid Mobile Number")
            return False
        elif(telephone and not validate_telephone(telephone)):
            messages.error(request,"Backend Validation Failed! Invalid Mobile Number")
            return False
        elif email and not validate_email(email):
            messages.error(request,"Backend Validation Failed! Invalid Email ID")
            return False
        else:
            return True
        

class UnauthorizedAccessView(View):
    def get(self,request):
        context = get_global_master_details()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        return render(request, 'unauthorized-access.html', context)

@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class ChangePasswordView(View):

    super_featrue = "change_password"
    sub_feature = "change_my_password"
    sub_menu_item = "user_details"

    def get(self, request, id):

        context = get_local_master_details()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        if is_authorized(user_profile,self.super_featrue):

            set_sub_menu_item(self.sub_menu_item,context)

            if User.objects.filter(pk=id).exists():
                user = User.objects.get(pk=id)
                user_profile = UserProfile.objects.get(user=user)
                context['user_profile'] = user_profile
                return render(request, 'change-password.html', context)
            else:
                messages.error(request, "Operation Not Allowed")
                return redirect('view-user', id)
        elif is_authorized(user_profile,self.sub_feature):
            user = request.user
            user_profile = UserProfile.objects.get(user=user)
            context['user_profile'] = user_profile
            return render(request, 'change-password.html', context)
        else:
            return redirect("unauthorized-access")

    def post(self, request):

        context = get_local_master_details()

        logged_user_profile = set_user_profile(request,context)

        if logged_user_profile==None:
            return redirect('login')

        get_privilleges(logged_user_profile,context)

        context["old_input_field_values"] = request.POST

        #there should be a branch here... if the user is loggied user then is authorized should be check for that feature. 
        user = None
        user_profile = None
        try:
            with transaction.atomic():
                if is_authorized(logged_user_profile,self.super_featrue):

                    set_sub_menu_item(self.sub_menu_item,context)

                    original_user_id = request.POST.get('original_user_id')

                    user = User.objects.get(pk=original_user_id)
                    user_profile = UserProfile.objects.get(user=user)
                    context['user_profile'] = user_profile
                        
                elif is_authorized(logged_user_profile,self.sub_feature):
                    user = logged_user_profile.user
                    user_profile = logged_user_profile
                    context['user_profile'] = user_profile
                else:
                    return redirect('unauthorized-access')

                password = request.POST.get('password')
                re_typed_password = request.POST.get('re_typed_password')

                if not password:
                    messages.error(request,"Please enter the new password")
                    return render(request, 'change-password.html', context)
                elif not validate_password(password):
                    messages.error(request,"Password doesn't meet the password complexity requirement")
                    return render(request, 'change-password.html', context)
                elif not re_typed_password:
                    messages.error(request,"Please re-type the new password")
                    return render(request, 'change-password.html', context)
                else:
                    if password == re_typed_password:
                        user.set_password(password)
                        user.save()
                        if user.id == logged_user_profile.user.id:
                            print ("validated.... ")
                            #user = auth.authenticate(request=request,password=password)
                            auth.login(request,user,backend='django.contrib.auth.backends.ModelBackend')
                            

                        messages.success(request,"Password has been changed successfully!")
                        return redirect('view-user', user.id)
                    else:
                        messages.error(request,'Backend Validation Failed! Password Mismatch')
                        return render(request, 'change-password.html', context)

        except Exception or IntegrityError as exp:
            messages.error(request, exp)
            messages.error(
                request, "Error Occured in atomic operation. Contact the System Administrator")
            return render(request, 'change-password.html', context)
            
       

@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class AddUserView(View):

    this_feature = "add_user"
    sub_menu_item = "add_user"

    def get(self, request):

        context = get_local_master_details_for_add_update_user()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        if not is_authorized(user_profile,self.this_feature):
            return redirect('unauthorized-access')
        
        set_sub_menu_item(self.sub_menu_item,context)

        return render(request, 'add-user.html', context)
       

    def post(self, request):
        
        # get data
        # do validations
        # save
        # redirect to view user

        context = get_local_master_details_for_add_update_user()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        if not is_authorized(user_profile,self.this_feature):
            return redirect('unauthorized-access')
        
        set_sub_menu_item(self.sub_menu_item,context)


        context["old_input_field_values"] = request.POST

        if (not validate_inputs(request)):
            return render(request, 'add-user.html', context)

        username = request.POST['username']
        profile_picture = request.FILES.get('choose-user-profile-picture')
        captured_image = request.POST.get('captured_image')
        password = request.POST['password']
        system_role_name = request.POST['system_role']
        first_name = request.POST['first_name']
        middle_name = request.POST['middle_name']
        last_name = request.POST['last_name']
        email = request.POST['email']
        mobile = request.POST['mobile']
        telephone = request.POST['telephone']
        address = request.POST['address']
        branch_code = request.POST['branch_code']
        employee_number = request.POST['employee_number']
        job_role_name = request.POST['job_role']
        reference_id = request.POST['reference_id']

        print (profile_picture)
        print (type(profile_picture))
        #print (captured_image)


        
        if (profile_picture):
            rename_file(profile_picture, username.lower())
        elif captured_image:
            imgstr = re.search(r'base64,(.*)', captured_image).group(1)
            binary_data = a2b_base64(imgstr)
            file = BytesIO(binary_data)
            new_pic= InMemoryUploadedFile(file, 
            'ImageField',
            username.lower()+'.png',
            'PNG',
            sys.getsizeof(file), None)
            profile_picture = new_pic      
        if profile_picture:
            file_size = profile_picture.size
            if file_size > get_max_image_file_size_in_bytes():
                messages.error(request,"Image file size is too large")
                return render(request, 'add-user.html', context)               

        if not User.objects.filter(username=username.lower()).exists():
            if not email or not User.objects.filter(email=email.lower()).exists():

                user = User(
                    username=username.lower(),
                    first_name=get_standard_text_input(first_name),
                    last_name=get_standard_text_input(last_name), 
                    email=email.lower().strip()
                    )
                user.set_password(password)

                system_role = SystemRole.objects.get(
                    role_name=system_role_name)
                branch = Branch.objects.get(branch_code=branch_code)

                job_role = JobRole(job_role_name.upper()).value

                user_profile = UserProfile(
                    user=user,
                    profile_picture=profile_picture,
                    middle_name=get_standard_text_input(middle_name),
                    system_role=system_role,
                    mobile=mobile,
                    telephone=telephone,
                    address=get_standard_text_input(address),
                    branch=branch,
                    employee_number=get_standard_text_input(employee_number),
                    job_role=job_role,
                    reference_id=reference_id
                )

                try:
                    with transaction.atomic():
                        user.save()
                        user_profile.save()
                        messages.success(request, "User is created successfully")
                        return redirect('view-user', id=user.pk)

                except Exception or IntegrityError:
                    messages.error(
                        request, "User is not created. Error Occured in atomic operation. Contact the System Administrator")
                    return render(request, 'add-user.html', context)

            else:
                messages.error(
                    request, "Email is already registered. Please use another email")
                return render(request, 'add-user.html', context)
        else:
            messages.error(
                request, "Username is taken already. Please try another Username")
            return render(request, 'add-user.html', context)

       

@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class ViewUserView(View):

    super_feature = "view_user"
    sub_feature = "view_my_profile"
    sub_menu_item = "user_details"

    def get(self, request, id):
        context = get_local_master_details()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)


        if (user_profile.user.id == id):
            if is_authorized(user_profile,self.sub_feature):

                sub_menu_item_2 = "view_my_profile"
                set_sub_menu_item(sub_menu_item_2,context)
                try:
                    with transaction.atomic():

                        context["user_profile"] =user_profile
                        return render(request, 'view-user.html', context)

                except Exception as exp:
                    messages.error(request, exp)
                    return redirect ('user-details')
            else:
                return redirect('unauthorized-access')
        else:
            if is_authorized(user_profile,self.super_feature):

                set_sub_menu_item(self.sub_menu_item,context)

                try:
                    with transaction.atomic():
                        if User.objects.filter(pk=id).exists():
                            user = User.objects.get(pk=id)
                            user_profile = UserProfile.objects.get(user=user)
                            context["user_profile"] =user_profile
                            return render(request, 'view-user.html', context)
                        else:
                            return redirect ('user-details')
                except Exception or IntegrityError:
                    messages.error(
                        request, "Error Occured in atomic operation. Contact the System Administrator")
                    return redirect ('user-details')
            
            else:
                return redirect('unauthorized-access')

@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class UpdateUserView(View):

    this_feature = "update_user"
    sub_menu_item = "user_details"


    def get(self, request, id):

        context = get_local_master_details_for_add_update_user()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        if not is_authorized(user_profile,self.this_feature):
            return redirect('unauthorized-access')
        
        set_sub_menu_item(self.sub_menu_item,context)


        if User.objects.filter(pk=id).exists():
            user = User.objects.get(pk=id)
            user_profile = UserProfile.objects.get(user=user)

            context["user_profile"] = user_profile

            return render(request, 'update-user.html', context)
        else:
            messages.error(request, "User doesn't exist")
            return render(request, 'update-user.html', context)

    def post(self, request):

        logged_user = request.user

        context = get_local_master_details_for_add_update_user()
        context["sub_menu_item"] = "user_details"

        set_user_profile(request,context)

        context["old_input_field_values"] = request.POST
        original_user_id = request.POST.get('original_user_id')
        original_username = request.POST.get('original_username')

        original_user_temp = User.objects.get(id=original_user_id)
        original_user_profile_temp = UserProfile.objects.get(user=original_user_temp)

        context["user_profile"] = original_user_profile_temp

        try:
            with transaction.atomic():

                original_user = User.objects.get(username=original_username)
                original_user_email = original_user.email
                original_user_profile = UserProfile.objects.get(user=original_user)

                context["user_profile"] = original_user_profile

                if (not validate_inputs_for_update(request)):
                    return render(request, 'update-user.html', context)


                account_active = request.POST.get('account_active',False)
                account_active_status = False

                if account_active=='on':
                    account_active_status = True
                else:
                    account_active_status = False

                if not account_active_status:
                    if logged_user.id == original_user.id:
                        messages.error(request,"Logged in user cannot de-activate the own account")
                        return render(request, 'update-user.html', context)

                username = request.POST['username']
                profile_picture = request.FILES.get('choose-user-profile-picture')
                captured_image = request.POST.get('captured_image')
                system_role_name = request.POST['system_role']
                first_name = request.POST['first_name']
                middle_name = request.POST['middle_name']
                last_name = request.POST['last_name']
                email = request.POST['email']
                mobile = request.POST['mobile']
                telephone = request.POST['telephone']
                address = request.POST['address']
                branch_code = request.POST['branch_code']
                employee_number = request.POST['employee_number']
                job_role_name = request.POST['job_role']
                reference_id = request.POST['reference_id']

                
                if (profile_picture):
                    rename_file(profile_picture, username)
                elif captured_image:
                    imgstr = re.search(r'base64,(.*)', captured_image).group(1)
                    binary_data = a2b_base64(imgstr)
                    file = BytesIO(binary_data)
                    new_pic= InMemoryUploadedFile(file, 
                    'ImageField',
                    username.lower()+'.png',
                    'PNG',
                    sys.getsizeof(file), None)
                    profile_picture = new_pic
                if profile_picture:
                    file_size = profile_picture.size
                    if file_size > get_max_image_file_size_in_bytes():
                        messages.error(request,"Image file size is too large")
                        return render(request, 'add-user.html', context)   

                if username.lower() == original_username.lower() or (not User.objects.filter(username=username.lower()).exists()):
                    if not email or email.lower()== original_user_email.lower() or (not User.objects.filter(email=email.lower()).exists()):

                        original_user.username = username.lower()
                        original_user.first_name = get_standard_text_input(first_name)
                        original_user.last_name = get_standard_text_input(last_name)
                        original_user.email = email.lower().strip()
                        original_user.is_active = account_active_status

                        original_user_profile.user = original_user
                        if(profile_picture):
                            original_user_profile.profile_picture = profile_picture
                        original_user_profile.middle_name = get_standard_text_input(middle_name)
                        original_user_profile.system_role = SystemRole.objects.get(
                            role_name=system_role_name)
                        original_user_profile.mobile = mobile
                        original_user_profile.telephone = telephone
                        original_user_profile.address = get_standard_text_input(address)
                        original_user_profile.branch = Branch.objects.get(
                            branch_code=branch_code)
                        original_user_profile.employee_number = get_standard_text_input(employee_number)

                        original_user_profile.job_role = JobRole(job_role_name.upper()).value
                        original_user_profile.reference_id = reference_id
                        original_user.save()
                        original_user_profile.save()
                        messages.success(
                            request, "User details are updated successfully")
                        return redirect('view-user', id=original_user.pk)

                    else:
                        messages.error(
                            request, "Email is already registered. Please use another email")
                        #return redirect ('update-user',original_user.id,context)
                        return render(request, 'update-user.html', context)
                else:
                    messages.error(
                        request, "Username is taken already. Please try another Username")
                    return render(request, 'update-user.html', context)
        except Exception or IntegrityError:
            messages.error(
                request, "Error Occured in atomic operation. Contact the System Administrator")
            return render(request, 'update-user.html', context)

@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class DeleteUserView(View):

    this_feature = "delete_user"
    sub_menu_item = "user_details"


    def post(self, request):
        context = {}
        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        if not is_authorized(user_profile,self.this_feature):
            return redirect('unauthorized-access')
        
        set_sub_menu_item(self.sub_menu_item,context)

        username = request.POST['username']
        try:
            with transaction.atomic():
                user = User.objects.get(username=username)

                if is_super_admin(user):
                    messages.error(request,"Deletion Restricted! Super Admin account cannot be deleted")
                    return redirect('view-user', user.id)
                else:
                    user.delete()
                return redirect('user-details')
        except RestrictedError:
            messages.error(request,"Deletion Restricted!. User activities are recorded for this user")
            return redirect('view-user', user.id)
        except Exception or IntegrityError:
            messages.error(
                request, "Error Occured in atomic operation. Contact the System Administrator")
            return redirect('view-user', user.id)

@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class UserDetailsView(View):

    this_feature = "user_details"
    sub_menu_item = "user_details"

    def get(self, request):

        context = get_local_master_details_for_user_details()

        user_profile = set_user_profile(request,context)

        if user_profile==None:
            return redirect('login')

        get_privilleges(user_profile,context)

        if not is_authorized(user_profile,self.this_feature):
            return redirect('unauthorized-access')
        
        set_sub_menu_item(self.sub_menu_item,context)


        per_page_count = request.GET.get('per_page_count')
        page_number = request.GET.get('page_number')
        start_index = request.GET.get('start_index')

        given_name = request.GET.get('given_name')
        job_role_string = request.GET.get('job_role')
        system_role_id = request.GET.get('system_role_id')
        branch_code = request.GET.get('branch_code')
        user_account_status = request.GET.get('user_account_status')

        if not page_number:
            page_number = 1

        if not per_page_count:
            per_page_count = 10

        if start_index:
            page_number = math.ceil(int(start_index)/int(per_page_count))

        context["default_per_page_count"] = per_page_count
        print('page number --- '+ str(page_number))

        #filter logic applies here

        filter_kwargs = {}
    
        if given_name:
            print ('Given Name  - '+ str(given_name))
            given_name = given_name.strip()
            if given_name:
                name_list = given_name.split()
                context["default_given_name"] = " ".join(name_list)
                if len(name_list)>1:
                    first_name = name_list[0]
                    middle_name = name_list[1]
                    filter_kwargs['user__first_name']= first_name
                    filter_kwargs['middle_name__istartswith']= middle_name
                elif len(name_list)>0:
                    first_name = name_list[0]
                    filter_kwargs['user__first_name__istartswith']= first_name

        exclude_doctor = False
        if job_role_string:
            if job_role_string.lower()!="all":
                if job_role_string.lower() == "doctor":
                    context["default_job_role"] = JobRole(job_role_string).value
                    filter_kwargs["job_role"] = JobRole(job_role_string).value

                elif job_role_string.lower() == "other":
                    context["default_job_role"] = "OTHER"
                    exclude_doctor = True
                else:
                    context["default_job_role"] = JobRole(job_role_string).value
                    filter_kwargs["job_role"] = JobRole(job_role_string).value

        if system_role_id:
            if system_role_id.lower()!="all":
                context["default_system_role_id"] = system_role_id
                filter_kwargs['system_role']= SystemRole.objects.get(pk=system_role_id)

        if branch_code:
            if branch_code.lower()!="all":
                context["default_branch_code"] = branch_code
                filter_kwargs['branch']= Branch.objects.get(branch_code=branch_code)

        if user_account_status:
            if user_account_status.lower()!="all":
                context["default_user_account_status"] = UserAccountStatus(user_account_status).value
                if UserAccountStatus(user_account_status).value == UserAccountStatus.ACTIVE.value:
                    filter_kwargs['user__is_active']= True
                else:
                    filter_kwargs['user__is_active']= False

        user_profiles = UserProfile.objects.filter(**filter_kwargs)

        if exclude_doctor:
            user_profiles = user_profiles.exclude(job_role=JobRole.DOCTOR.value)

        user_profiles = user_profiles.order_by('id')

        if len(user_profiles)>0:
            context["has_entries"] = True
        else:
            context["has_entries"] = False

        paginator = Paginator(user_profiles,per_page_count)
        page = Paginator.get_page(paginator,page_number)
        page_list = list(paginator.get_elided_page_range(page_number, on_each_side=1))
        
        context["page"] = page
        context["page_list"] = page_list

        return render(request, 'user-details.html', context)
    


class RolePermissionsAPIView(View):
    """API to handle role permissions management"""
    
    def get(self, request):
        """Get all roles with their current permissions"""
        try:
            roles = SystemRole.objects.all().order_by('id')
            roles_data = []
            
            for role in roles:
                assigned_count = Privilege.objects.filter(system_role=role).count()
                
                roles_data.append({
                    'id': role.id,
                    'role_name': role.role_name,
                    'assigned_features_count': assigned_count,
                    'badge_class': 'bg-success' if assigned_count > 0 else 'bg-secondary',
                    'badge_text': f'{assigned_count} features' if assigned_count > 0 else 'No features'
                })
            
            return JsonResponse({
                'success': True,
                'roles_data': roles_data
            })
            
        except Exception as e:
            return JsonResponse({
                'success': False,
                'error': str(e)
            })

class FeaturesAPIView(View):
    """API to get all features organized by main features"""
    
    def get(self, request):
        try:
            main_features = MainFeature.objects.all().order_by('id')
            features_data = []
            
            for main_feature in main_features:
                sub_features = SubFeature.objects.filter(
                    main_feature=main_feature
                ).order_by('feature_name')
                
                features_data.append({
                    'main_feature_id': main_feature.id,
                    'main_feature': main_feature.feature_name,
                    'sub_features': [
                        {
                            'id': sf.id,
                            'code': f"{main_feature.feature_name.upper()}_{sf.feature_name.upper()}",
                            'name': sf.feature_name.replace('_', ' ').title(),
                            'type': sf.feature_type
                        } for sf in sub_features
                    ]
                })
            
            return JsonResponse({
                'success': True,
                'features': features_data
            })
            
        except Exception as e:
            return JsonResponse({
                'success': False,
                'error': str(e)
            })

class RoleFeaturesAPIView(View):
    """API to get/set features for a specific role - 100% WORKING VERSION"""
    
    def get(self, request, role_id):
        """Get current features for a role FROM DATABASE"""
        try:
            role = SystemRole.objects.get(id=role_id)
            
            assigned_privileges = Privilege.objects.filter(system_role=role)
            
            assigned_feature_codes = []
            for privilege in assigned_privileges:
                main_feature = privilege.sub_feature.main_feature.feature_name.upper()
                sub_feature = privilege.sub_feature.feature_name.upper()
                feature_code = f"{main_feature}_{sub_feature}"
                assigned_feature_codes.append(feature_code)
            
            return JsonResponse({
                'success': True,
                'role_id': role.id,
                'role_name': role.role_name,
                'assigned_feature_codes': assigned_feature_codes
            })
            
        except SystemRole.DoesNotExist:
            return JsonResponse({
                'success': False,
                'error': 'Role not found'
            })
        except Exception as e:
            return JsonResponse({
                'success': False,
                'error': str(e)
            })
    
    def post(self, request):
        """Assign features to a role - 100% WORKING VERSION"""
        try:
            data = json.loads(request.body)
            role_id = data.get('role_id')
            feature_codes = data.get('feature_codes', [])
            
            # print(f"PROCESSING: Received {len(feature_codes)} features for role {role_id}")
            
            role = SystemRole.objects.get(id=role_id)
            
            deleted_count, _ = Privilege.objects.filter(system_role=role).delete()
            # print(f" DELETED: {deleted_count} existing privileges")
            
            privileges_created = 0
            failed_features = []
            
            main_features = MainFeature.objects.all()
            main_feature_map = {}
            for mf in main_features:
                main_feature_map[mf.feature_name.upper()] = mf
            
            for feature_code in feature_codes:
                try:
                    # FIXED PARSING: Handle main features with underscores properly
                    # Feature code format: "MAIN_FEATURE_SUB_FEATURE"
                    
                    # Find which main feature this belongs to
                    found_main_feature = None
                    found_sub_feature_name = None
                    
                    for main_feature_name, main_feature_obj in main_feature_map.items():
                        prefix = main_feature_name + "_"
                        if feature_code.startswith(prefix):
                            found_main_feature = main_feature_obj
                            found_sub_feature_name = feature_code[len(prefix):]
                            break
                    
                    if not found_main_feature:
                        failed_features.append(f"{feature_code}: Main feature not found")
                        continue
                    
                    sub_feature = SubFeature.objects.get(
                        main_feature=found_main_feature,
                        feature_name__iexact=found_sub_feature_name
                    )
                    
                    Privilege.objects.create(
                        system_role=role,
                        sub_feature=sub_feature
                    )
                    privileges_created += 1
                    
                except SubFeature.DoesNotExist:
                    error_msg = f"{feature_code}: Sub feature not found"
                    failed_features.append(error_msg)
                    continue
                except Exception as e:
                    error_msg = f"{feature_code}: Error - {str(e)}"
                    failed_features.append(error_msg)
                    continue
            
            # print(f" SUCCESS: Created {privileges_created} privileges")
            # print(f" FAILED: {len(failed_features)} features")
            
            actual_privileges_count = Privilege.objects.filter(system_role=role).count()
            # print(f"VERIFICATION: Database now has {actual_privileges_count} privileges for this role")
            
            response_data = {
                'success': True,
                'message': f'Permissions updated successfully! {privileges_created} features assigned to {role.role_name}.',
                'privileges_created': privileges_created,
                'total_requested': len(feature_codes),
                'actual_in_database': actual_privileges_count
            }
            
            if failed_features:
                response_data['warning'] = f'{len(failed_features)} features failed'
                response_data['failed_count'] = len(failed_features)
            
            return JsonResponse(response_data)
            
        except SystemRole.DoesNotExist:
            return JsonResponse({
                'success': False,
                'error': 'Role not found'
            })
        except Exception as e:
            print ('3333333333333       ',e)
            return JsonResponse({
                'success': False,
                'error': f'System error: {str(e)}'
            })

class CreateRoleAPIView(View):
    """API to create new system roles"""
    
    def post(self, request):
        try:
            data = json.loads(request.body)
            role_name = data.get('role_name')
            description = data.get('description', '')
            
            if not role_name:
                return JsonResponse({
                    'success': False,
                    'error': 'Role name is required'
                })
            
            if SystemRole.objects.filter(role_name__iexact=role_name).exists():
                return JsonResponse({
                    'success': False,
                    'error': 'Role already exists'
                })
            
            new_role = SystemRole.objects.create(role_name=role_name)
            
            return JsonResponse({
                'success': True,
                'message': f'Role "{role_name}" created successfully',
                'role_id': new_role.id
            })
            
        except Exception as e:
            return JsonResponse({
                'success': False,
                'error': str(e)
            })

class InitializeDataView(View):
    """View to initialize default roles and features"""
    
    def get(self, request):
        try:
            roles_result = SystemRole.initialize_default_roles()

            features_result = MainFeature.initialize_default_features()
            
            messages.success(request, f"Data initialized successfully! {roles_result}. {features_result}")
            return redirect('manage-permissions')
            
        except Exception as e:
            messages.error(request, f"Error initializing data: {str(e)}")
            return redirect('manage-permissions')


@method_decorator(cache_control(no_cache=True, must_revalidate=True,no_store=True), name='dispatch')
class ManagePermissionsView(View):
    
    this_feature = "manage_permissions"
    sub_menu_item = "manage_permissions"

    def get(self, request):
        context = get_global_master_details()

        user_profile = set_user_profile(request, context)
        
        if user_profile is None:
            return redirect('login')

        get_privilleges(user_profile, context)
        
        set_sub_menu_item(self.sub_menu_item, context)
        
        system_roles = SystemRole.objects.all().order_by('id')
        roles_data = []
        
        for role in system_roles:
            assigned_count = Privilege.objects.filter(system_role=role).count()
            
            roles_data.append({
                'id': role.id,
                'role_name': role.role_name,
                'assigned_features_count': assigned_count,
                'badge_class': 'bg-success' if assigned_count > 0 else 'bg-secondary',
                'badge_text': f'{assigned_count} features' if assigned_count > 0 else 'No features'
            })
        
        context['roles_data'] = roles_data
        
        return render(request, 'manage-permissions.html', context)
