from django.conf import settings
from django.shortcuts import render
from .models import Profiles,Otp,Product, Announcement, LeaveRequest,Payslip, Client,  Employee, Attendance,Department, Designation
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.exceptions import NotFound
from django.contrib.auth import authenticate, login
from rest_framework_simplejwt.tokens import RefreshToken
from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import User
from django.utils import timezone as djtz
from django.utils import timezone
from datetime import date, datetime, timedelta
import cv2
import face_recognition
import os
import numpy as np
import sys
import requests


import io
import requests
from django.utils import timezone
from django.http import HttpResponse
import base64
from PIL import Image, ImageEnhance, ImageFilter
from django.db.models import Q
from rest_framework.generics import RetrieveAPIView, ListAPIView
from .serializers import UserSerializer
from rest_framework.permissions import IsAuthenticated
from datetime import datetime, time
import json
from django.core.mail import EmailMessage
from school.settings import BASE_DIR
import pdfkit
from django.core.exceptions import ObjectDoesNotExist
# import openai
import re
from django.conf import settings
import threading
# import pywhatkit
from django.core.mail import send_mail
from django.utils.crypto import get_random_string
from django.db.models import Sum




from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from django.core.exceptions import ObjectDoesNotExist
from rest_framework_simplejwt.tokens import RefreshToken
import re  # For basic email validation
# from twilio.rest import Client as TwilioClient # 💡 Maru Peyaridhal!
class LoginAPIView(APIView):

    def post(self, request):
        data = request.data
        username_or_email = data.get("username")  # Allow either username or email field
        password = data["password"]



        # Basic email validation
        if re.match(r"[^@]+@[^@]+\.[^@]+", username_or_email):
            # It's an email address, fetch the user by email
            try:
                user = User.objects.get(email=username_or_email)
            except User.DoesNotExist:
                user = None
        else:
            # It's a username, fetch the user by username
            user = authenticate(request, username=username_or_email, password=password)

        # Authenticate the user
        if user is not None and user.check_password(password):
            login(request, user)
            token = RefreshToken.for_user(user)

            try:
                profile = Profiles.objects.get(user_id=user.id)

                if profile.status == 2:  # Check if the profile status s 2 (inactive user)
                    return Response({
                        "status": {"code": status.HTTP_403_FORBIDDEN, "response": "error"},
                        "error": "Inactive user",
                        "message": "You are inactive. Contact Admin",
                        "data": None
                    }, status=status.HTTP_403_FORBIDDEN)
                pro = profile.profiles.url
                companyname = profile.name
                # Set default company logo
                com = "../static/dummy.png"

                if profile.role == 2:
                    try:
                        created_company = Profiles.objects.get(user_id=profile.user_id)
                        company_creator_profile = Profiles.objects.get(user_id=created_company.created_by_id)
                        if company_creator_profile.companylogo:
                            com = company_creator_profile.companylogo.url
                            companyname = company_creator_profile.servicename
                    except ObjectDoesNotExist:
                        pass
                else:
                    if profile.companylogo:
                        com = profile.companylogo.url
                        companyname = profile.servicename

            except ObjectDoesNotExist:
                pro = "../static/dummy.png"
                com = "../static/dummy.png"
                profile = None

            companyname = "loop"
            phone = profile.phone
            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Login success",
                "data": {
                    "name": user.username,
                
                    "id": user.id,
                    "username": user.first_name,
                    "email": user.email,
                    "isSuper": user.is_superuser,
                    "refresh": str(token),
                    "token": str(token.access_token),
                    "profile": pro,
                    "companylogo" : com,
                    "companyname" : companyname,
                    "phone" : phone,
                    "role": profile.role,
                }
            })
        else:
            return Response({
                "status": {"code": status.HTTP_401_UNAUTHORIZED, "response": "error"},
                "error": "Authentication failed",
                "message": "Invalid username or password",
                "data": None
            }, status=status.HTTP_401_UNAUTHORIZED)



class UserAPIView(RetrieveAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = UserSerializer
    

    def get_object(self):
        return self.request.user

    def post(self, request):
        data = request.data

        user = User.objects.get(email=data["email"])
        profile = Profiles.objects.get(user=user)

        

        return Response({
            "status": {"code": status.HTTP_200_OK, "response": "success"},
            "error": True,
            "data": {
                "username": user.username,
                "email": user.email,
                "role": profile.role.id,
                "profile": profile.profiles.url,
            }
        })
    

def send_otp_email(email, otp):
    subject = 'Your One-Time  (OTP) for Verification'
    message = f'''Dear User,

    Your One-Time  (OTP) for verification is:

    {otp}

    Please enter this code to proceed. This OTP is valid for the next 1 minutes.

    If you did not request this code, please ignore this email.

    Thank you,  
    Pearlcon Technologies LLP
    https://pearlcons.com
    '''
    try:
        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,
            [email],
            fail_silently=False,
        )
    except Exception as e:
        print(f"Error sending email: {e}")
def send_otp_emails(email, otp):
   
    subject = 'Your One-Time  (OTP) for Verification'
    message = f'''Dear User,

    Your One-Time  (OTP) for verification is:

    {otp}

    Please enter this code to proceed. This OTP is valid for the next 1 minutes.

    If you did not request this code, please ignore this email.

    Thank you,  
    Pearlcon Technologies LLP
    https://pearlcons.com
        '''
    try:
        send_mail(
            subject,
            message,
            settings.DEFAULT_FROM_EMAIL,
            [email],
            fail_silently=False,
        )
    except Exception as e:
        print(f"Error sending email: {e}")

        
from django.contrib.auth import get_user_model
User = get_user_model()

class SendotpAPIView(APIView):
    def post(self, request):
        data = request.data
        try:
            email = data.get('params', {}).get('email', None)
            print('Received email:', email)

            # ✅ Step 1: Check if email exists in registered users
            if not User.objects.filter(email=email).exists():
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "Email not found"},
                    "error": True,
                    "message": "Email not registered"
                })

            # ✅ Step 2: Create OTP record and send OTP
            user = Otp.objects.create(email=email)
            otp = get_random_string(length=6, allowed_chars='1234567890')
            user.otp = otp
            user.otp_created_at = timezone.now()
            user.save()

            threading.Thread(target=send_otp_email, args=(email, otp)).start()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "Success"},
                "error": None,
                "data": {"email": email}
            })
        except Exception as e:
            print("Error:", e)
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "Internal Server Error"},
                'error': True,
                "message": str(e)
            })


class SendotpsAPIView(APIView):
    def post(self, request):
        data = request.data
        try:
            email = data.get('email', None)
            print('Received email:', email)

            # If this is registration
            if User.objects.filter(email=email).exists():
                return Response({
                    "status": {"code": status.HTTP_409_CONFLICT, "response": "Email already registered"},
                    "error": True,
                    "message": "This email is already registered. Please use another email."
                })

            otp = get_random_string(length=6, allowed_chars='1234567890')
            user = Otp.objects.create(email=email, otp=otp, otp_created_at=timezone.now())

            threading.Thread(target=send_otp_emails, args=(email, otp)).start()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "Success"},
                "error": None,
                "data": {"email": email}
            })
        except Exception as e:
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "Internal Server Error"},
                'error': True,
                "message": str(e)
            })

from datetime import timedelta
from django.utils import timezone

class VerifyotpAPIView(APIView):
    def get(self, request):
        email = request.query_params.get('email')
        otp_entered = request.query_params.get('otp')

        try:
            user_otp = Otp.objects.filter(email=email).latest('otp_created_at')

            # Expiry time check (30 seconds)
            expiration_time = user_otp.otp_created_at + timedelta(seconds=60)
            if timezone.now() > expiration_time:
                return Response({
                    "status": 401,
                    "message": "OTP expired. Please request a new one.",
                    "error": True
                }, status=status.HTTP_200_OK) 

            if otp_entered == user_otp.otp:
                return Response({
                    "status": 200,
                    "message": "OTP Verified",
                    "error": False
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    "status": 400,
                    "message": "Invalid OTP",
                    "error": True
                }, status=status.HTTP_200_OK)

        except Otp.DoesNotExist:
            return Response({
                "status": 404,
                "message": "OTP not found",
                "error": True
            }, status=status.HTTP_200_OK)




    def delete(self, request, id):
        if id is not None:
            try:
                profile = Profiles.objects.get(user_id=id)

                # Delete the image file from storage (optional)
                if profile.profiles:  # replace 'image' with your actual image field name
                    profile.profiles.delete(save=False)  # Deletes the file from MEDIA folder
                    profile.profiles = None
                    profile.save()

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "message": "Profile image deleted successfully"
                })

            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": None,
                    "message": "Profile not found"
                })

        return Response({
            "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
            "error": "ID not provided",
            "message": "User ID is required"
        })




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

    def get(self, request, **kwargs):
        id = kwargs.get('id')


        if id is not None:
            try:
                user = User.objects.get(id=id)
                company = Profiles.objects.get(user_id=user.id)
                if company.profiles and company.profiles.url != "../static/dummy.png":
                    pr = company.profiles.url
                else:
                    pr = "../static/dummy.png"

                data = {
                    'name': company.name,
                    'email': company.email,
                    'phone': company.phone,
                    'f_name': user.first_name,
                    'l_name': user.last_name,

                    'profile' : pr,
                    'id': user.id   
                }



                

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "Success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "Failed"},
                    'error': True,
                    "message": "Company not found"
                })

    def post(self, request):
        data = request.data
        try:


            pho = data.get("prof_photo")
            # name = data.get("username")

            take = Profiles.objects.get(user_id=request.user.id)
            take.profiles = pho

            take.save()
            # # Create User instance
            # van = User(username=name, email=email, password=hashed_password)
            # van.save()

           

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Profile updated successfully"
            })

        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {str(e)}"
            })
        except Exception as e:
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "failed"},
                "error": True,
                "message": f"An error occurred: {str(e)}"
            })


    def put(self, request, id):
        data = request.data
        prof_photo = request.data.get('prof_photo')
        
        phone_no = request.data.get('phone_no')
        email_id = request.data.get('email_id')
        first_name = request.data.get('first_name')

       
        try:


            mm = Profiles.objects.get(user_id=id)
            sd = User.objects.get(id=id)


            sd.username = data["first_name"]
            sd.first_name = data["first_names"]
            sd.last_name = data["last_name"]


            
            sd.email = data["email_id"]
            sd.save()

            
            mm.email = data["email_id"]
            mm.phone = data["phone_no"]
            mm.name = data["first_name"]
            mm.profiles = data['prof_photo']

            
            mm.save()

            

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "User updated successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": "Something went wrong"
            })





class RegisterAPIView(APIView):
    def get(self, request, **kwargs):
        id = kwargs.get('id')


        if id is not None:
            try:
                user = User.objects.get(id=id)
                company = Profiles.objects.get(user=user.id)
                if company.profiles and company.profiles.url != "../static/dummy.png":
                    pr = company.profiles.url
                else:
                    pr = "../static/dummy.png"

                data = {
                    'name': company.name,
                    'email': company.email,
                    'phone': company.phone,
                    'address': company.address,
                    'pincode': company.pincode,
                    'profile' : pr,
                   
                    'firstname': user.first_name,
                    'lastname': user.last_name,
                    'gender': company.gender,
                
                    'doj': company.doj,
                    'password': company.password,
                    


                    'id': user.id   
                }

                

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "Success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "Failed"},
                    'error': True,
                    "message": "Company not found"
                })
        else:

            val = request.GET.get('val')
            print(val)
            try:
                data = []


                username = request.query_params.get('vendorname', '').strip()  # Uncomment this line
                pincode = request.query_params.get('pincode', '').strip()  # Uncomment this line

                email = request.query_params.get('email', '').strip()  # Uncomment this line
                phone = request.query_params.get('phone', '').strip()  # Uncomment this line

                

                status_param = request.query_params.get('status', '').strip()

                if val == '2':
                    companies = Profiles.objects.filter(status=2,role=0).order_by('-user_id')
                else:
                    companies = Profiles.objects.filter(status=1,role=0).order_by('-user_id')


                if username:
                  
                    companies = companies.filter(name__icontains=username) 

                if email:
                  
                    companies = companies.filter(email__icontains=email) 
                if phone:
                  
                    companies = companies.filter(phone__icontains=phone) 

                if pincode:
                  
                    companies = companies.filter(pincode__icontains=pincode) 
                if status_param:
                    try:
                        status_int = int(status_param)
                        if status_int in [1, 2]:
                            companies = companies.filter(status=status_int)
                    except ValueError:
                        pass

                for company in companies:
                        


                        

                    users  = User.objects.get(id=company.user_id) 

                    # if company.profiles:
                    #     pro = company.profiles.url
                    # else:
                    #     pro = "../static/dummy.png"

                    company_data = {
                    
                        'name': company.name,
                        'id': company.user_id,
                        'phone': company.phone,
                        # 'gstnumber': company.gstnumber,
                        'pincode': company.pincode,

                        # 'gst': company.gst.url,
                        'email': company.email,
                        'address': company.address,
                        # 'profile': pro,
                        'phone': company.phone,
                        'status' : company.status,


                    }
                    data.append(company_data)
                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "Success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "Failed"},
                    "error": True,
                    "message": "Something went wrong"
                })

    def post(self, request):
        data = request.data
        try:
            # Collect data from request
            # servicename = data.get("servicename")
            name = data.get("employeename")
            # f_name = data.get("first_name")
            # l_name = data.get("last_names")

            email = data.get("email")
            phone = data.get("mobilenumber")
            address = data.get("address")
            pincode = data.get("pincode")
            # gstnumber = data.get("gstnumber")
            # state = data.get("state")


            # role = data.get("role")
            # gst = data.get("gst")
            # doj = data.get("doj")  
            # profiles = data.get("prof_photo")
            # pan = data.get("pan")
            # gender = data.get("gender")
            password = data.get("password")
            # companylogo = data.get("companyprofile")
           
            # pro = "../static/dummy.png"

            # if not profiles:
            #     profiles = pro

            hashed_password = make_password(password)

            van = User(username=name, email=email, password=hashed_password)
            van.save()

            


            profile_data = Profiles(
                password=password,
                 name=name, email=email,
                phone=phone, address=address, user=van
                
            )
            profile_data.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "New User Registered successfully"
            })

        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {str(e)}"
            })
        except Exception as e:
            return Response({
                "status": {"code": status.HTTP_500_INTERNAL_SERVER_ERROR, "response": "failed"},
                "error": True,
                "message": f"An error occurred: {str(e)}"
            })

    def put(self, request, id):
        val = request.GET.get('val')
        data = request.data
        ctc = request.data.get('ctc')

        if val == '1':
            po = Profiles.objects.get(user_id=id)
            if po.wfh == 1:
                po.wfh = 2
            else:
                po.wfh = 1
            po.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "WFH updated successfully"
            })
        elif val == '2':
            po = Profiles.objects.get(user_id=id)
            if po.status == 1:
                po.status = 2
            else:
                po.status = 1
            po.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Inactive updated successfully"
            })
        elif ctc:
            meow = Profiles.objects.get(user_id=id)
            meow.ctc = data['ctc']
            meow.gross = data['gross']
            meow.pt = data['pt']
            meow.uan = data['uan']
            meow.pan = data['pan']
            meow.account = data['account']
            meow.reim = data['reim']


            meow.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Salary details updated successfully"
            })
        else:
            try:
                mm = Profiles.objects.get(user_id=id)
                sd = User.objects.get(id=id)

                mm.name = data["name"]
                mm.pemail = data["pemail"]
                mm.shift = data["shift"]
                mm.marriedstatus = data["marriedstatus"]
                mm.gender = data["gender"]
                mm.email = data["email"]
                mm.phone = data["phone"]
                mm.address = data["address"]
                mm.city = data["city"]
                mm.state = data["state"]
                mm.country = data["country"]
                mm.pincode = data["pincode"]
                mm.department_id = data["department"]
                mm.designation_id = data["designation"]
                mm.role = data["role"]
                mm.authority_id = data["authority"]
                mm.doj = data["doj"]
                mm.profiles = data["profiles"]
                mm.empcode = data["empcode"]
                mm.password = data["password"]
                mm.save()

                sd.username = data["name"]
                sd.first_name = data["firstname"]
                sd.last_name = data["lastname"]
                sd.email = data["email"]
                sd.password = make_password(data["password"])
                sd.save()

                return Response({
                    "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                    "error": None,
                    "message": "User updated successfully"
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": "Something went wrong"
                })

    def delete(self,  *args, **kwargs):
        company_id = kwargs.get('id')

        try:

            pr  = Profiles.objects.get(user_id =company_id)
            pr.delete()
            company = User.objects.get(id=company_id)
            company.delete()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Company deleted successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })



class CompanydashboardAPIView(APIView):
    # permission_classes = (IsAuthenticated,)

    def get(self, request):
        
        try:
            from django.utils.timezone import now

            op = request.user.id

            totalenquiry = Product.objects.filter(created_by_id=op).count()

            from django.utils.timezone import now
            from datetime import timedelta

            op = request.user.id

            # Get current date
            current_date = now()

            

            totalvendorlastmonth = 6
            totalvendor=5
            totalenquirytodaydate=6
            activevendor=6
            monthdata=7
            inactivevendor=8
            last_month_enquiry=9
            current_month_enquiry=8
            current_month_auction=5
            last_month_auction=4
            current_month_product=2
            last_month_product=2
            
                
            data = {
                "totalenquiry": totalenquiry,
                "totalvendor": totalvendor,
                "totalenquirytodaydate": totalenquirytodaydate,
                "activevendor" : activevendor,
                "inactivevendor" : inactivevendor,
                "monthdata" : monthdata,
                "totalvendorlastmonth" :totalvendorlastmonth,
                "current_month_enquiry" : current_month_enquiry,
                "last_month_enquiry" : last_month_enquiry,
                "current_month_auction" : current_month_auction,
                "last_month_auction" : last_month_auction,
                "current_month_product" : current_month_product,
                "last_month_product" : last_month_product

            }

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "data": data
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found",
            })
        





    



class CheckcompanyAPIView(APIView):
    def get(self, request, id=None):
        phone = request.query_params.get('phone')
        email = request.query_params.get('email')
        name = request.query_params.get('username')

       
        gstnumber = request.query_params.get('gstnumber') or request.query_params.get('gst')



        print("Check Params:", phone, email, gstnumber)

        if phone or email or gstnumber or name:
            query = Q()
            if name:
                query |= Q(name=name)
            if phone:
                query |= Q(phone=phone)
            if email:
                query |= Q(email=email)
            if gstnumber:
                query |= Q(gstnumber=gstnumber)

            exists = Profiles.objects.filter(query).exists()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "exists": exists
            })

        return Response({
            "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
            "error": True,
            "message": "No phone, email, or GST provided."
        }, status=status.HTTP_400_BAD_REQUEST)



class ClientAPIView(APIView):
    # permission_classes = (IsAuthenticated,)

    def get(self, request, id=None):
        if id is not None:
            try:
                company = Product.objects.get(id=id)

                try:
                    fl = company.sfile.url if company.sfile else None
                except ValueError:
                    fl = None 
                data = {
                    'id': company.id,
                    'name': company.name,
                    'code': company.code,

                    'description': company.description,
                    'specification':company.specification,
                    'sfile': fl,
                    'status': company.status

                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:

                index = 0
                companies = []

                # user_id = request.query_params.get('user_id')
             
                # name = request.query_params.get('name', '').strip()  # Uncomment this line
                # status_param = request.query_params.get('status', '').strip()

                # if user_id:
                #     products = Product.objects.filter(created_by_id=user_id)
                # else:
                #     products = Product.objects.filter(created_by_id=request.user.id)

                

                client = Client.objects.all()

                for company in client:
                    index += 1


                    companies.append({
                        'row': index,
                        'id': company.id,
                        'client_name': company.client_name,
                        'phone': company.phone,

                        'email': company.email,
                        'address': company.address,
                        'doj': company.doj,

                    })


                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })

    def post(self, request):
        data = request.data

        try:
            company = Client.objects.create(
                client_name=data["clientName"],

                phone=data["mobilenumber"],
                address =data["address"],
                # email =data["email"],
                # aadhar =data["aadharNumber"],
                # pan =data["panNumber"],
                # doj =data["dateOfJoining"],



                # created_by=request.user
            )
            company.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Client created successfully",
                 "data": {
                "id": company.id,  # இந்த ID தான் ஆப்பிற்கு தேவை
                "client": company.client_name
            }
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })





    # def put(self, request, id):
    #     data = request.data

    #     try:

    #         ve =data.get("sfile")

    #         company = Product.objects.get(id=id)
    #         company.name = data.get("name", company.name)
    #         company.code = data.get("code", company.code)

    #         company.description = data.get("description", company.description)
    #         company.specification = data.get("specification", company.specification)
    #         company.sfile = data.get("sfile", company.sfile) 
    #         company.status = data.get("status", company.status)
    #         company.save()

    #         return Response({
    #             "status": {"code": status.HTTP_200_OK, "response": "success"},
    #             "error": None,
    #             "message": "Product updated successfully"
    #         })
    #     except ObjectDoesNotExist:
    #         return Response({
    #             "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
    #             "error": True,
    #             "message": "No data found"
    #         })
    #     except Exception as e:
    #         print(e)
    #         return Response({
    #             "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
    #             "error": True,
    #             "message": "Something went wrong"
    #         })

   


    # def delete(self, request, id):
    #     if id is not None:
    #         try:
    #             product_id_str = str(id)
    #             is_used = Enquiry.objects.filter(product__contains=[product_id_str]).exists()

    #             if is_used:
    #                 return Response({
    #                     "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
    #                     "error": "Product is used in enquiry",
    #                     "message": "Cannot delete product. It's used in one or more enquiries."
    #                 })

    #             # If not used, delete the product
    #             product = Product.objects.get(id=id)
    #             product.delete()

    #             return Response({
    #                 "status": {"code": status.HTTP_200_OK, "response": "success"},
    #                 "error": None,
    #                 "message": "Product deleted successfully"
    #             })

    #         except Product.DoesNotExist:
    #             return Response({
    #                 "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
    #                 "error": None,
    #                 "message": "No product found"
    #             })
class DashboardapiAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request):
        date_str = request.query_params.get('date', None)
        try:
            target_date = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else date.today()
        except:
            target_date = date.today()

        # 1. மொத்த ஆக்டிவ் பணியாளர்கள்
        all_emp = Employee.objects.filter(status=1)
        total_count = all_emp.count()
        
        # 2. இன்றைய வருகை (Present)
        present_today = Attendance.objects.filter(date=target_date, status="Present")
        present_count = present_today.count()

        # 3. இன்றைய பிரசன்ட் ஆனவர்களின் IDs (Absent லிஸ்ட் எடுக்க இது தேவை)
        present_emp_ids = present_today.values_list('employee_id', flat=True)

        # 4. அப்சென்ட் ஆனவர்கள் (Active-ஆக இருந்து, இன்று வரவில்லை)
        absent_emps = all_emp.exclude(id__in=present_emp_ids)
        
        absent_list = []
        for emp in absent_emps:
            # போட்டோ இருந்தால் Full URL எடுக்கும், இல்லையென்றால் Null
            image_url = request.build_absolute_uri(emp.photo.url) if emp.photo else None
            absent_list.append({
                "name": emp.name,
                "image": image_url
            })

        # 5. லேட் வருகை (09:30 AM-க்கு மேல்)
        late_threshold = datetime.strptime("09:30:00", "%H:%M:%S").time()
        late_count = present_today.filter(in_time__gt=late_threshold).count()

        # சதவீத கணக்கீடு
        p_percent = int((present_count / total_count) * 100) if total_count > 0 else 0
        l_percent = int((late_count / present_count) * 100) if present_count > 0 else 0

        return Response({
            "status": {"code": 200, "response": "success"},
            "data": {
                "n_data": {
                    "label": "Active Staff", 
                    "present": present_count, 
                    "total": total_count, 
                    "percent": p_percent
                },
                "s_data": {
                    "label": "Late Entry", 
                    "present": late_count, 
                    "total": present_count, 
                    "percent": l_percent
                },
                "absent_employees": absent_list, # இதுதான் அந்த அனிமேஷன் லிஸ்ட்
                "selected_date": target_date.strftime('%Y-%m-%d')
            }
        })

class StudentClassCountAPIView(APIView):
    def get(self, request, id):
        try:

            print('nddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd')
            # Attendance டேபிளில் இருந்து குறிப்பிட்ட மாணவர் மற்றும் கிளாஸ் வகைப்படி கவுண்ட் எடுத்தல்
            # class_type 1=Normal, 2=Special என வைத்துக்கொள்கிறேன்
            normal_count = Attendance.objects.filter(student_id=id, session_type=1).count()
            special_count = Attendance.objects.filter(student_id=id, session_type=2).count()


            print(normal_count,special_count,'jsabdbsdsmdbasmdbsand')

            return Response({
                "status": {"code": 200, "response": "success"},
                "data": {
                    "normal_count": normal_count,
                    "special_count": special_count
                }
            })
        except Exception as e:
            return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST)


class EmployeeAPIView(APIView):
    # permission_classes = (IsAuthenticated,)

    def get(self, request, id=None):
        if id is not None:
            try:
                emp = Employee.objects.get(id=id)
                data = {
                    'id': emp.id,
                    'name': emp.name,
                    'mobile': emp.mobile,
                    'age': emp.age,
                    'address': emp.address,
                    'department_id': emp.department.id if emp.department else None,
                    'department_name': emp.department.name if emp.department else "N/A",
                    'designation_id': emp.designation.id if emp.designation else None,
                    'designation_name': emp.designation.name if emp.designation else "N/A",
                    'doj': emp.doj,
                    'status': emp.status,
                    'profile_pic': request.build_absolute_uri(emp.photo.url) if emp.photo else None
                }
                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except Employee.DoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No employee found",
                })
        else:
            try:
                employees = Employee.objects.all().order_by('-created_at')
                emp_list = []
                for index, emp in enumerate(employees, 1):
                    emp_list.append({
                        'row': index,
                        'id': emp.id,
                        'name': emp.name,
                        'mobile': emp.mobile,
                        'department': emp.department.name if emp.department else "N/A",
                        'designation': emp.designation.name if emp.designation else "N/A",
                        'status': emp.status,
                        'profile_pic': request.build_absolute_uri(emp.photo.url) if emp.photo else None
                    })
                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": emp_list
                })
            except Exception as e:
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": str(e),
                })

    # def post(self, request):
    #     data = request.data
    #     profile_pic = request.FILES.get('profile_pic')

    #     try:
    #         # Foreign Key ஆப்ஜெக்ட்களை எடுத்தல்
    #         dept_id = data.get('department')
    #         desig_id = data.get('designation')
            
    #         dept = Department.objects.get(id=dept_id) if dept_id else None
    #         desig = Designation.objects.get(id=desig_id) if desig_id else None

    #         employee = Employee.objects.create(
    #             name=data.get('name'),
    #             mobile=data.get('mobile'),
    #             age=data.get('age'),
    #             address=data.get('address'),
    #             department=dept,
    #             designation=desig,
    #             doj=data.get('doj'),
    #             photo=profile_pic,
    #             created_by=request.user if request.user.is_authenticated else None
    #         )

    #         if profile_pic:
    #             try:
    #                 # ????????????? ???????? ??????????
    #                 img = Image.open(employee.photo.path).convert('RGB')
    #                 img_array = np.array(img)
                    
    #                 # ????????? ??????????
    #                 encodings = face_recognition.face_encodings(img_array)
                    
    #                 if encodings:
    #                     # ????? ??????????? ??????? ??????? ???????????
    #                     employee.save_encoding(encodings[0])
    #                 else:
    #                     # ????? ??????????? ??????? ?????? ?????? ????? ???????????? ????????? 
    #                     # ?????? error ??????????
    #                     print(f"Face not detected for {employee.name}")
    #             except Exception as face_err:
    #                 print(f"Encoding Error: {face_err}")
            
    #         return Response({
    #             "status": {"code": status.HTTP_201_CREATED, "response": "success"},
    #             "error": None,
    #             "message": "Employee created successfully",
    #         })
    #     except Exception as e:
    #         return Response({
    #             "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
    #             "error": True,
    #             "message": f"Error: {str(e)}"
    #         })
    # def put(self, request, id):
    #     data = request.data
    #     profile_pic = request.FILES.get('profile_pic')

    #     try:
    #         emp = Employee.objects.get(id=id)
            
    #         # Department & Designation ???????
    #         if 'department' in data:
    #             emp.department = Department.objects.get(id=data.get('department'))
    #         if 'designation' in data:
    #             emp.designation = Designation.objects.get(id=data.get('designation'))

    #         emp.name = data.get("name", emp.name)
    #         emp.mobile = data.get("mobile", emp.mobile)
    #         emp.age = data.get("age", emp.age)
    #         emp.address = data.get("address", emp.address)
    #         emp.doj = data.get("doj", emp.doj)
    #         emp.status = data.get("status", emp.status)
            
    #         # 1. ????? ?????? ??????? ??? ????????????
    #         if profile_pic:
    #             emp.photo = profile_pic
    #             emp.save()
    #         else:
    #             emp.save()

    #         # 2. ?????????? ???????: 
    #         # ????? ?????? ????????????? ?????? ???? ?????? ??????? ?????? ??????? ????????? ????????????? ?????????...
    #         if profile_pic or (emp.photo and not emp.face_encoding_data):
    #             try:
    #                 # ?????? ???? ?????????? ????? ????? ??????????
    #                 if emp.photo and os.path.exists(emp.photo.path):
    #                     img = Image.open(emp.photo.path).convert('RGB')
    #                     encodings = face_recognition.face_encodings(np.array(img))
                        
    #                     if encodings:
    #                         emp.save_encoding(encodings[0])
    #                         print(f"Encoding successful for: {emp.name}")
    #                     else:
    #                         # ????? ??????????? ???????
    #                         if profile_pic: # ????? ????????? ????????? ??????? ??? (Null) ????????
    #                             emp.face_encoding_data = None
    #                             emp.save()
    #             except Exception as face_err:
    #                 print(f"Face encoding error: {face_err}")

    #         return Response({
    #             "status": {"code": 200, "response": "success"},
    #             "message": "Employee updated and Face ID generated"
    #         })

    #     except Employee.DoesNotExist:
    #         return Response({"status": {"code": 404, "response": "failed"}, "message": "Employee not found"})
    #     except Exception as e:
    #         return Response({"status": {"code": 400, "response": "failed"}, "message": str(e)})


    def _save_face_encoding(self, employee):
        """
        Employee photo-???? face encoding ??????? save ???????.
        ???? size photo-???? handle ???????.
        Returns: (success: bool, message: str)
        """
        if not employee.photo:
            return False, "Photo ?????"
 
        photo_path = employee.photo.path
        if not os.path.exists(photo_path):
            return False, "Photo file ?????????????"
 
        try:
            img_array, face_locations = preprocess_image(photo_path)
 
            if not face_locations:
                return False, "Photo-?? ????? ???????????"
 
            # Register-???? num_jitters=5 — better accuracy
            encodings = face_recognition.face_encodings(
                img_array,
                known_face_locations=face_locations,
                num_jitters=5,
            )
            if not encodings:
                return False, "Face encode ????????"
 
            employee.save_encoding(encodings[0])
            invalidate_cache()
            print(f"[Encoding] Saved for: {employee.name}")
            return True, "Encoding saved"
 
        except Exception as e:
            print(f"[Encoding Error] {employee.name}: {e}")
            return False, str(e)
 
    def post(self, request):
        data        = request.data
        profile_pic = request.FILES.get('profile_pic')
 
        try:
            dept_id  = data.get('department')
            desig_id = data.get('designation')
            dept     = Department.objects.get(id=dept_id)  if dept_id  else None
            desig    = Designation.objects.get(id=desig_id) if desig_id else None
 
            employee = Employee.objects.create(
                name=data.get('name'),
                mobile=data.get('mobile'),
                age=data.get('age'),
                address=data.get('address'),
                department=dept,
                designation=desig,
                doj=data.get('doj'),
                photo=profile_pic,
                created_by=request.user if request.user.is_authenticated else None
            )
 
            encoding_status = "Photo ?????"
            if profile_pic:
                ok, encoding_status = self._save_face_encoding(employee)
                if not ok:
                    print(f"[Warning] Encoding failed for {employee.name}: {encoding_status}")
 
            return Response({
                "status":          {"code": status.HTTP_201_CREATED, "response": "success"},
                "error":           None,
                "message":         "Employee created successfully",
                "encoding_status": encoding_status,
            })
 
        except Exception as e:
            return Response({
                "status":  {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error":   True,
                "message": f"Error: {str(e)}",
            })
 
    def put(self, request, id):
        data        = request.data
        profile_pic = request.FILES.get('profile_pic')
 
        try:
            emp = Employee.objects.get(id=id)
 
            if 'department' in data:
                emp.department  = Department.objects.get(id=data.get('department'))
            if 'designation' in data:
                emp.designation = Designation.objects.get(id=data.get('designation'))
 
            emp.name    = data.get("name",    emp.name)
            emp.mobile  = data.get("mobile",  emp.mobile)
            emp.age     = data.get("age",     emp.age)
            emp.address = data.get("address", emp.address)
            emp.doj     = data.get("doj",     emp.doj)
            emp.status  = data.get("status",  emp.status)
 
            if profile_pic:
                emp.photo = profile_pic
            emp.save()
 
            encoding_status = "Photo ?????????"
            if profile_pic or (emp.photo and not emp.face_encoding_data):
                ok, encoding_status = self._save_face_encoding(emp)
                if not ok:
                    print(f"[Warning] Encoding update failed for {emp.name}: {encoding_status}")
 
            return Response({
                "status":          {"code": 200, "response": "success"},
                "message":         "Employee updated successfully",
                "encoding_status": encoding_status,
            })
 
        except Employee.DoesNotExist:
            return Response({
                "status":  {"code": 404, "response": "failed"},
                "message": "Employee not found",
            })
        except Exception as e:
            return Response({
                "status":  {"code": 400, "response": "failed"},
                "message": str(e),
            })

    def delete(self, request, id):
        try:
            emp = Employee.objects.get(id=id)
            emp.delete()
            return Response({
                "status": {"code": 200, "response": "success"},
                "message": "Employee deleted"
            })
        except Employee.DoesNotExist:
            return Response({"status": {"code": 404, "response": "failed"}, "message": "Not found"})

    # def delete(self, request, id):
    #     if id is not None:
    #         try:
    #             product_id_str = str(id)
    #             is_used = Enquiry.objects.filter(product__contains=[product_id_str]).exists()

    #             if is_used:
    #                 return Response({
    #                     "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
    #                     "error": "Product is used in enquiry",
    #                     "message": "Cannot delete product. It's used in one or more enquiries."
    #                 })

    #             # If not used, delete the product
    #             product = Product.objects.get(id=id)
    #             product.delete()

    #             return Response({
    #                 "status": {"code": status.HTTP_200_OK, "response": "success"},
    #                 "error": None,
    #                 "message": "Product deleted successfully"
    #             })

    #         except Product.DoesNotExist:
    #             return Response({
    #                 "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
    #                 "error": None,
    #                 "message": "No product found"
    #             })


class FetchdesignationAPIView(APIView):
    def get(self, request, id):
        company = Designation.objects.filter(department_id=id)

        data = []

        for i in company:
            data.append({
                'name': i.name,
                'id': i.id
            })

        return Response({
            "status": {"code": status.HTTP_200_OK, "response": "success"},
            "error": None,
            "data": data
        })
    


class StudentStatusAPIView(APIView):
    def patch(self, request, id):
        try:
            student = Employee.objects.get(id=id)
            # 1-ஆக இருந்தால் 2-க்கு மாற்றவும், இல்லையென்றால் 1-க்கு மாற்றவும்
            if student.status == 1:
                student.status = 2
            else:
                student.status = 1
            
            student.save()
            return Response({
                "status": {"code": 200, "response": "success"},
                "new_status": student.status,
                "message": "Status updated successfully"
            })
        except Employee.DoesNotExist:
            return Response({"error": "Student not found"}, status=404)
from datetime import datetime, time
import calendar

class MonthlyAttendanceAPIView(APIView):

    def get(self, request):
        val = request.query_params.get('val')
        if val:
            try:
                year, month = map(int, val.split('-'))
            except ValueError:
                return Response({"error": "Invalid val format. Use YYYY-MM"}, status=400)
        else:
            month = int(request.query_params.get('month', datetime.now().month))
            year  = int(request.query_params.get('year',  datetime.now().year))

        student_id_param  = request.query_params.get('student_id')
        office_start_time = time(8, 30, 0)

        num_days   = calendar.monthrange(year, month)[1]
        month_name = calendar.month_name[month][:3]

        days_list = []
        for d in range(1, num_days + 1):
            dt = datetime(year, month, d)
            # ✅ key = "2026-03-18" — existing frontend match ஆகும்
            date_key = f"{year}-{month:02d}-{d:02d}"
            days_list.append({
                "day_num":  d,
                "display":  f"{month_name} {d:02d}",
                "day_name": dt.strftime("%a").upper(),
                "date":     date_key,
            })

        if student_id_param and student_id_param != "all":
            students = Employee.objects.filter(id=student_id_param)
        else:
            students = Employee.objects.all()

        attendance_records = Attendance.objects.filter(
            date__month=month,
            date__year=year
        ).select_related('employee')

        report_data = []
        for student in students:
            student_att = {}
            total_p     = 0
            total_a     = 0
            late_count  = 0

            for day_obj in days_list:
                d        = day_obj["day_num"]
                date_key = day_obj["date"]

                rec = attendance_records.filter(
                    employee_id=student.id,
                    date__day=d
                ).first()

                if rec:
                    status = "P" if rec.status == "Present" else "A"
                else:
                    status = "-"

                # ✅ Same logic as TodayAttendanceAPIView
                if rec and rec.in_time and rec.in_time > office_start_time:
                    late_count += 1

                student_att[date_key] = {
                    "status": status,
                    "ot":     "00:00",
                }

                if status == "P":
                    total_p += 1
                elif status == "A":
                    total_a += 1

            report_data.append({
                "name":          student.studentName,
                "code":          getattr(student, 'emp_id', str(student.id)),
                "attendance":    student_att,
                "total_present": total_p,
                "total_absent":  total_a,
                "late_count":    late_count,  # ✅ இது புதுசா சேர்க்கிறோம்
                "total_ot":      "00:00",
            })

        print('MONTHLY API HIT - late_count working!', flush=True)

        return Response({
            "month":  month,
            "year":   year,
            "days":   days_list,
            "report": report_data
        })

from datetime import date
from django.utils import timezone

import threading
import time as time_module

# ============================================================
# GLOBAL IN-MEMORY CACHE
# ============================================================
_encoding_cache = {
    "encodings":   [],
    "ids":         [],
    "last_reload": 0,
}
_cache_lock = threading.Lock()
CACHE_TTL   = 300  # 5 minutes
 
 
def load_encoding_cache(force=False):
    global _encoding_cache
    # now = time.time()
    now = time_module.time()     
    with _cache_lock:
        if not force and (now - _encoding_cache["last_reload"]) < CACHE_TTL:
            return
        employees = Employee.objects.exclude(
            face_encoding_data__isnull=True
        ).exclude(face_encoding_data='')
        encodings, ids = [], []
        for emp in employees:
            enc = emp.get_encoding()
            if enc is not None:
                encodings.append(enc)
                ids.append(emp.id)
        _encoding_cache["encodings"]   = encodings
        _encoding_cache["ids"]         = ids
        _encoding_cache["last_reload"] = now
        print(f"[Cache] {len(encodings)} encodings loaded.")
 
 
def invalidate_cache():
    with _cache_lock:
        _encoding_cache["last_reload"] = 0
 
 
# ============================================================
# SMART IMAGE PREPROCESSOR
# ???? size, ???? quality photo-???? face detect ?????
# ============================================================
def preprocess_image(source):
    """
    source: uploaded file object ?????? file path string
 
    5 different attempts-?? face detect ???????:
      1. Normal HOG
      2. HOG + upsample (small photos)
      3. Extra brightness (dark photos)
      4. 800px width resize (portrait photos)
      5. Horizontally flipped (selfie mirror issue)
 
    Returns: (img_array, face_locations)
    """
    # -- Load image --
    if isinstance(source, str):
        pil_img = Image.open(source).convert('RGB')
    else:
        source.seek(0)
        pil_img = Image.open(io.BytesIO(source.read())).convert('RGB')
 
    w, h = pil_img.size
    print(f"[DEBUG] Original size: {w}x{h}")
 
    # -- Too small ? upscale (thumbnail, WhatsApp compressed) --
    short = min(w, h)
    if short < 200:
        scale   = 300 / short
        pil_img = pil_img.resize(
            (int(w * scale), int(h * scale)), Image.LANCZOS
        )
        w, h = pil_img.size
        print(f"[DEBUG] Upscaled to: {w}x{h}")
 
    # -- Too large ? downscale (DSLR, 4K photos) --
    long = max(w, h)
    if long > 1200:
        scale   = 1200 / long
        pil_img = pil_img.resize(
            (int(w * scale), int(h * scale)), Image.LANCZOS
        )
        w, h = pil_img.size
        print(f"[DEBUG] Downscaled to: {w}x{h}")
 
    # -- Enhance: brightness + contrast + sharpness --
    pil_img = ImageEnhance.Brightness(pil_img).enhance(1.2)
    pil_img = ImageEnhance.Contrast(pil_img).enhance(1.3)
    pil_img = ImageEnhance.Sharpness(pil_img).enhance(1.5)
 
    img_array = np.array(pil_img)
 
    # -- Attempt 1: Normal HOG --
    locs = face_recognition.face_locations(img_array, model="hog", number_of_times_to_upsample=1)
    print(f"[DEBUG] Attempt 1 (HOG): {len(locs)} faces")
    if locs:
        return img_array, locs
 
    # -- Attempt 2: HOG with upsample=2 (small face) --
    locs = face_recognition.face_locations(img_array, model="hog", number_of_times_to_upsample=2)
    print(f"[DEBUG] Attempt 2 (HOG upsample=2): {len(locs)} faces")
    if locs:
        return img_array, locs
 
    # -- Attempt 3: Extra brightness (dark photo) --
    bright_arr = np.array(ImageEnhance.Brightness(pil_img).enhance(1.8))
    locs       = face_recognition.face_locations(bright_arr, model="hog", number_of_times_to_upsample=2)
    print(f"[DEBUG] Attempt 3 (extra bright): {len(locs)} faces")
    if locs:
        return bright_arr, locs
 
    # -- Attempt 4: 800px width resize --
    new_h      = int(800 * h / w) if w > 0 else 800
    resized    = pil_img.resize((800, new_h), Image.LANCZOS)
    resize_arr = np.array(resized)
    locs       = face_recognition.face_locations(resize_arr, model="hog", number_of_times_to_upsample=1)
    print(f"[DEBUG] Attempt 4 (800w resize): {len(locs)} faces")
    if locs:
        return resize_arr, locs
 
    # -- Attempt 5: Horizontally flipped (selfie mirror issue) --
    flipped  = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
    flip_arr = np.array(flipped)
    locs     = face_recognition.face_locations(flip_arr, model="hog", number_of_times_to_upsample=1)
    print(f"[DEBUG] Attempt 5 (flipped): {len(locs)} faces")
    if locs:
        return flip_arr, locs
 
    return img_array, []
 
 
# ============================================================
# Attendance API — GET / POST
# ============================================================
class AttendanceAPIView(APIView):
 
    def get(self, request):
        try:
            query_date   = request.query_params.get('date', date.today().isoformat())
            session_type = request.query_params.get('session_type')
            attendances  = Attendance.objects.filter(date=query_date).order_by('-created_at')
            if session_type:
                attendances = attendances.filter(session_type=session_type)
 
            attendance_list = []
            for index, att in enumerate(attendances, 1):
                attendance_list.append({
                    'row':          index,
                    'id':           att.id,
                    'studentId':    att.student.id,
                    'studentName':  att.student.studentName,
                    'status':       att.status,
                    'session_type': att.session_type,
                    'date':         att.date,
                })
            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error":  None,
                "data":   attendance_list,
            })
        except Exception as e:
            return Response({
                "status":  {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error":   True,
                "message": str(e),
            })
 
    def post(self, request):
        uploaded_file = request.FILES.get('image')
        if not uploaded_file:
            return Response({"message": "Image required"}, status=400)
 
        try:
            # -- 1. Preprocess + detect --
            img_array, face_locations = preprocess_image(uploaded_file)
 
            if not face_locations:
                return Response({
                    "message": "????? ?????? ???????????! ???????? camera-? ?????????."
                }, status=400)
 
            # -- 2. Encode --
            target_encodings = face_recognition.face_encodings(
                img_array,
                known_face_locations=face_locations,
                num_jitters=1,
            )
            if not target_encodings:
                return Response({
                    "message": "????? ????????? ????? encode ????????. ???????? ??????????????."
                }, status=400)
 
            target_enc = target_encodings[0]
 
            # -- 3. Cache load --
            load_encoding_cache()
            known_encodings = _encoding_cache["encodings"]
            known_ids       = _encoding_cache["ids"]
 
            if not known_encodings:
                return Response({
                    "message": "????? ??????????? ???????? ??????? ?????!"
                }, status=400)
 
            # -- 4. Vectorized match --
            face_distances = face_recognition.face_distance(known_encodings, target_enc)
            best_idx       = int(np.argmin(face_distances))
            best_distance  = float(face_distances[best_idx])
 
            print(f"[DEBUG] Best match distance: {best_distance:.4f} (threshold: 0.50)")
 
            if best_distance > 0.50:
                return Response({
                    "message": "???? ????? ???????? ??? ???????????!"
                }, status=401)
 
            # -- 5. Save attendance --
            emp_id     = known_ids[best_idx]
            found_user = Employee.objects.get(id=emp_id)
            today      = timezone.now().date()
            now_time   = timezone.now().time()
 
            att, created = Attendance.objects.get_or_create(
                employee_id=found_user.id,
                date=today,
                defaults={'status': 'Present', 'in_time': now_time}
            )
 
            if not created:
                att.out_time = now_time
                att.save()
                msg    = f"?????????? ????? ?????: {found_user.name}"
                action = "out"
            else:
                msg    = f"????? ?????: {found_user.name}"
                action = "in"
 
            return Response({
                "status":  "success",
                "message": msg,
                "data": {
                    "name":     found_user.name,
                    "action":   action,
                    "distance": round(best_distance, 3),
                },
            })
 
        except Exception as e:
            print(f"[ERROR] Attendance post: {e}")
            return Response({"error": str(e)}, status=500)
class DesignationAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, id=None):
        if id is not None:
            try:
                designation = Designation.objects.get(id=id)
                data = {
                    'id': designation.id,
                    'name': designation.name,
                    'description': designation.description,
                    'department': designation.department_id
                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:
                index = 0
                designations = []

                for designation in Designation.objects.all():
                    index += 1

                    try:
                        department = Department.objects.get(id=designation.department_id)
                        department = department.name
                    except Department.DoesNotExist:
                        department = ''

                    designations.append({
                        'row': index,
                        'id': designation.id,
                        'name': designation.name,
                        'description': designation.description,
                        'department': department
                    })

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": designations
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })

    def post(self, request):
        data = request.data

        try:
            department = Designation.objects.create(
                name=data["name"],
                description=data["description"],
                department=Department.objects.get(id=data["department"]),
                created_by=request.user
            )
            department.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Designation created successfully"
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })

    def put(self, request, id):
        data = request.data

        try:
            designation = Designation.objects.get(id=id)

            designation.name = data["name"]
            designation.description = data["description"]
            designation.department = Department.objects.get(id=data["department"])
            designation.save()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Designation updated successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })

    def delete(self, request, id):
        if id is not None:
            try:
                designation = Designation.objects.get(id=id)
                designation.delete()

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "message": "Designation deleted successfully"
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": None,
                    "message": "No data found"
                })
        else:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": None,
                "message": "Something went wrong"
            })
        
class DepartmentAPIView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, id=None):
        if id is not None:
            try:
                company = Department.objects.get(id=id)
                data = {
                    'id': company.id,
                    'name': company.name,
                    'description': company.description
                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:

                index = 0
                companies = []

                for company in Department.objects.all():
                    index += 1

                    companies.append({
                        'row': index,
                        'id': company.id,
                        'name': company.name,
                        'description': company.description,
                    })

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })

    def post(self, request):
        data = request.data

        try:
            company = Department.objects.create(
                name=data["name"],
                description=data["description"],
                created_by=request.user
            )
            company.save()

            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Department created successfully"
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })

    def put(self, request, id):
        data = request.data

        try:
            company = Department.objects.get(id=id)
            company.name = data["name"]
            company.description = data["description"]
            company.save()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Department updated successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })
        except Exception as e:
            print(e)
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": "Something went wrong"
            })

    def delete(self, request, id):
        if id is not None:
            try:
                company = Department.objects.get(id=id)
                company.delete()

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "message": "Department deleted successfully"
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": None,
                    "message": "No data found"
                })


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

    def get(self, request, id=None):
        if id is not None:
            try:
                company = Announcement.objects.get(id=id)
                data = {
                    'id': company.id,
                    'date': company.date,
                    'description': company.description
                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:

                index = 0
                companies = []

                for company in Announcement.objects.all():
                    index += 1

                    companies.append({
                        'row': index,
                        'id': company.id,
                        'date': company.date,
                        'description': company.description,
                    })

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })

    def post(self, request):
        data = request.data

        try:
            date=data["date"]
            description=data["description"]
            company = Announcement.objects.create(
                date=data["date"],
                description=data["description"],
                created_by=request.user
            )
            company.save()


            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Announcement created successfully"
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })

    def put(self, request, id):
        data = request.data

        try:

            date = data["date"]
            description = data["description"]
            company = Announcement.objects.get(id=id)
            company.date = data["date"]
            company.description = data["description"]
            company.save()




           

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Announcement updated successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })
        except Exception as e:
            print(e)
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": "Something went wrong"
            })

    def delete(self, request, id):
        if id is not None:
            try:
                company = Announcement.objects.get(id=id)
                company.delete()

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "message": "Department deleted successfully"
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": None,
                    "message": "No data found"
                })


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


   
    def get(self, request, id=None):
        if id is not None:
            try:
                company = LeaveRequest.objects.get(id=id)
               
                data = {
                    'id': company.id,
                    'name': company.type,
                    'description': company.reason,
                    'totaldays': company.total_days,
                    'leavedates': company.leave_dates,
                    'status' : company.status
                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:

                index = 0
                companies = []

                for company in LeaveRequest.objects.filter(created_by_id=request.user):
                    index += 1
                    tf = company.created_at  # tf is already a datetime object
                    # Format the datetime object to the desired string format
                    date_str = tf.strftime('%Y-%m-%d %H:%M:%S')

                    companies.append({
                        'row': index,
                        'id': company.id,
                        'type': company.type,
                        'reason': company.reason,
                        'td': company.total_days,
                        'date': date_str,
                        'status': company.status,
                        'why' : company.why,

                    })

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })

    def post(self, request):
        data = request.data

        try:
            casual = data['name']
            man = data['totalday']
            leave_request = LeaveRequest(
            type=data['name'],
            reason=data['description'],
            total_days=data['totalday'],
            leave_dates=data['leavedate'],
            created_by=request.user
            )
            leave_request.save()


            jk = Profiles.objects.get(user_id=request.user)

            meesi = Profiles.objects.get(user_id=jk.authority_id)


            ro = meesi.email
        
            login_url = "https://pearlpackagingindia.com/manageleave"

            subject = "Leave request"
            body = f"""
            Hi am {jk.name},

            This is my leave request for {casual}.

            Total days: {man}

            

            You can log in using the following link and check:
            {login_url}

            

            
            """
            we = jk.email
            # Create the email message
            email = EmailMessage(
                subject=subject,
                body=body,
                from_email=settings.EMAIL_HOST_USER,
                to=[ro],
                # to=[fieldstaffemail],  # Uncomment and use this if you have a dynamic recipient
            )

            # Send the email
            email.send()


            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Leave request created successfully"
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })

    def put(self, request, id):
        data = request.data

        try:
            company = LeaveRequest.objects.get(id=id)
            company.type = data["name"]
            company.reason = data["description"]
            company.leave_dates = data["leavedate"]
            company.total_days = data["totalday"]

            company.save()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Department updated successfully"
            })
        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })
        except Exception as e:
            print(e)
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": "Something went wrong"
            })

    def delete(self, request, id):
        if id is not None:
            try:
                company = Department.objects.get(id=id)
                company.delete()

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "message": "Department deleted successfully"
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": None,
                    "message": "No data found"
                })


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

    def get(self, request, id=None):
        if id is not None:
            try:

                


                company = LeaveRequest.objects.get(id=id)
               
                data = {
                    'id': company.id,
                    'name': company.type,
                    'description': company.reason,
                    'totaldays': int(company.total_days),
                    'leavedates': company.leave_dates,
                    'why': company.why,
                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:

                index = 0
                companies = []

                erp = Profiles.objects.filter(authority_id=request.user)
                for m in erp:

                    for company in LeaveRequest.objects.filter(created_by=m.user_id):
                        index += 1
                        tf = company.created_at  # tf is already a datetime object
                        # Format the datetime object to the desired string format
                        date_str = tf.strftime('%Y-%m-%d %H:%M:%S')

                        try:
                            user_id = company.created_by_id
                            val = User.objects.get(id=user_id)
                            username = val.first_name + ' ' + val.last_name
                        except (ValueError, User.DoesNotExist):
                            username = "Unknown"

                        companies.append({
                            'row': index,
                            'id': company.id,
                            'type': company.type,
                            'reason': company.reason,
                            'td': company.total_days,
                            'date': date_str,
                            'status': company.status,
                            'username': username

                        })

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })

    
    def put(self, request, id):
        data = request.data

        try:
            # Attempt to convert totalday to float, or set a default value if None
            try:
                rto = float(data["totalday"]) if data["totalday"] is not None else 0.0
            except (ValueError, TypeError):
                rto = 0.0

            sta = data.get("status")
            ml = data.get("totalday", 0.0)
            names = data.get("name", "")

            if sta == '2':
                we = "Approved"
            elif sta == '3':
                we = "Rejected"
            else:
                we = "Pending"

            try:
                company = LeaveRequest.objects.get(id=id)
                company.type = names
                company.reason = data.get("description", "")
                company.leave_dates = data.get("leavedate", "")
                company.total_days = ml
                company.status = sta
                company.why = data.get("why", "")

                company.save()

                if sta == '2':
                    try:
                        pr = Profiles.objects.get(user_id=company.created_by_id)
                        if pr.total_leave is None:
                            pr.total_leave = 0  # Set to 0 if None
                        
                        # Ensure total_leave is treated as an integer
                            pr.total_leave = int(pr.total_leave)
                            pr.save()
                    except Profiles.DoesNotExist:
                        # Handle case where Profiles object doesn't exist
                        print(f"Profile for user ID {company.created_by_id} does not exist.")
                        pass

            except LeaveRequest.DoesNotExist:
                # Handle case where LeaveRequest object doesn't exist
                print(f"LeaveRequest with ID {id} does not exist.")
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found"
                })

            # Send an email notification
            try:
                jk = Profiles.objects.get(user_id=request.user)
                pr = Profiles.objects.get(user_id=company.created_by_id)

                ro = jk.email
                login_url = "https://pearlpackagingindia.com/leaverequest"

                subject = "Leave request"
                body = f"""
                Your leave request {names} is {we}.
                Total days: {ml}

                You can log in using the following link and check:
                {login_url}
                """

                recipient_email = pr.email
                print(recipient_email, 'Sending email to recipient')

                email = EmailMessage(
                    subject=subject,
                    body=body,
                    from_email=settings.EMAIL_HOST_USER,
                    to=[recipient_email],
                )

                email.send()

            except Profiles.DoesNotExist:
                print(f"Profile for user ID {company.created_by_id} does not exist.")
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "Profile not found for email notification"
                })

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Request updated successfully"
            })

        except ObjectDoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "No data found"
            })

        except Exception as e:
            print(f"Error occurred: {e}")
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": "Something went wrong"
            })
        

from datetime import datetime, time
class TodayAttendanceAPIView(APIView):
    def get(self, request):
        # 1. தேதியை பெறுதல் (Default: Today)
        date_str = request.query_params.get('date', None)
        if date_str:
            target_date = datetime.strptime(date_str, '%Y-%m-%d').date()
        else:
            target_date = datetime.now().date()

        # 2. நேர வரையறைகள்
        office_start_time = time(8, 30, 0)  # 8:30 AM

        # 6:00 PM-ஐ 5:00 PM (17:00) ஆக மாற்றுகிறோம்   
        office_end_time = time(17, 0, 0)    # 5:00 PM

        # 3. வந்தவர்கள் பட்டியல் (Present List)
        attendance_records = Attendance.objects.filter(date=target_date).select_related('employee')
        present_list = []

        for record in attendance_records:
            entry_status = "On Time"
            overtime = "0:00"

            # Late Calculation
            if record.in_time and record.in_time > office_start_time:
                entry_status = "Late"
            elif record.in_time and record.in_time <= office_start_time:
                entry_status = "Early/On-Time"

            # OT Calculation (மாலை 6 மணிக்கு மேல் இருந்தால்)
            if record.out_time and record.out_time > office_end_time:
                # நேர வித்தியாசத்தை கணக்கிடுதல்
                dummy_today = datetime.today()
                dt_out = datetime.combine(dummy_today, record.out_time)
                dt_off = datetime.combine(dummy_today, office_end_time)
                diff = dt_out - dt_off
                hours, remainder = divmod(diff.seconds, 3600)
                minutes, _ = divmod(remainder, 60)
                overtime = f"{hours}h {minutes}m"

            present_list.append({
                "id": record.employee.id,
                "name": record.employee.name,
                "photo": record.employee.photo.url if record.employee.photo else None,
                "in_time": record.in_time.strftime('%I:%M %p') if record.in_time else "--",
                "out_time": record.out_time.strftime('%I:%M %p') if record.out_time else "--",
                "entry_status": entry_status,
                "ot_time": overtime
            })

        # 4. வராதவர்கள் பட்டியல் (Absent List)
        present_ids = attendance_records.values_list('employee_id', flat=True)
        absent_employees = Employee.objects.exclude(id__in=present_ids)
        
        absent_list = [{
            "id": emp.id,
            "name": emp.name,
            "photo": emp.photo.url if emp.photo else None
        } for emp in absent_employees]

        return Response({
            "date": target_date,
            "present_count": len(present_list),
            "absent_count": len(absent_list),
            "present_list": present_list,
            "absent_list": absent_list
        }, status=status.HTTP_200_OK)








class FpAPIView(APIView):

    

    def post(self, request):
        data = request.data

        try:
            
            params = data.get('params', {})

            # Now retrieve 'email' and 'password' from the 'params' dictionary
            email = params.get('email')  # Access the 'email' field
            password = params.get('password')  # Access the 'password' field


            # Hash the password
            hashed_password = make_password(password)

            man = User.objects.get(email=email)

            man.password = hashed_password

            man.save()



            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": "Password reset successfully"
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })
class MonthattendanceAPIView(APIView):
    def get(self, request, *args, **kwargs):
        val = request.GET.get('val')  # எதிர்பார்ப்பது: "2026-01"
        try:
            first_day = datetime.strptime(val + "-01", "%Y-%m-%d").date()
            if first_day.month == 12:
                last_day = first_day.replace(year=first_day.year + 1, month=1, day=1) - timedelta(days=1)
            else:
                last_day = first_day.replace(month=first_day.month + 1, day=1) - timedelta(days=1)

            dates_in_month = [first_day + timedelta(days=i) for i in range((last_day - first_day).days + 1)]

            holiday_announcements = Announcement.objects.filter(date__range=[first_day, last_day])
            announcement_dates    = set(ann.date for ann in holiday_announcements)

            employees      = Employee.objects.filter(status=1)
            all_attendance = Attendance.objects.filter(date__range=[first_day, last_day])

            office_start_time = time(8, 30, 0)

            today        = date.today()
            final_report = []

            for emp in employees:
                emp_records      = {r.date: r for r in all_attendance if r.employee_id == emp.id}
                total_p          = 0
                total_a          = 0
                total_ot_seconds = 0
                late_count       = 0
                attendance_map   = {}

                for day in dates_in_month:
                    day_str    = day.strftime("%Y-%m-%d")
                    ot_display = "00:00"

                    if day in emp_records:
                        rec = emp_records[day]
                        if rec.status == "Present":
                            status_code = "P"
                            total_p += 1

                            # ✅ Late check
                            if rec.in_time and rec.in_time > office_start_time:
                                late_count += 1

                            # OT Calculation
                            if rec.in_time and rec.out_time:
                                start = datetime.combine(date.today(), rec.in_time)
                                end   = datetime.combine(date.today(), rec.out_time)
                                diff  = (end - start).total_seconds()
                                if diff > 28800:
                                    ot_sec = diff - 28800
                                    total_ot_seconds += ot_sec
                                    ot_display = f"{int(ot_sec // 3600):02d}:{int((ot_sec % 3600) // 60):02d}"
                        else:
                            status_code = "A"
                            total_a += 1

                    elif day in announcement_dates:
                        status_code = "H"
                    elif day.weekday() == 6:
                        status_code = "H"
                    elif day > today:
                        status_code = "--"
                    else:
                        status_code = "A"
                        total_a += 1

                    attendance_map[day_str] = {"status": status_code, "ot": ot_display}

                # ✅ ஒவ்வொரு 3 late = 0.5 day cut
                # late_count=3 → half_day_cuts=1 → deduction=0.5
                # late_count=6 → half_day_cuts=2 → deduction=1.0
                # late_count=2 → half_day_cuts=0 → deduction=0.0
                half_day_cuts      = late_count // 3           # எத்தனை 0.5 day cut
                late_deduction     = half_day_cuts * 0.5       # total cut days (0.5, 1.0, 1.5...)
                effective_present  = total_p - late_deduction  # actual present after cut
                if effective_present < 0:
                    effective_present = 0

                total_ot_h = int(total_ot_seconds // 3600)
                total_ot_m = int((total_ot_seconds % 3600) // 60)

                final_report.append({
                    "name":               emp.name,
                    "code":               emp.mobile,
                    "total_present":      total_p,           # Raw present (without cut)
                    "effective_present":  effective_present, # ✅ After late deduction
                    "total_absent":       total_a,
                    "total_ot":           f"{total_ot_h:02d}:{total_ot_m:02d}",
                    "late_count":         late_count,        # ✅ Total late days
                    "half_day_cuts":      half_day_cuts,     # ✅ எத்தனை 0.5 cut ஆச்சு
                    "late_deduction":     late_deduction,    # ✅ Total deduction (0.5, 1.0...)
                    "attendance":         attendance_map,
                })

            return Response({
                "days": [
                    {
                        "date":     d.strftime("%Y-%m-%d"),
                        "display":  d.strftime("%d"),
                        "day_name": d.strftime("%a"),
                    }
                    for d in dates_in_month
                ],
                "report": final_report
            }, status=200)

        except Exception as e:
            return Response({"error": str(e)}, status=400)


class SalaryAPIView(APIView):

    def get(self, request, id=None):
        if id is not None:
            try:
                company = Department.objects.get(id=id)
                data = {
                    'id': company.id,
                    'name': company.name,
                    'description': company.description
                }

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except ObjectDoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "No data found",
                })
        else:
            try:
                now = datetime.now()
                month = int(request.query_params.get('month', now.month))
                year  = int(request.query_params.get('year',  now.year))

                total_days = calendar.monthrange(year, month)[1]

                # ✅ அந்த month-இன் date range
                from datetime import date
                month_start = date(year, month, 1)
                month_end   = date(year, month, total_days)

                # ✅ Late threshold — 09:00 AM
                LATE_TIME = time(9, 0, 0)

                # ✅ Late deduction rule: 3 lates = 1 day cut
                LATES_PER_DAY_CUT = 3

                index = 0
                companies = []

                for company in Employee.objects.all():
                    index += 1

                    # ── 1. அந்த employee-இன் அந்த month attendance எடுக்கிறோம் ──
                    attendance_qs = Attendance.objects.filter(
                        employee_id=company.id,
                        date__gte=month_start,
                        date__lte=month_end,
                    )

                    # ── 2. Present days count ──
                    present_days = attendance_qs.filter(status='Present').count()

                    # ── 3. Late count — in_time > 09:00:00 ──
                    late_count = 0
                    for att in attendance_qs.filter(status='Present'):
                        if att.in_time and att.in_time > LATE_TIME:
                            late_count += 1

                    # ── 4. Late deduction days calculate ──
                    # 3 lates = 1 day cut, 6 lates = 2 days cut

                    late_deduction_days = (late_count // 3) * 0.5   # ✅ float: 0.5, 1.0, 1.5...


                    working_days = max(0.0, present_days - late_deduction_days) 


                    companies.append({
                        'row':           index,
                        'id':            company.id,
                        'name':          company.name,
                        'pan':           company.pan,
                        'ctc':           float(company.ctc),
                        'grossSalary':   float(company.grossSalary),
                        'basic':         float(company.basic),
                        'hra':           float(company.hra),
                        'conveyance':    float(company.conveyance),
                        'otherAllowance':float(company.otherAllowance),
                        'totalDays':     total_days,
                        'workingDays':   working_days,       # ✅ auto calculated
                        'presentDays':   present_days,       # ✅ info only
                        'lateCount':     late_count,         # ✅ frontend-ல் காட்டலாம்
                        'lateDeduction': late_deduction_days,# ✅ frontend-ல் காட்டலாம்
                        'fixedPT':       float(company.fixedPT),
                        'pfLimit':       float(company.pfLimit),
                        'advance':       float(company.advance),
                        'ot':            float(company.ot),
                        'reimbursement': float(company.reimbursement),
                        'incentive':     float(company.incentive),
                        'month':         month,
                        'year':          year,
                    })


                    print(companies)

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })

            except Exception as e:
                print(f"Error: {e}")
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": str(e)
                })
    def put(self, request, id):
        data = request.data

        try:
            # ID-யை வைத்து சரியான எம்ப்ளாயியை எடுக்கிறோம்
            employee = Employee.objects.get(id=id)
            
            # --- பேசிக் இன்போ அப்டேட் ---
            employee.pan = data.get("pan", employee.pan)
            
            # --- சேலரி மற்றும் அட்டெண்டன்ஸ் டேட்டா அப்டேட் ---
            # data.get() பயன்படுத்துவதால், ஒருவேளை டேட்டா வராவிட்டாலும் பழைய வேல்யூ அப்படியே இருக்கும்
            employee.ctc = data.get("ctc", employee.ctc)
            employee.grossSalary = data.get("grossSalary", employee.grossSalary)
            employee.basic = data.get("basic", employee.basic)
            employee.hra = data.get("hra", employee.hra)
            employee.conveyance = data.get("conveyance", employee.conveyance)
            employee.otherAllowance = data.get("otherAllowance", employee.otherAllowance)
            
            # employee.totalDays = data.get("totalDays", employee.totalDays)
            # employee.workingDays = data.get("workingDays", employee.workingDays)
            
            # --- கழிவுகள் மற்றும் இதர வேல்யூக்கள் ---
            employee.fixedPT = data.get("fixedPT", employee.fixedPT)
            employee.pfLimit = data.get("pfLimit", employee.pfLimit)
            employee.advance = data.get("advance", employee.advance)
            employee.ot = data.get("ot", employee.ot)
            employee.reimbursement = data.get("reimbursement", employee.reimbursement)
            employee.incentive = data.get("incentive", employee.incentive)

            # டேட்டாபேஸில் சேமிக்கிறோம்
            employee.save()

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": f"Employee {employee.name} updated successfully"
            })

        except Employee.DoesNotExist:
            return Response({
                "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                "error": True,
                "message": "Employee not found"
            })
        except Exception as e:
            print(f"Error: {e}")
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": "Something went wrong during update"
            })


class PayslipAPIView(APIView):
    # permission_classes = [IsAuthenticated]

    def get(self, request, id=None):
        if id is not None:
            try:
                company = Payslip.objects.get(id=id)
                data = {
                    'id':               company.id,
                    'empname':          company.empname,
                    'empid':            company.empid,
                    'emppan':           company.emppan,
                    'ctc':              company.ctc,
                    'grosssalary':      company.grosssalary,
                    'perdaysalary':     company.perdaysalary,
                    'basicsalary':      company.basicsalary,
                    'hra':              company.hra,
                    'conveyance':       company.conveyance,
                    'otherallowance':   company.otherallowance,
                    'totaldays':        company.totaldays,
                    'workingdays':      company.workingdays,
                    'baiscnew':         company.baiscnew,
                    'hranew':           company.hranew,
                    'conveyancenew':    company.conveyancenew,
                    'otherallowancenew':company.otherallowancenew,
                    'grosspay':         company.grosspay,
                    'variablepfgross':  company.variablepfgross,
                    'pfless':           company.pfless,
                    'esiless':          company.esiless,
                    'lesspt':           company.lesspt,
                    'pf':               company.pf,
                    'esi':              company.esi,
                    'bank':             company.bank,
                    'uan':              company.uan,
                    'advance':          company.advance,
                    'netpay':           company.netpay,
                    'ot':               company.ot,
                    'reimbursement':    company.reimbursement,
                    'incentive':        company.incentive,
                    'topay':            company.topay,
                    'month':            company.month,
                }
                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": data
                })
            except Payslip.DoesNotExist:
                return Response({
                    "status": {"code": status.HTTP_404_NOT_FOUND, "response": "failed"},
                    "error": True,
                    "message": "Payslip not found",
                })
        else:
            try:
             

                index = 0
                companies = []

                for company in Payslip.objects.all():
                    index += 1

             
                    companies.append({
                        'row':           index,
                        'id':            company.id,
                        'name':          company.empname,
                        'topay':           company.topay,
                        'month':           company.month,

                       
                    })


                    print(companies)

                return Response({
                    "status": {"code": status.HTTP_200_OK, "response": "success"},
                    "error": None,
                    "data": companies
                })

            except Exception as e:
                print(f"Error: {e}")
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": str(e)
                })

    def post(self, request):
        try:
            payslips_data = request.data.get("payslips", [])

            if not payslips_data:
                return Response({
                    "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                    "error": True,
                    "message": "Payslip data இல்லை"
                })

            created_list = []
            updated_list = []


            MONTH_NAMES = {
                1: "January", 2: "February", 3: "March",
                4: "April",   5: "May",      6: "June",
                7: "July",    8: "August",   9: "September",
                10: "October",11: "November",12: "December"
            }

            for p in payslips_data:
                month_val = p.get("month")
                emp_id    = p.get("employee")

                # ✅ FIX: Employee instance 
                month_name = MONTH_NAMES.get(int(month_val), str(month_val))

                try:
                    employee_instance = Employee.objects.get(id=emp_id)
                except Employee.DoesNotExist:
                    continue  # இல்லாத employee skip பண்றோம்

                existing = Payslip.objects.filter(
                    employee=employee_instance,
                    month=month_name
                ).first()

               

                if existing:
                    # ✅ UPDATE — field by field safe ஆக செட் பண்றோம்
                    existing.empname           = p.get("empname", existing.empname)
                    existing.empid             = p.get("empid", existing.empid)
                    existing.emppan            = p.get("emppan", existing.emppan)
                    existing.ctc               = p.get("ctc", existing.ctc)
                    existing.grosssalary       = p.get("grosssalary", existing.grosssalary)
                    existing.perdaysalary      = p.get("perdaysalary", existing.perdaysalary)
                    existing.basicsalary       = p.get("basicsalary", existing.basicsalary)
                    existing.hra               = p.get("hra", existing.hra)
                    existing.conveyance        = p.get("conveyance", existing.conveyance)
                    existing.otherallowance    = p.get("otherallowance", existing.otherallowance)
                    existing.totaldays         = p.get("totaldays", existing.totaldays)
                    existing.workingdays       = p.get("workingdays", existing.workingdays)
                    existing.baiscnew          = p.get("baiscnew", existing.baiscnew)
                    existing.hranew            = p.get("hranew", existing.hranew)
                    existing.conveyancenew     = p.get("conveyancenew", existing.conveyancenew)
                    existing.otherallowancenew = p.get("otherallowancenew", existing.otherallowancenew)
                    existing.grosspay          = p.get("grosspay", existing.grosspay)
                    existing.variablepfgross   = p.get("variablepfgross", existing.variablepfgross)
                    existing.pfless            = p.get("pfless", existing.pfless)
                    existing.esiless           = p.get("esiless", existing.esiless)
                    existing.lesspt            = p.get("lesspt", existing.lesspt)
                    existing.pf                = p.get("pf", existing.pf)
                    existing.esi               = p.get("esi", existing.esi)
                    existing.bank              = p.get("bank", existing.bank)
                    existing.uan               = p.get("uan", existing.uan)
                    existing.advance           = p.get("advance", existing.advance)
                    existing.netpay            = p.get("netpay", existing.netpay)
                    existing.ot                = p.get("ot", existing.ot)
                    existing.reimbursement     = p.get("reimbursement", existing.reimbursement)
                    existing.incentive         = p.get("incentive", existing.incentive)
                    existing.topay             = p.get("topay", existing.topay)
                    existing.month = month_name  # ✅ "March" store ஆகும்

                    existing.status            = 1
                    existing.save()
                    updated_list.append(emp_id)
                else:
                    # ✅ CREATE — employee instance pass பண்றோம்
                    Payslip.objects.create(
                        employee         = employee_instance,  # ✅ instance
                        empname          = p.get("empname", ""),
                        empid            = p.get("empid", ""),
                        emppan           = p.get("emppan", ""),
                        ctc              = p.get("ctc", "0"),
                        grosssalary      = p.get("grosssalary", "0"),
                        perdaysalary     = p.get("perdaysalary", "0"),
                        basicsalary      = p.get("basicsalary", "0"),
                        hra              = p.get("hra", "0"),
                        conveyance       = p.get("conveyance", "0"),
                        otherallowance   = p.get("otherallowance", "0"),
                        totaldays        = p.get("totaldays", "0"),
                        workingdays      = p.get("workingdays", "0"),
                        baiscnew         = p.get("baiscnew", "0"),
                        hranew           = p.get("hranew", "0"),
                        conveyancenew    = p.get("conveyancenew", "0"),
                        otherallowancenew= p.get("otherallowancenew", "0"),
                        grosspay         = p.get("grosspay", "0"),
                        variablepfgross  = p.get("variablepfgross", "0"),
                        pfless           = p.get("pfless", "0"),
                        esiless          = p.get("esiless", "0"),
                        lesspt           = p.get("lesspt", "0"),
                        pf               = p.get("pf", "0"),
                        esi              = p.get("esi", "0"),
                        bank             = p.get("bank", ""),
                        uan              = p.get("uan", ""),
                        advance          = p.get("advance", "0"),
                        netpay           = p.get("netpay", "0"),
                        ot               = p.get("ot", "0"),
                        reimbursement    = p.get("reimbursement", "0"),
                        incentive        = p.get("incentive", "0"),
                        topay            = p.get("topay", "0"),
                        month    = month_name,       # ✅ "March" store ஆகும்

                        status           = 1,
                    )
                    created_list.append(emp_id)

            return Response({
                "status": {"code": status.HTTP_200_OK, "response": "success"},
                "error": None,
                "message": f"{len(created_list)} created, {len(updated_list)} updated",
                "created": len(created_list),
                "updated": len(updated_list),
            })

        except Exception as e:
            print(f"Payslip Error: {e}")
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": str(e)
            })

class ProductactivestatusupdateAPIView(APIView):
    
    def put(self, request, id):
        

        try:
            


            ven = Product.objects.get(id=id)

            if ven.status == 1:
                ven.status = 2
                ven.save()

            else:
                ven.status = 1
                ven.save()
            

           

            



           
    
            return Response({
                "status": {"code": status.HTTP_201_CREATED, "response": "success"},
                "error": None,
                "message": "Quote accepted successfully"
            })
        except KeyError as e:
            return Response({
                "status": {"code": status.HTTP_400_BAD_REQUEST, "response": "failed"},
                "error": True,
                "message": f"Missing required field: {e}"
            })


