from datetime import timezone
from django.db.models import Q, Sum
from payrollservice.data.response.empmonthpaydeductionresponse import Employeemonthlypay_deductionsResponse
from payrollservice.models import Employeemonthlypay_deductions
from payrollservice.service.auditservice import AudtiService
from payrollservice.service.payrollmastersservice import PayrollComponentService, EmployeePFService
from payrollservice.util.payrollutil import Activestatus, Advancetype, ModifyStatus, payrolldeduction_val, \
    is_advance_data
from utilityservice.data.response.nwisefinerror import NWisefinError
from utilityservice.data.response.nwisefinerrorconstants import ErrorMessage, ErrorDescription
from utilityservice.data.response.nwisefinlist import NWisefinList
from utilityservice.data.response.nwisefinpaginator import NWisefinPaginator
from utilityservice.data.response.nwisefinsuccess import NWisefinSuccess, SuccessStatus, SuccessMessage
from utilityservice.service.applicationconstants import ApplicationNamespace
from utilityservice.service.payroll_api_service import Payrollcommon_Apicall
from utilityservice.service.threadlocal import NWisefinThread
from django.utils import timezone

class Employeemonthlypay_deductionsService(NWisefinThread):
    def __init__(self, scope):
        super().__init__(scope)
        self._set_namespace(ApplicationNamespace.PAYROLL_SERVICE)


    def create_employeemonth_deduct(self,deduct_obj,user_id, employee_id):
        success_obj = NWisefinSuccess()
        success_obj.set_status(SuccessStatus.SUCCESS)
        if deduct_obj.get_id() is not None:
            deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(id=deduct_obj.get_id()).update(
                                                                                                            employee_id=employee_id,
                                                                                                            paycomponent_id=deduct_obj.get_paycomponent_id(),
                                                                                                            type=deduct_obj.get_type(),
                                                                                                            from_date=deduct_obj.get_from_date(),
                                                                                                            to_date= deduct_obj.get_to_date(),
                                                                                                            deduct_date=deduct_obj.get_deduct_date(),
                                                                                                            updated_by= user_id,
                                                                                                            updated_date=timezone.now(),
                                                                                                            entity_id=self._entity_id())
            deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).get(id=deduct_obj.get_id())
            audit_insert_data = AudtiService(self._scope()).audit_function(deduct_data, deduct_data.id,
                                                                           deduct_data.employee_id,
                                                                           Advancetype.employeemonthlypay_deduction,
                                                                           ModifyStatus.UPDATE)
            success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
        else:
            deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).create(employee_id=employee_id,
                                                                                                        paycomponent_id=deduct_obj.get_paycomponent_id(),
                                                                                                        type=deduct_obj.get_type(),
                                                                                                        from_date=deduct_obj.get_from_date(),
                                                                                                        to_date=deduct_obj.get_to_date(),
                                                                                                        deduct_date=deduct_obj.get_deduct_date(),
                                                                                                        created_by=user_id,
                                                                                                        entity_id=self._entity_id())
            audit_insert_data = AudtiService(self._scope()).audit_function(deduct_data, deduct_data.id,
                                                                           deduct_data.employee_id,
                                                                           Advancetype.employeemonthlypay_deduction,
                                                                           ModifyStatus.CREATE)

            success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
        return success_obj



    def get_employeemonth(self, employee_id):
        obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(status=Activestatus.active, employee_id=employee_id)
        return obj


    def employeemonthpay_deduct(self, emp_id, month, year):
        condition = Q(entity_id=self._entity_id(), status=Activestatus.active, employee_id=emp_id, deduct_date__month=month, deduct_date__year=year)
        emp_deduct = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(condition)
        employeepay_list = []
        paycomponent = [i.paycomponent_id for i in emp_deduct]
        amount = [i.amount for i in emp_deduct]
        # pay_com_obj = PayrollComponentService(self._scope()).get_multiple_payroll_component(paycomponent)
        # pay_com_obj = PayrollComponentService(self._scope()).get_payrollcomponent_details(paycomponent)
        # pay_com_obj = EmployeePFService(self._scope()).get_multiple_emp_pf(paycomponent)
        # employee_arr = [i.employee_id for i in emp_deduct]
        for empmonth in emp_deduct:
            resp = Employeemonthlypay_deductionsResponse()
            resp.set_id(empmonth.id)
            resp.set_type(empmonth.type)
            resp.set_from_date(empmonth.from_date)
            resp.set_to_date(empmonth.to_date)
            resp.set_amount(empmonth.amount)
            resp.sum_amount = str(sum(amount))
            resp.set_deduct_date(empmonth.deduct_date)
            if empmonth.deduction_status == 1 and empmonth.is_advance == 0:
                # pay_com_obj = Payrollcommon_Apicall(self._scope()).get_payroll_component(paycomponent)
                pay_com_obj = PayrollComponentService(self._scope()).get_multiple_payroll_component_val(paycomponent)
                resp.set_paycomponent_val(empmonth.paycomponent_id, pay_com_obj)
            elif empmonth.deduction_status == -1 and empmonth.is_advance == 0:
                # pay_com_obj = Payrollcommon_Apicall(self._scope()).get_multiple_emp_pf_struct(paycomponent)
                pay_com_obj = EmployeePFService(self._scope()).get_multiple_emp_pf(paycomponent)
                resp.set_paycomponent_val(empmonth.paycomponent_id, pay_com_obj)
            elif empmonth.deduction_status == 1 and empmonth.is_advance == 1: #advance
                resp.paycomponent = is_advance_data.data
            resp.set_deduction_status(empmonth.deduction_status)
            employeepay_list.append(resp)
        return employeepay_list

    def fetch_employeemonth_deduct(self, id):
        deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(status=Activestatus.active,id=id).first()
        if not deduct_data:
            error_obj = NWisefinError()
            error_obj.set_code(ErrorMessage.UNEXPECTED_ERROR)
            error_obj.set_description(ErrorMessage.INVALID_DATA)
            return error_obj
        # pay_com_obj = PayrollComponentService(self._scope()).get_multiple_payroll_component([deduct_data.paycomponent_id])
        # pay_com_obj = EmployeePFService(self._scope()).get_multiple_emp_pf([deduct_data.paycomponent_id])
        # pay_com_obj = Payrollcommon_Apicall(self._scope()).get_multiple_emp_pf_struct([deduct_data.paycomponent_id])
        pay_com_obj = EmployeePFService(self._scope()).get_multiple_emp_pf([deduct_data.paycomponent_id])
        resp = Employeemonthlypay_deductionsResponse()
        resp.set_id(deduct_data.id)
        resp.set_type(deduct_data.type)
        resp.set_from_date(deduct_data.from_date)
        resp.set_to_date(deduct_data.to_date)
        resp.set_amount(deduct_data.amount)
        resp.set_deduct_date(deduct_data.deduct_date)
        resp.set_paycomponent_val(deduct_data.paycomponent_id, pay_com_obj)
        apifunction = Payrollcommon_Apicall(self._scope())
        emp_data = apifunction.emp_details_payroll(deduct_data.employee_id)
        # emp_data = self.employee_details(deduct_data.employee_id)
        resp.employee = emp_data
        return resp


    def inactive_employeemonth_deduct(self, id, user_id):
        deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(id=id).update(status=Activestatus.inactive, updated_by=user_id,updated_date=timezone.now())
        if deduct_data > 0:
            success_obj = NWisefinSuccess()
            success_obj.set_status(SuccessStatus.SUCCESS)
            success_obj.set_message(SuccessMessage.DELETE_MESSAGE)
        else:
            success_obj = NWisefinError()
            success_obj.set_code(ErrorMessage.UNEXPECTED_ERROR)
            success_obj.set_description(ErrorDescription.INVALID_DATA)
        return success_obj


    def emppaystruct_deduct(self, id):
        condition = Q(entity_id=self._entity_id(), status=Activestatus.active) & Q(paydetail_id=id, paydetail_id__is_deduction=True)
        emp_deduct = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(condition)
        resp_arr = []
        for empmonth in emp_deduct:
            resp = Employeemonthlypay_deductionsResponse()
            resp.set_id(empmonth.id)
            resp.set_type(empmonth.type)
            resp.set_from_date(empmonth.from_date)
            resp.set_to_date(empmonth.to_date)
            resp.set_deduction_status(empmonth.deduction_status)
            resp_arr.append(resp)
        return resp_arr


    def excel_uplode(self,df_values):
        for index, row in df_values.iterrows():
            # paycomponent_data = PayrollComponentService(self._scope()).get_payrollcomponent_val(row.PAYCOMPONENT)
            apifunction = Payrollcommon_Apicall(self._scope())
            employee_id = apifunction.emp_code(row.EMPLOYEE_CODE)
            # paycomponent_data = Payrollcommon_Apicall(self._scope()).get_component_val(row.PAYCOMPONENT)
            paycomponent_data = PayrollComponentService(self._scope()).get_payroll_component(row.PAYCOMPONENT)
            # employee_id = Employee.objects.using(self._current_app_schema()).get(code=row.EMPLOYEE_CODE)
            deducation_status = payrolldeduction_val(row.DEDUCTION_STATUS)
            type = payrolldeduction_val(row.TYPE)
            obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).create(employee_id=employee_id.get('id'),
                                                                                                 paycomponent_id=paycomponent_data,
                                                                                                 type=type['id'],
                                                                                                 deduction_status=deducation_status['id'], amount=row.AMOUNT, created_by=1, from_date=row.FROM_DATE, to_date=row.TO_DATE)
        success_obj = NWisefinSuccess()
        success_obj.set_status(SuccessStatus.SUCCESS)
        return success_obj


    def deduction_summary(self,vys_page):
        obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(status=Activestatus.active)[vys_page.get_offset():vys_page.get_query_limit()]
        employee_data =[i.employee_id for i in obj]
        apifunction = Payrollcommon_Apicall(self._scope())
        emp_name = apifunction.employee_detail_arr(employee_data)
        paycomponent = [i.paycomponent_id for i in obj]
        # pay_com_obj = PayrollComponentService(self._scope()).get_payrollcomponent_details(paycomponent)
        # pay_com_obj = Payrollcommon_Apicall(self._scope()).get_multiple_emp_pf_struct(paycomponent)
        pay_com_obj = EmployeePFService(self._scope()).get_multiple_emp_pf(paycomponent)
        list_data = NWisefinList()
        for i in obj:
            data_resp = Employeemonthlypay_deductionsResponse()
            data_resp.set_id(i.id)
            data_resp.set_employee_val(i.employee_id,emp_name)
            data_resp.set_type(i.type)
            data_resp.set_amount(i.amount)
            data_resp.set_deduction_status(i.deduction_status)
            data_resp.set_from_date(i.from_date)
            data_resp.set_to_date(i.to_date)
            data_resp.set_paycomponent_val(i.paycomponent_id,pay_com_obj)
            list_data.append(data_resp)
        vpage = NWisefinPaginator(obj, vys_page.get_index(), 10)
        list_data.set_pagination(vpage)
        return list_data


    def employee_dedution_info(self, emp_id_arr,arr,year):
        condition = Q(deduct_date__month__in=arr, deduct_date__year=year) #| Q(to_date__month__in=arr, to_date__year=year)
        obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(condition, employee_id__in=emp_id_arr, status=Activestatus.active).values('employee_id', 'deduct_date__month','deduct_date__year','deduct_date').annotate(deduction_amout=Sum('amount'))
        #     'deduction_amount'].sum()
        # values('amount','from_date','to_date','employee_id')
        return obj

    def employee_dedution_info1(self, emp_id_arr,arr,year):
        condition = Q(deduct_date__month__in=arr, deduct_date__year=year) & Q(Q(is_advance=1) | Q(deduction_status=1)) #| Q(to_date__month__in=arr, to_date__year=year)
        obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(condition, employee_id__in=emp_id_arr, status=Activestatus.active).values('employee_id', 'deduct_date__month','deduct_date__year','deduct_date').annotate(deduction_amout=Sum('amount'))
        return obj

    def employee_dedution_data1(self, emp_id_arr,month,year):
        condition=Q(deduct_date__month__in=month,deduct_date__year=year)#|Q(to_date__month=month,to_date__year=year)
        obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(condition,employee_id__in=emp_id_arr,status=Activestatus.active).values('employee_id','from_date','to_date','paycomponent_id','amount','type','deduction_status','deduct_date','is_advance')
            # values('amount','from_date','to_date','employee_id')
        return obj

    def employee_dedution_data(self, emp_id_arr,month,year):
        condition=Q(deduct_date__month=month,deduct_date__year=year)#|Q(to_date__month=month,to_date__year=year)
        obj = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(condition,employee_id__in=emp_id_arr,status=Activestatus.active).values('employee_id','from_date','to_date','paycomponent_id','amount','type','deduction_status','deduct_date','is_advance')
            # values('amount','from_date','to_date','employee_id')
        return obj


    def advance_deduct_data(self, employee,from_date):
        advance_deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=employee, deduct_date__month=from_date.month).aggregate(Sum('amount'))
        return advance_deduct_data
