package nckd.jxccl.hr.hspm.business.application.task;

import kd.bos.common.enums.EnableEnum;
import kd.bos.context.RequestContext;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.exception.KDException;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.schedule.executor.AbstractTask;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import nckd.jxccl.base.common.utils.ConvertUtil;
import nckd.jxccl.hr.hspm.common.application.task.SJDRTaskConstant;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 特殊工种时长刷新作业
 * @author: jtd
 * @date: 2025/11/21 23:23
 */
public class SpecialJobDurationRefreshTask extends AbstractTask {

    private static final Log LOGGER = LogFactory.getLog(SpecialJobDurationRefreshTask.class);

    private enum EntityType {
        EMPPOSORGREL(SJDRTaskConstant.HRPI_EMPPOSORGREL, SJDRTaskConstant.POSITION_KEY),
        SPECIALWORKLOG(SJDRTaskConstant.NCKD_HSPM_SPECWRKLOG_E_ENTITY, SJDRTaskConstant.NCKD_POSITION_KEY);

        private final String entity;
        private final String positionKey;

        EntityType(String entity, String positionKey) {
            this.entity = entity;
            this.positionKey = positionKey;
        }

        public String getEntity() {
            return this.entity;
        }

        public String getPositionKey() {
            return this.positionKey;
        }
    }

    @Override
    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
        // 初始化
        Boolean init = ConvertUtil.toBoolean(map.get("init"), false);
        if (init) {
            // 初始化任职经历处理
            initProcess(EntityType.EMPPOSORGREL);
            // 初始化特殊工种记录处理
            initProcess(EntityType.SPECIALWORKLOG);
        } else {
            // 任职经历处理
            process(EntityType.EMPPOSORGREL);
            // 特殊工种记录处理
            process(EntityType.SPECIALWORKLOG);
        }
    }

    /**
     * 计算时长
     * @param entityType
     * @param dataDy
     * @param lastDyObj
     */
    private void calculateMon(EntityType entityType, DynamicObject dataDy, DynamicObject lastDyObj) {
        // 工种截止时间
        Date workEndDate = dataDy.getDynamicObject(entityType.getPositionKey()).getDate(SJDRTaskConstant.NCKD_WORKENDDATE_KEY);
        // 开始日期
        Date startDate = dataDy.getDate(SJDRTaskConstant.STARTDATE);
        // 结束日期
        Date endDate = dataDy.getDate(SJDRTaskConstant.ENDDATE);
        // 如果结束日期 晚于 工种截止时间 则结束日期取工种截止时间
        if (workEndDate != null && endDate.after(workEndDate)) {
            endDate = workEndDate;
        }
        // 结束日期-1
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(endDate);
        endCalendar.add(Calendar.DATE, -1);
        endDate = endCalendar.getTime();
        // 先计算两个日期的月份差，考虑到跨年的情况，取绝对值
        int month = Math.abs((startDate.getMonth()+1) - (endDate.getMonth()+1));
        // 计算是否满一个月
        int startDay = startDate.getDate();
        int endDay = endDate.getDate();
        // 如果跨月 并且 结束日期小于开始日期 则月-1（不满一个月所以需要减）
        if (month > 0 && endDay < startDay) {
            month -= 1;
        }
        // 设置从事时长
        dataDy.set(SJDRTaskConstant.NCKD_SERVICEMON_KEY, month);
        // 累计从事时长
        BigDecimal totalmon = BigDecimal.ZERO;
        // 如果从事时长大于0
        if (month > 0) {
            // 获取特殊工种年限
            int specwrkyrs = dataDy.getDynamicObject(entityType.getPositionKey()).getDynamicObject(SJDRTaskConstant.NCKD_SPEJOBPROP_KEY).getInt(SJDRTaskConstant.NCKD_SPECWRKYRS_KEY);
            // 累计从事时长=从事时长/特殊工种年限*12，保留两位小数向下取整
            totalmon = new BigDecimal(month).divide(new BigDecimal(specwrkyrs*12), 2, RoundingMode.DOWN);
        }
        // 获取上一条数据的累计从事时长 相加
        if (lastDyObj != null) {
            BigDecimal lastTotalmon = lastDyObj.getBigDecimal(SJDRTaskConstant.NCKD_TOTALMON_KEY);
            totalmon = lastTotalmon.add(totalmon);
        }
        dataDy.set(SJDRTaskConstant.NCKD_TOTALMON_KEY, totalmon);
    }

    /**
     * 获取数据
     * @param entityType
     * @param customFilter
     * @return
     */
    private List<DynamicObject> getDataDys(EntityType entityType, QFilter customFilter) {
        // 员工编码
        String empNumberKey = String.join(".", SJDRTaskConstant.EMPLOYEE_KEY, SJDRTaskConstant.EMP_NUMBER_KEY);
        // 特殊工种性质
        String speJobPropKey = String.join(".", entityType.getPositionKey(), SJDRTaskConstant.NCKD_SPEJOBPROP_KEY);
        // 工种截止时间
        String workEndDateKey = String.join(".", entityType.getPositionKey(), SJDRTaskConstant.NCKD_WORKENDDATE_KEY);
        // 特殊工种年限
        String specwrkyrsKey = String.join(".", speJobPropKey, SJDRTaskConstant.NCKD_SPECWRKYRS_KEY);
        // 查询 开始日期、结束日期、员工编码、工种截止时间、特殊工种年限、从事时间、累计从事时间
        String selectProperties = String.join(",", SJDRTaskConstant.STARTDATE, SJDRTaskConstant.ENDDATE, empNumberKey, workEndDateKey, specwrkyrsKey, SJDRTaskConstant.NCKD_SERVICEMON_KEY, SJDRTaskConstant.NCKD_TOTALMON_KEY);
        // 过滤 特殊工种性质有值
        QFilter qFilter = new QFilter(speJobPropKey, QCP.large_than, 0L);
        // 并且 特殊工种年限>0
        qFilter.and(new QFilter(specwrkyrsKey, QCP.large_than, 0L));
        if (customFilter != null) {
            qFilter.and(customFilter);
        }
        // 排序 员工编码、开始时间、结束时间、特殊工种性质编码
        String orderBy = String.join(",", empNumberKey, SJDRTaskConstant.STARTDATE, SJDRTaskConstant.ENDDATE, String.join(".", entityType.getPositionKey(), SJDRTaskConstant.INDEX_KEY));
        // 获取数据
        DynamicObject[] dataDys = BusinessDataServiceHelper.load(entityType.getEntity(), selectProperties, new QFilter[]{qFilter}, orderBy);
        // 过滤 工种截止时间没有值 或 工种截止时间晚于开始日期
        List<DynamicObject> result = new ArrayList<DynamicObject>();
        for (int i = 0; i < dataDys.length; i++) {
            DynamicObject dataDy = dataDys[i];
            DynamicObject positionDy = dataDy.getDynamicObject(entityType.getPositionKey());
            Date startDate = dataDy.getDate(SJDRTaskConstant.STARTDATE);
            Date workEndDate = positionDy.getDate(SJDRTaskConstant.NCKD_WORKENDDATE_KEY);
            if (workEndDate == null || workEndDate.after(startDate)) {
                result.add(dataDy);
            }
        }
        return result;
    }

    /**
     * 初始化数据处理
     * @param entityType
     */
    private void initProcess(EntityType entityType) {
        // 获取 所有员工的数据
        List<DynamicObject> empPosRgelDys = getDataDys(entityType, null);
        // 分组 员工编码
        Map<String, List<DynamicObject>> dataDyMap = empPosRgelDys.stream().collect(Collectors.groupingBy(dataDy -> dataDy.getDynamicObject(SJDRTaskConstant.EMPLOYEE_KEY).getString(SJDRTaskConstant.NUMBER_KEY)));
        // 处理数据
        List<DynamicObject> data = new ArrayList<DynamicObject>();
        for (List<DynamicObject> dataDyList : dataDyMap.values() ) {
            for (int i = 0, size = dataDyList.size(); i < size; i++) {
                DynamicObject dataDy = dataDyList.get(i);
                calculateMon(entityType, dataDy, i > 0 ? dataDyList.get(i-1) : null);
                data.add(dataDy);
            }
        }
        // 保存
        SaveServiceHelper.save((DynamicObject[]) data.toArray());
    }

    /**
     * 数据处理
     */
    private void process(EntityType entityType) {
        // 过滤 雇佣阶段最新记录=1 并且 在职=1
        QFilter qFilter = new QFilter(SJDRTaskConstant.EMPSTAGELATESTRECORD_KEY, QCP.equals, EnableEnum.YES.getCode());
        qFilter.and(SJDRTaskConstant.ISHIRED_KEY, QCP.equals, EnableEnum.YES.getCode());
        // 查询所有员工当前生效的雇佣信息
        DynamicObject[] empentrelDys = BusinessDataServiceHelper.load(SJDRTaskConstant.HRPI_EMPENTREL, SJDRTaskConstant.EMPLOYEE_KEY, new QFilter[]{qFilter});
        // 当前在职的员工
        List<Long> employeeIds = Arrays.stream(empentrelDys).map(empentrelDy -> empentrelDy.getDynamicObject(SJDRTaskConstant.EMPLOYEE_KEY).getLong(SJDRTaskConstant.ID_KEY)).collect(Collectors.toList());
        // 获取 所有在职员工的数据
        qFilter = new QFilter(SJDRTaskConstant.EMPLOYEE_KEY, QCP.in, employeeIds);
        List<DynamicObject> allDatalDys = getDataDys(entityType, qFilter);
        // 分组 根据员工编码
        Map<String, List<DynamicObject>> allDataDyMap = allDatalDys.stream().collect(Collectors.groupingBy(dataDy -> dataDy.getDynamicObject(SJDRTaskConstant.EMPLOYEE_KEY).getString(SJDRTaskConstant.EMP_NUMBER_KEY)));
        // 获取 昨天（不含时间）
        Date yesterday = Date.from(LocalDate.now().minusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
        // 过滤 开始日期<=昨天 并且 结束日期>=昨天
        qFilter = new QFilter(SJDRTaskConstant.STARTDATE, QCP.less_equals, yesterday).and(SJDRTaskConstant.ENDDATE, QCP.large_equals, yesterday);
        // 获取 所有员工生效中的数据
        List<DynamicObject> dataDys = getDataDys(entityType, qFilter);
        // 处理数据
        for (int i = 0, is = dataDys.size(); i < is; i++) {
            DynamicObject dataDy = dataDys.get(i);
            // 获取 员工编码
            String empNumber = dataDy.getDynamicObject(SJDRTaskConstant.EMPLOYEE_KEY).getString(SJDRTaskConstant.EMP_NUMBER_KEY);
            // 从所有数据中获取当前员工数据的上一条数据
            List<DynamicObject> dataDyList = allDataDyMap.get(empNumber);
            DynamicObject lastDataDy = null;
            for (int j = 0, js = dataDyList.size(); j < js; j++) {
                DynamicObject tempDy = dataDyList.get(j);
                if (tempDy.getLong(SJDRTaskConstant.ID_KEY) == dataDy.getLong(SJDRTaskConstant.ID_KEY) && j > 0) {
                    lastDataDy = dataDyList.get(j-1);
                    break;
                }
            }
            // 判断获取到的上一条任职经历是否等于当前生效任职经历的上一条数据
            if (lastDataDy != null && i > 0 && lastDataDy.getLong(SJDRTaskConstant.ID_KEY) == dataDys.get(i-1).getLong(SJDRTaskConstant.ID_KEY)) {
                lastDataDy = dataDys.get(i-1);
            }
            // 计算时长
            calculateMon(entityType, dataDy, lastDataDy);
        }
        // 保存
        SaveServiceHelper.save((DynamicObject[]) dataDys.toArray());
    }
}
