from datetime import timezone

import pandas as pd
from django.utils import timezone
from django.db.models import Q
from payrollservice.data.response.empadditionalallowanceresponse import Employeeadditional_allowanceResponse
from payrollservice.models import Employeeadditional_allowance, Employeemonthly_payinfo, Employeemonthlypay_details, \
    Employeemonthlypay_deductions
from payrollservice.service.auditservice import AudtiService
from payrollservice.service.payrollmastermappingservice import PayrollmastermappingService
from payrollservice.service.payrollmastersservice import ComponentTypeService
from payrollservice.util.payrollutil import Activestatus, Advancetype, ModifyStatus
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, SuccessMessage, SuccessStatus
from utilityservice.service.applicationconstants import ApplicationNamespace
from utilityservice.service.payroll_api_service import Payrollcommon_Apicall
from utilityservice.service.threadlocal import NWisefinThread


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

    def employeeadditional_allowance_create(self, data_obj, user_id):
        from datetime import datetime
        success_obj = NWisefinSuccess()
        if not data_obj.get_id() is None:
            obj = Employeeadditional_allowance.objects.using(self._current_app_schema()).filter(id=data_obj.get_id()).update(employee_id=data_obj.get_employee_id(),
                                                                                                                       type=data_obj.get_type(),
                                                                                                                       active_date=data_obj.get_active_date(),
                                                                                                                       end_date=data_obj.get_end_date(),
                                                                                                                       amount=data_obj.get_amount(),
                                                                                                                       custom_deduct=data_obj.get_custom_deduct(),
                                                                                                                       updated_date=timezone.now(),
                                                                                                                       updated_by=user_id)
            obj = Employeeadditional_allowance.objects.using(self._current_app_schema()).get(id=data_obj.get_id())

            # currentMonth = datetime.now().month
            # currentYear = datetime.now().year
            # date = datetime.today().strftime("%Y-%m")
            # current_month_year = datetime.now()
            # from_date = datetime.strptime(str(obj.active_date), "%Y-%m-%d")
            # from_datem = from_date.strftime("%Y-%m")
            # to_date = datetime.strptime(str(obj.end_date), "%Y-%m-%d")
            # to_datem = to_date.strftime("%Y-%m")
            # if from_datem <= date <= to_datem:
            #     if obj.custom_deduct == False:
            #         month_details = Employeemonthly_payinfo.objects.using(self._current_app_schema()).filter(status=Activestatus.active, employee_id=obj.employee_id, payroll_date__month=currentMonth, payroll_date__year=currentYear)
            #         if month_details.count() > 0:
            #             details = Employeemonthlypay_details.objects.using(self._current_app_schema()).filter(status=Activestatus.active,empmonthly_pay_id=month_details[0].id, paycomponent=obj.type, from_date=obj.active_date,to_date=obj.end_date, amount=obj.amount)
            #             if details.count() == 0:
            #                 emp_details = Employeemonthlypay_details.objects.using(self._current_app_schema()).update(
            #                     empmonthly_pay_id=month_details[0].id,
            #                     paycomponent=obj.type,
            #                     from_date=obj.active_date,
            #                     to_date=obj.end_date,
            #                     updated_date=timezone.now(),
            #                     updated_by=user_id,
            #                     entity_id=self._entity_id(),
            #                     amount=obj.amount)
            #     else:
            #         month_details = Employeemonthly_payinfo.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=obj.employee_id, payroll_date__month=currentMonth, payroll_date__year=currentYear)
            #         if month_details.count() > 0:
            #             deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).update(
            #                 employee_id=obj.employee_id,
            #                 paycomponent_id=obj.type,
            #                 from_date=obj.active_date,
            #                 deduction_status=1,
            #                 to_date=obj.end_date,
            #                 amount=obj.amount,
            #                 updated_date=timezone.now(),
            #                 updated_by=user_id,
            #                 entity_id=self._entity_id())
            audit_insert_data = AudtiService(self._scope()).audit_function(obj, obj.id, obj.employee_id,
                                                                           Advancetype.employeeadditional_allowance,
                                                                           ModifyStatus.UPDATE)
            success_obj.set_message(SuccessMessage.UPDATE_MESSAGE)
        else:
            obj = Employeeadditional_allowance.objects.using(self._current_app_schema()).create(employee_id=data_obj.get_employee_id(),
                                                                                                type=data_obj.get_type(),
                                                                                                active_date=data_obj.get_active_date(),
                                                                                                end_date=data_obj.get_end_date(),
                                                                                                amount=data_obj.get_amount(),
                                                                                                custom_deduct=data_obj.get_custom_deduct(),
                                                                                                created_by=user_id)
            audit_insert_data = AudtiService(self._scope()).audit_function(obj, obj.id, obj.employee_id,
                                                                           Advancetype.employeeadditional_allowance,
                                                                           ModifyStatus.CREATE)

            currentMonth = datetime.now().month
            currentYear = datetime.now().year
            date = datetime.today().strftime("%Y-%m")
            current_month_year = datetime.now()
            from_date = datetime.strptime(str(obj.active_date), "%Y-%m-%d")
            from_datem = from_date.strftime("%Y-%m")
            to_date = datetime.strptime(str(obj.end_date), "%Y-%m-%d")
            to_datem = to_date.strftime("%Y-%m")
            # payroll_mastermap = Payrollcommon_Apicall(self._scope()).get_segment_based_paycom(obj.type)
            payroll_mastermap = PayrollmastermappingService(self._scope()).get_segment_based_paycom(obj.type)
            if payroll_mastermap == []:
                payroll_mastermap = None
            else:
                payroll_mastermap = payroll_mastermap[0]['segment']
            if from_datem <= date <= to_datem:
                if obj.custom_deduct == False:
                    month_details = Employeemonthly_payinfo.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=obj.employee_id, payroll_date__month=currentMonth, payroll_date__year=currentYear)
                    if month_details.count() > 0:
                        details = Employeemonthlypay_details.objects.using(self._current_app_schema()).filter(status=Activestatus.active,empmonthly_pay_id=month_details[0].id, paycomponent=obj.type, from_date=obj.active_date,to_date=obj.end_date, amount=obj.amount)
                        if details.count() == 0:
                            emp_details = Employeemonthlypay_details.objects.using(self._current_app_schema()).create(
                                empmonthly_pay_id=month_details[0].id,
                                paycomponent=obj.type,
                                from_date=obj.active_date,
                                to_date=obj.end_date,
                                segment=payroll_mastermap,
                                created_by=user_id,
                                entity_id=self._entity_id(),
                                amount=obj.amount)
                else:
                    month_details = Employeemonthly_payinfo.objects.using(self._current_app_schema()).filter(status=Activestatus.active,employee_id=obj.employee_id, payroll_date__month=currentMonth, payroll_date__year=currentYear)
                    if month_details.count() > 0:
                        deduct_data = Employeemonthlypay_deductions.objects.using(self._current_app_schema()).create(
                                                                                            employee_id=obj.employee_id,
                                                                                            paycomponent_id=obj.type,
                                                                                            from_date=obj.active_date,
                                                                                            deduction_status=1,
                                                                                            to_date=obj.end_date,
                                                                                            created_by=user_id,
                                                                                            amount=obj.amount,
                                                                                            entity_id=self._entity_id())

            success_obj.set_message(SuccessMessage.CREATE_MESSAGE)
        return success_obj


    def employeeadditional_allowance_summary(self,request, vys_page):
        condition=Q(status=Activestatus.active)
        employee_id = request.GET.get('employee_id')
        active_date = request.GET.get('active_date')
        end_date = request.GET.get('end_date')
        custom_deduct = request.GET.get('custom_deduct')
        if employee_id != None and employee_id != "":
            condition &= Q(employee_id=employee_id)
        if active_date != None and active_date != "":
            condition &= Q(active_date=active_date)
        if end_date != None and end_date != "":
            condition &= Q(end_date=end_date)
        if custom_deduct == 'True':
            addition_data = Employeeadditional_allowance.objects.using(self._current_app_schema()).filter(condition, custom_deduct=1)[vys_page.get_offset():vys_page.get_query_limit()]
        else:
            addition_data = Employeeadditional_allowance.objects.using(self._current_app_schema()).filter(condition,custom_deduct=0)[vys_page.get_offset():vys_page.get_query_limit()]
        emp_addition_list = NWisefinList()
        if addition_data.count() > 0:
            for i in addition_data:
                data_obj = Employeeadditional_allowanceResponse()
                data_obj.set_id(i.id)
                data_obj.set_active_date(i.active_date)
                data_obj.set_end_date(i.end_date)
                data_obj.set_amount(i.amount)
                data_obj.set_type(i.type)
                data_obj.set_custom_deduct(i.custom_deduct)
                apifunction = Payrollcommon_Apicall(self._scope())
                obj = apifunction.emp_info(i.employee_id)
                data_obj.Employee_info = {"Employeename":obj.get('full_name'), "Employeecode":obj.get('code'), "Employee_id":obj.get('id'), "Employeegrade":obj.get(grade)}
                emp_addition_list.append(data_obj)
            vpage = NWisefinPaginator(addition_data, vys_page.get_index(), 10)
            emp_addition_list.set_pagination(vpage)
            return emp_addition_list
        else:
            vpage = NWisefinPaginator([], vys_page.get_index(), 11)
            emp_addition_list.pagination = vpage
            return emp_addition_list


    def employeeadditional_allowance_get(self, id):
        addition_data = Employeeadditional_allowance.objects.using(self._current_app_schema()).filter(id=id,status=Activestatus.active)
        if addition_data.count() > 0:
            data_obj = Employeeadditional_allowanceResponse()
            data_obj.set_id(addition_data[0].id)
            data_obj.set_type(addition_data[0].type)
            data_obj.set_active_date(addition_data[0].active_date)
            data_obj.set_end_date(addition_data[0].end_date)
            data_obj.set_amount(addition_data[0].amount)
            data_obj.set_custom_deduct(addition_data[0].custom_deduct)
            apifunction = Payrollcommon_Apicall(self._scope())
            obj = apifunction.emp_info(addition_data[0].employee_id)
            data_obj.Employee_info = {"Employeename": obj.get('full_name'), "Employeecode": obj.get('code'), "Employee_id": obj.get('id'), "Employeegrade": obj.get('grade')}
            return data_obj
        else:
            data = NWisefinList()
            return data


    def employeeadditional_allowance_inactive(self, id):
        obj = Employeeadditional_allowance.objects.using(self._current_app_schema()).filter(id=id).update(status=Activestatus.inactive)
        if obj == 0:
            error_obj = NWisefinError()
            error_obj.set_code(ErrorMessage.INVALID_ID)
            error_obj.set_description(ErrorDescription.INVALID)
            return error_obj
        else:
            success_obj = NWisefinSuccess()
            success_obj.set_status(SuccessStatus.SUCCESS)
            success_obj.set_message(SuccessMessage.DELETE_MESSAGE)
            return success_obj

    def custom_deduct_upload(self,custom_df, user_id):
        try:
            error = []
            success_obj = NWisefinSuccess()
            custom_df["Active_Date"] = pd.to_datetime(custom_df["Active_Date"]).dt.strftime('%Y-%m-%d')
            custom_df["End_Date"] = pd.to_datetime(custom_df["End_Date"]).dt.strftime('%Y-%m-%d')
            excel = ['Employee_Code','Active_Date','End_Date','Amount','COMPONENT_TYPE']
            excel_df = pd.DataFrame(columns=excel)
            customdf = pd.DataFrame(columns=custom_df.columns)
            columns_diff = excel_df.equals(customdf)
            if columns_diff is False:
                error.append({"ErrorMessage":"INVALID COLUMN NAMES"})
            else:
                for index, row in custom_df.iterrows():
                    try:
                        employee_id = Payrollcommon_Apicall(self._scope()).emp_code(row['Employee_Code'])
                        type = ComponentTypeService(self._scope()).get_componenttype_name1(row['COMPONENT_TYPE'])
                        custom_obj = Employeeadditional_allowance.objects.using(self._current_app_schema()).create(employee_id=employee_id.get('id'),
                                                                                                                    # type=data_obj.get_type(),
                                                                                                                    active_date=row['Active_Date'],
                                                                                                                    end_date=row['End_Date'],
                                                                                                                    amount=row['Amount'],
                                                                                                                    custom_deduct=1,
                                                                                                                    created_by=user_id)


                    except Exception as excep:
                        error.append({"employee_code":row['Employee_Code'],"ErrorMessage":str(excep)})
                        print('error_message', row['Employee_Code'])
                        continue
            if len(error) > 0:
                msg = error
            else:
                msg = {"SuccessMessage":"DATA INSERTED SUCCESSFULLY"}
            success_obj.set_status(SuccessStatus.SUCCESS)
            success_obj.set_message(msg)
            return success_obj
        except Exception as excep:
            obj = NWisefinError()
            obj.set_code(ErrorMessage.INVALID_DATA)
            obj.set_description(str(excep))
            return obj