from npayroll.settings import logger
from payrollservice.data.response.emppaystructureresponse import EmployeePaystructureResponse
from payrollservice.service.auditservice import AudtiService
from payrollservice.service.emppaystructuredetailsservice import EmployeePaystructure_detailsService
from payrollservice.service.payrollmastersservice import EmployeePFService, payrollGradeService
from payrollservice.service.payrolltemplateservice import PayrollTemplateService
from utilityservice.service.payroll_api_service import Payrollcommon_Apicall
from utilityservice.service.threadlocal import NWisefinThread
from utilityservice.service.applicationconstants import ApplicationNamespace
from payrollservice.models.payrollmodels import EmployeePaystructure
from django.utils import timezone
from utilityservice.data.response.nwisefinlist import NWisefinList
from utilityservice.data.response.nwisefinsuccess import NWisefinSuccess, SuccessMessage, SuccessStatus
from utilityservice.data.response.nwisefinpaginator import NWisefinPaginator
from utilityservice.data.response.nwisefinerror import NWisefinError
from utilityservice.data.response.nwisefinerrorconstants import ErrorDescription, ErrorMessage
from django.db.models import Q
from payrollservice.util.payrollutil import Activestatus, Advancetype, ModifyStatus, PF_Type, get_pf_type


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


    def create_employeepay_struct(self, request, data_obj, user_id):
        success_obj = NWisefinSuccess()
        success_obj.set_status(SuccessStatus.SUCCESS)
        if data_obj.get_id() is not None:
            emp_pay = EmployeePaystructure.objects.using(self._current_app_schema()).filter(id=data_obj.get_id()).update(
                                                                                            employee_id=data_obj.get_employee_id(),
                                                                                            standard_ctc=data_obj.get_standard_ctc(),
                                                                                            pf_type=data_obj.get_pf_type(),
                                                                                            is_tds=data_obj.get_is_tds(),
                                                                                            gross_pay=data_obj.get_gross_pay(),
                                                                                            updated_by=user_id,
                                                                                            take_home=data_obj.get_take_home(),
                                                                                            updated_date=timezone.now(),
                                                                                            entity_id=self._entity_id(),
                                                                                            emp_grade=data_obj.get_emp_template())
            emp_pay = EmployeePaystructure.objects.using(self._current_app_schema()).get(id=data_obj.get_id())
            audit_insert_data = AudtiService(self._scope()).audit_function(emp_pay, emp_pay.id, emp_pay.employee_id,
                                                                           Advancetype.paystructure,
                                                                           ModifyStatus.UPDATE)
            success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
            # success_obj.gross_pay = str(emp_pay.gross_pay)
            # success_obj.id=emp_pay.id
            # success_obj.standard_ctc = round(emp_pay.standard_ctc)
            # return success_obj

        else:
            var = EmployeePaystructure.objects.using(self._current_app_schema()).filter(employee_id=data_obj.get_employee_id(), status=Activestatus.active).values_list('employee_id', flat=True)
            arr1 = list(set(var))
            if len(arr1) > 0:
                success_obj = NWisefinSuccess()
                success_obj.set_status("INVALID EMPLOYEE CODE")
                success_obj.set_message("ALREADY EXISTS IN EMPLOYEE CODE")
                return success_obj
            else:
                emp_pay = EmployeePaystructure.objects.using(self._current_app_schema()).create(employee_id=data_obj.get_employee_id(),
                                                       standard_ctc=data_obj.get_standard_ctc(),
                                                       pf_type=data_obj.get_pf_type(),
                                                       is_tds=data_obj.get_is_tds(),
                                                       gross_pay=data_obj.get_gross_pay(),
                                                       take_home=data_obj.get_take_home(),
                                                       created_by=user_id,
                                                       entity_id=self._entity_id(),
                                                       emp_grade=data_obj.get_emp_template())
                audit_insert_data = AudtiService(self._scope()).audit_function(emp_pay, emp_pay.id, emp_pay.employee_id,
                                                                               Advancetype.paystructure,
                                                                               ModifyStatus.CREATE)

                success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
        success_obj.id=emp_pay.id
        success_obj.standard_ctc=str(emp_pay.standard_ctc)
        success_obj.gross_pay = str(emp_pay.gross_pay)
        return success_obj



    def create_emp_payroll(self, data_obj, user_id, emp_id):
        try:
            resp = NWisefinSuccess()
            if data_obj.get_id() is not None:
                EmployeePaystructure.objects.using(
                    self._current_app_schema()).filter(
                    id=data_obj.get_id()).update(employee_id=emp_id,
                                                 standard_ctc=data_obj.get_standard_ctc(),
                                                 disability=data_obj.get_disability(),
                                                 pf_type=data_obj.get_pf_type(),
                                                 take_home=data_obj.get_take_home(),
                                                 # percentage=data_obj.get_pf_percentage(),
                                                 updated_by=user_id,
                                                 updated_date=timezone.now(),is_tds=data_obj.get_is_tds(),emp_grade=data_obj.get_emp_template())
                message = SuccessMessage.UPDATE_MESSAGE
            else:
                emp_pay = EmployeePaystructure.objects.using(
                    self._current_app_schema()).create(employee_id=emp_id,
                                                       standard_ctc=data_obj.get_standard_ctc(),
                                                       disability=data_obj.get_disability(),
                                                       pf_type=data_obj.get_pf_type(),
                                                       take_home=data_obj.get_take_home(),
                                                       created_by=user_id,
                                                       entity_id=self._entity_id(),is_tds=data_obj.get_is_tds(),emp_grade=data_obj.get_emp_template())
                EmployeePaystructure_detailsService(self._scope()).create_emp_default_allowance(emp_pay.id, data_obj.get_standard_ctc(), user_id)
                message = SuccessMessage.CREATE_MESSAGE
            resp.set_status(SuccessStatus.SUCCESS)
            resp.set_message(message)
            return resp
        except:
            error = NWisefinError()
            error.set_code(ErrorMessage.UNEXPECTED_ERROR)
            error.set_description(ErrorDescription.UNEXPECTED_ERROR)
            return error

    def employeepay_summary(self, vys_page):
        condition=Q(entity_id=self._entity_id(),status=Activestatus.active)
        employeepay_details = EmployeePaystructure.objects.using(self._current_app_schema()).filter(condition)[vys_page.get_offset():vys_page.get_query_limit()]
        employeepay_obj_data = NWisefinList()
        for emppay in employeepay_details:
            resp = EmployeePaystructureResponse()
            resp.set_id(emppay.id)
            resp.set_employee_id(emppay.employee_id)
            resp.set_pf_type(emppay.pf_type)
            resp.set_is_tds(emppay.is_tds)
            resp.set_standard_ctc(emppay.standard_ctc)
            resp.set_gross_pay(emppay.gross_pay)
            resp.set_take_home(emppay.take_home)
            employeepay_obj_data.append(resp)
            vpage = NWisefinPaginator(employeepay_details, vys_page.get_index(), 10)
            employeepay_obj_data.set_pagination(vpage)
        return employeepay_obj_data


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

    def employee_paystrct_inactive(self, struct_id, user_id):
        obj = EmployeePaystructure.objects.using(self._current_app_schema()).filter(id=struct_id).update(status=Activestatus.inactive, updated_by=user_id,updated_date=timezone.now())
        if obj > 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 employee_pay_get(self, pay_id):
        obj = EmployeePaystructure.objects.using(self._current_app_schema()).get(id=pay_id,status=Activestatus.active)
        data_resp = EmployeePaystructureResponse()
        data_resp.set_id(obj.id)
        # data_resp.set_standard_ctc(obj.standard_ctc)
        # data_resp.set_standard_yearly_ctc(obj.standard_ctc)
        # employee_pay_obj = Payrollcommon_Apicall(self._scope()).get_emp_pf_info(obj.pf_type)
        employee_pay_obj = EmployeePFService(self._scope()).get_emp_pf_info(obj.pf_type)
        # employee_pay_obj = EmployeePFService(self._scope()).get_emp_pf_info(obj.pf_type)
        data_resp.set_pf_type(employee_pay_obj)
        data_resp.set_is_tds(obj.is_tds)
        data_resp.set_gross_pay(obj.gross_pay)
        data_resp.set_yearly_gross_pay(obj.gross_pay)
        # data_resp.set_take_home(obj.take_home)
        # data_resp.set_take_home_yearly(obj.take_home)
        return data_resp



    def paystructure_excel_upload(self,struct_data, user_id):
        success_obj = NWisefinSuccess()
        success_obj.set_status(SuccessStatus.SUCCESS)
        # pf_type = Payrollcommon_Apicall(self._scope()).get_pf_type(struct_data['PF_TYPE'])
        pf_type = EmployeePFService(self._scope()).get_pf_type(struct_data['PF_TYPE'])
        employee_id = Payrollcommon_Apicall(self._scope()).emp_code(struct_data['EMPLOYEE_CODE'])
        var = EmployeePaystructure.objects.using(self._current_app_schema()).filter(employee_id=employee_id.get('id'), status=Activestatus.active).values_list('employee_id', flat=True)
        arr1 = list(set(var))
        if len(arr1) > 0:
            success_obj = NWisefinSuccess()
            success_obj.set_status("INVALID DATA")
            success_obj.set_message("TRY AGAIN VALID DATA")
            return success_obj
        else:
            obj = EmployeePaystructure.objects.using(self._current_app_schema()).create(employee_id=employee_id.get('id'),
                                                                                        gross_pay=struct_data['GROSS_PAY'],
                                                                                        pf_type=pf_type,
                                                                                        created_by=user_id)

            success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
            success_obj.id = obj.id
            success_obj.gross_pay = str(obj.gross_pay)
            return success_obj


    def advance_gross_pay(self, employee):
        month_data =EmployeePaystructure.objects.using(self._current_app_schema()).filter(status=Activestatus.active, employee_id=employee).values('gross_pay','take_home').first()
        return month_data


    def  create_employeepay_struct1(self, request, data_obj, user_id):
        success_obj = NWisefinSuccess()
        success_obj.set_status(SuccessStatus.SUCCESS)
        if data_obj.get_is_esi() is None:
            is_esi_val = True
        else:
            is_esi_val = data_obj.get_is_esi()
        if data_obj.get_id() is not None:
            emp_pay = EmployeePaystructure.objects.using(self._current_app_schema()).filter(id=data_obj.get_id()).update(
                                                                                            employee_id=data_obj.get_employee_id(),
                                                                                            standard_ctc=data_obj.get_standard_ctc(),
                                                                                            pf_type=data_obj.get_pf_type(),
                                                                                            is_tds=data_obj.get_is_tds(),
                                                                                            gross_pay=data_obj.get_gross_pay(),
                                                                                            updated_by=user_id,
                                                                                            take_home=data_obj.get_take_home(),
                                                                                            updated_date=timezone.now(),
                                                                                            entity_id=self._entity_id(),
                                                                                            is_esi=is_esi_val,
                                                                                            emp_grade=data_obj.get_emp_template(),
                                                                                            from_date=data_obj.get_from_date(),
                                                                                            to_date=data_obj.get_to_date())
            emp_pay = EmployeePaystructure.objects.using(self._current_app_schema()).get(id=data_obj.get_id())
            audit_insert_data = AudtiService(self._scope()).audit_function(emp_pay, emp_pay.id, emp_pay.employee_id,
                                                                           Advancetype.paystructure,
                                                                           ModifyStatus.UPDATE)
            success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
            # success_obj.gross_pay = str(emp_pay.gross_pay)
            # success_obj.id=emp_pay.id
            # success_obj.standard_ctc = round(emp_pay.standard_ctc)
            # return success_obj

        else:
            var = EmployeePaystructure.objects.using(self._current_app_schema()).filter(employee_id=data_obj.get_employee_id(), status=Activestatus.active).values_list('employee_id', flat=True)
            arr1 = list(set(var))
            if len(arr1) > 0:
                success_obj = NWisefinSuccess()
                success_obj.set_status("INVALID EMPLOYEE CODE")
                success_obj.set_message("ALREADY EXISTS IN EMPLOYEE CODE")
                return success_obj
            else:
                emp_pay = EmployeePaystructure.objects.using(self._current_app_schema()).create(employee_id=data_obj.get_employee_id(),
                                                       standard_ctc=data_obj.get_standard_ctc(),
                                                       pf_type=data_obj.get_pf_type(),
                                                       is_tds=data_obj.get_is_tds(),
                                                       gross_pay=data_obj.get_gross_pay(),
                                                       take_home=data_obj.get_take_home(),
                                                       created_by=user_id,
                                                       entity_id=self._entity_id(),
                                                       is_esi=is_esi_val,emp_grade=data_obj.get_emp_template(),
                                                       from_date=data_obj.get_from_date(),
                                                       to_date=data_obj.get_to_date())

                audit_insert_data = AudtiService(self._scope()).audit_function(emp_pay, emp_pay.id, emp_pay.employee_id,
                                                                               Advancetype.paystructure,
                                                                               ModifyStatus.CREATE)

                success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
        success_obj.id=emp_pay.id
        success_obj.standard_ctc=str(emp_pay.standard_ctc)
        success_obj.gross_pay = str(emp_pay.gross_pay)
        success_obj.take_home = str(emp_pay.take_home)
        success_obj.employee_id = str(emp_pay.employee_id)
        return success_obj




    def grade_emp_based_structure_get(self, request, employee_id, grade):
        error_obj = NWisefinError()
        condition = Q(entity_id=self._entity_id(), status=Activestatus.active)
        employee = Payrollcommon_Apicall(self._scope()).grade_employee(employee_id, grade)
        if len(employee) > 0:
            pay_struct = EmployeePaystructure.objects.using(self._current_app_schema()).filter(condition, employee_id=employee_id)
            if pay_struct.count() > 0:
                data_resp = EmployeePaystructureResponse()
                data_resp.set_id(pay_struct[0].id)
                data_resp.set_standard_ctc(pay_struct[0].standard_ctc)
                # employee_pay_obj = Payrollcommon_Apicall(self._scope()).get_emp_pf_info(pay_struct[0].pf_type)
                employee_pay_obj = EmployeePFService(self._scope()).get_emp_pf_info(pay_struct[0].pf_type)
                data_resp.set_pf_type(employee_pay_obj)
                data_resp.set_is_tds(pay_struct[0].is_tds)
                data_resp.set_gross_pay(pay_struct[0].gross_pay)
                data_resp.set_take_home(pay_struct[0].take_home)
                return data_resp
            else:
                error_obj.set_description("NO RECORD IN STRUCTURE")
                return error_obj
        else:
            error_obj.set_description("Employee Not Match")
            return error_obj


    def paystructure_excel_upload1(self,struct_data, user_id):
        try:
            logger.info("upload paystruct data" + str(struct_data))
            success_obj = NWisefinSuccess()
            success_obj.set_status(SuccessStatus.SUCCESS)
            pf_type = get_pf_type(struct_data['PF_TYPE'])['id']
            # pf_type = Payrollcommon_Apicall(self._scope()).get_pf_type(struct_data['PF_TYPE'])
            employee_id = Payrollcommon_Apicall(self._scope()).emp_code(struct_data['EMPLOYEE_CODE'])
            # grade = payrollGradeService(self._scope()).get_grade_name(struct_data['GRADE'])
            # grade = Payrollcommon_Apicall(self._scope()).get_grade_name(struct_data['GRADE'])
            template = PayrollTemplateService(self._scope()).get_payrolltemplate_name(struct_data['TEMPLATE'])
            var = EmployeePaystructure.objects.using(self._current_app_schema()).filter(employee_id=employee_id.get('id'), status=Activestatus.active).values_list('employee_id', flat=True)
            arr1 = list(set(var))
            if len(arr1) > 0:
                success_obj = NWisefinSuccess()
                success_obj.set_status("INVALID EMPLOYEE CODE")
                success_obj.set_message("INVALID_DATA")
                success_obj.description = "ALREADY EXISTS IN EMPLOYEE CODE"
                return success_obj
            else:
                obj = EmployeePaystructure.objects.using(self._current_app_schema()).create(employee_id=employee_id.get('id'),
                                                                                            gross_pay=struct_data['GROSS_PAY'],
                                                                                            pf_type=pf_type,
                                                                                            created_by=user_id,
                                                                                            standard_ctc=struct_data['STANDARD_CTC'],
                                                                                            take_home=struct_data['TAKE_HOME'],
                                                                                            is_esi=struct_data['IS_ESI'],
                                                                                            emp_grade=template,
                                                                                            from_date=struct_data['FROM_DATE'],
                                                                                            to_date=struct_data['TO_DATE'])
                success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
                success_obj.id = obj.id
                success_obj.gross_pay = str(obj.gross_pay)
                success_obj.employee_id = str(obj.employee_id)
                success_obj.pf_type = obj.pf_type
                success_obj.is_esi = obj.is_esi
                logger.info("upload paystruct data employee code" + str(struct_data['EMPLOYEE_CODE']))
                return success_obj
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.message = "INVALID_DATA"
            obj.set_description(str(excep))
            return obj

    def emp_details_segment_data(self, employee_id,template_id):
        obj = EmployeePaystructure.objects.using(self._current_app_schema()).filter(employee_id=employee_id,emp_grade=template_id,status=Activestatus.active)
        for i in obj:
            data = {"id": i.id, "standard_ctc": str(i.standard_ctc), "gross_pay": str(i.gross_pay), "take_home": str(i.take_home),
                    "employee_id": i.employee_id}
            return data

    def common_master_data_for_segment(self, grade, template_id):
        # comm_fun_cal = Payrollcommon_Apicall(self._scope()).common_master_data_for_segment(grade)
        comm_fun_cal = PayrollTemplateService(self._scope()).grade_based_segment_data2(grade, template_id)
        return comm_fun_cal

