package nckd.jxccl.hr.psms.task;

import com.alibaba.fastjson.JSON;
import kd.bos.common.enums.EnableEnum;
import kd.bos.context.RequestContext;
import kd.bos.dataentity.OperateOption;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.utils.ObjectUtils;
import kd.bos.entity.EntityMetadataCache;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.operate.result.IOperateInfo;
import kd.bos.entity.operate.result.OperationResult;
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.DispatchServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.sdk.plugin.Plugin;
import nckd.jxccl.base.common.constant.FormConstant;
import nckd.jxccl.base.common.enums.psms.AdjustTypeEnum;
import nckd.jxccl.base.common.enums.psms.TypeStateEnum;
import nckd.jxccl.base.common.exception.ValidationException;
import nckd.jxccl.base.common.utils.ConvertUtil;
import nckd.jxccl.base.common.utils.DateUtil;
import nckd.jxccl.base.common.utils.QueryFieldBuilder;
import nckd.jxccl.base.common.utils.StrFormatter;
import nckd.jxccl.base.entity.helper.EntityHelper;
import nckd.jxccl.base.swc.helper.AdjFileServiceHelper;
import nckd.jxccl.hr.psms.common.PositionStructureConstant;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 职位体系推送薪酬
 *
 * @author W.Y.C
 * @version 1.0
 * @date 2025/12/21 15:01
 */
public class PsmsAdjustSalaryTask extends AbstractTask implements Plugin {

    private static final Log logger = LogFactory.getLog(PsmsAdjustSalaryTask.class);


    @Override
    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
        logger.info("开始执行职位体系推送薪酬任务, 参数: {}", JSON.toJSONString(map));
        Long salaryItemId = EntityHelper.getIdByNumber(FormConstant.HSBS_STANDARDITEM, "jt008");
        Long billTypeId = EntityHelper.getIdByNumber(FormConstant.BOS_BILLTYPE, FormConstant.HCDM_APPLYBILL_BT_ADJ);
        Long countryId = EntityHelper.getIdByNumber(FormConstant.BD_COUNTRY, "001");
        Long salaryAdjuStrSnId = EntityHelper.getIdByNumber(FormConstant.HSBS_SALARYADJUSTRSN, "zhijibiandong");
        Long currencyId = EntityHelper.getIdByNumber(FormConstant.BD_CURRENCY, "CNY");
        Long adjApproveScmId = EntityHelper.getLatestIdByNumber(FormConstant.HCDM_ADJAPPROVESCM, "dingtiaoxin");
        Long exRateTableId = EntityHelper.getIdByNumber(FormConstant.BD_EXRATETABLE, "ERT-01");
        Long calFrequencyId = EntityHelper.getIdByNumber(FormConstant.HSBS_CALFREQUENCY, "000_m_001");
        //1：为本月数据，2：为上月数据
        Integer type = ConvertUtil.toInt(map.get("type"));
        Date beginDateParam = ConvertUtil.toDate(map.get("beginDateParam"));
        Date endDateParam = ConvertUtil.toDate(map.get("endDateParam"));
        
        logger.info("解析参数完成: type={}, beginDateParam={}, endDateParam={}", type, beginDateParam, endDateParam);
        
        // 校验日期：要么都为空，要么都不为空
        if ((beginDateParam == null && endDateParam != null) || (beginDateParam != null && endDateParam == null)) {
            logger.error("日期参数错误-开始日期和结束日期必须同时为空或同时不为空, beginDateParam={}, endDateParam={}", beginDateParam, endDateParam);
            throw new ValidationException("日期参数错误-开始日期和结束日期必须同时为空或同时不为空");
        }

        QFilter filter = new QFilter(PositionStructureConstant.NCKD_DISABLE, QCP.equals, EnableEnum.NO.getCode())
                .and(PositionStructureConstant.NCKD_TYPESTATE, QCP.in, new String[]{TypeStateEnum.NEW_ENTRY.getCode(),TypeStateEnum.IN_SERVICE_LEVEL.getCode(),TypeStateEnum.ANNUAL_ADJUSTMENT.getCode(),TypeStateEnum.POSITION_TRANSFER.getCode()});
        Date beginDate = null;
        Date endDate = null;
        if(beginDateParam != null && endDateParam != null){
            beginDate = DateUtil.beginOfDay(beginDateParam);
            endDate = DateUtil.endOfDay(endDateParam);
            logger.info("使用自定义日期范围: beginDate={}, endDate={}", beginDate, endDate);
        }else{
            LocalDateTime now = DateUtil.now();
            if(type == 2){
                now = DateUtil.minusMonths(now, 1);
                logger.info("处理上月数据");
            }else if(type == 1){
                logger.info("处理本月数据");
            }else{
                logger.error("参数错误-type，只能为1或2, 当前type={}", type);
                throw new ValidationException("参数错误-type，只能为1或2");
            }
            beginDate = DateUtil.toDate(DateUtil.beginOfMonth(now));
            endDate = DateUtil.toDate(DateUtil.endOfMonth(now));
            logger.info("计算日期范围: beginDate={}, endDate={}", beginDate, endDate);
        }
        filter.and(FormConstant.CREATE_TIME_KEY,QCP.large_equals,beginDate);
        filter.and(FormConstant.CREATE_TIME_KEY,QCP.less_equals,new Date());

        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                .add(FormConstant.ID_KEY)
                .addIdNumberName(FormConstant.NCKD_PERSON)
                .add(PositionStructureConstant.NCKD_ISSALADJPUSH)
                .add(PositionStructureConstant.NCKD_BEGINDATE)
                .add(PositionStructureConstant.CREATE_TIME_KEY)
                .addIdNumberNameWithExtras(new String[]{PositionStructureConstant.NCKD_JOBLEVELHR},PositionStructureConstant.JOBLEVELSEQ,PositionStructureConstant.NCKD_COEFFICIENT)
                .addIdNumberName(PositionStructureConstant.NCKD_LASTPERSONPOSFILE,PositionStructureConstant.NCKD_JOBLEVELHR)
                .orderDesc(FormConstant.CREATE_TIME_KEY);
        DynamicObjectCollection personPosFileColl = QueryServiceHelper.query(PositionStructureConstant.PERSONPOSFILE_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
        
        logger.info("查询到 {} 条职位档案记录", personPosFileColl.size());
        
        // 按人员分组，Map<Long,List<DynamicObject>>
        Map<Long, List<DynamicObject>> personPosFileMap = personPosFileColl.stream()
                .collect(Collectors.groupingBy(
                        obj -> obj.getLong(String.join(".", PositionStructureConstant.NCKD_PERSON, FormConstant.ID_KEY))
                ));
        
        logger.info("按人员分组完成，共 {} 个员工", personPosFileMap.size());
        
        //需要推送调薪的员工档案id
        List<Long> needAdjustSalaryId = new ArrayList<>();
        List<Long> needPersonId = new ArrayList<>();
        List<Long> jobLevelIds = new ArrayList<>();
        // 处理每个员工的记录
        for (Map.Entry<Long, List<DynamicObject>> entry : personPosFileMap.entrySet()) {
            List<DynamicObject> records = entry.getValue();
            // 在当前员工的所有记录中，找出beginDate~endDate范围内CREATE_TIME_KEY最新的那条记录
            Date finalBeginDate = beginDate;
            Date finalEndDate = endDate;
            Optional<DynamicObject> latestRecordOpt = records.stream()
                    .filter(record -> {
                        Date createTime = record.getDate(PositionStructureConstant.CREATE_TIME_KEY);
                        return createTime != null &&
                                !createTime.before(finalBeginDate) &&
                                !createTime.after(finalEndDate);
                    })
                    .max(Comparator.comparing(record -> record.getDate(PositionStructureConstant.CREATE_TIME_KEY)));

            // 如果找到了时间范围内的最新记录
            if (latestRecordOpt.isPresent()) {
                DynamicObject latestRecord = latestRecordOpt.get();
                Date latestCreateTime = latestRecord.getDate(PositionStructureConstant.CREATE_TIME_KEY);

                // 检查在latestCreateTime到当前时间范围内，该员工是否有NCKD_ISSALADJPUSH=true的记录（有的话说明当前数据之后已经有推送薪酬了，这条不用推送）
                boolean hasPushedRecord = records.stream()
                        .filter(record -> {
                            Date createTime = record.getDate(PositionStructureConstant.CREATE_TIME_KEY);
                            return createTime != null &&
                                    !createTime.before(latestCreateTime);
                        })
                        .anyMatch(record -> record.getBoolean(PositionStructureConstant.NCKD_ISSALADJPUSH));
                // 如果在最新记录时间之后没有推送调薪的记录，则添加到需要推送调薪的列表中
                if (!hasPushedRecord) {
                    needAdjustSalaryId.add(latestRecord.getLong(FormConstant.ID_KEY));
                    needPersonId.add(latestRecord.getLong(String.join(".", PositionStructureConstant.NCKD_PERSON, FormConstant.ID_KEY)));
                    jobLevelIds.add(latestRecord.getLong(String.join(".", PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY)));
                    //上一档案职级
                    long lastJobLevel = latestRecord.getLong(String.join(".", PositionStructureConstant.NCKD_LASTPERSONPOSFILE, PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
                    jobLevelIds.add(lastJobLevel);
                }
            }
        }
        
        logger.info("筛选出需要推送调薪的记录 {} 条", needAdjustSalaryId.size());

        if(!needAdjustSalaryId.isEmpty()){
            logger.info("开始获取人员最新岗位工资标准定薪记录");
            //获取人员最新岗位工资标准定薪记录
            List<AdjFileServiceHelper.SalaryAdjustmentResult> salaryAdjustmentResultList = AdjFileServiceHelper.getLastDecAdjRecords(needPersonId, FormConstant.POS_STANDARD_ITEM_NUMBER);
            Map<Long, List<AdjFileServiceHelper.SalaryAdjustmentResult>> salaryAdjustmentResultMap = salaryAdjustmentResultList.stream()
                    .collect(Collectors.groupingBy(result -> result.employee.getLong(FormConstant.ID_KEY)));
            
            logger.info("获取到 {} 条定薪记录", salaryAdjustmentResultList.size());
            
            if (!salaryAdjustmentResultList.isEmpty()) {
                Map<Long, DynamicObject> jobLevelMap = new HashMap<>(jobLevelIds.size());
                if(!jobLevelIds.isEmpty()) {
                    MainEntityType jobLevelEntityType = EntityMetadataCache.getDataEntityType(FormConstant.HBJM_JOBLEVELHR);
                    //重新加载职级信息，避免获取不到系数
                    DynamicObject[] load = BusinessDataServiceHelper.load(jobLevelIds.toArray(new Long[0]), jobLevelEntityType);
                    jobLevelMap = Arrays.stream(load)
                            .collect(Collectors.toMap(
                                    obj -> obj.getLong(FormConstant.ID_KEY),
                                    obj -> obj
                            ));
                    
                    logger.info("加载 {} 条职级信息", load.length);
                }

                List<DynamicObject> updatePersonPosFile = new ArrayList<>();
                MainEntityType personPosFileEntityType = EntityMetadataCache.getDataEntityType(PositionStructureConstant.PERSONPOSFILE_ENTITYID);
                DynamicObject[] personPosFileArray = BusinessDataServiceHelper.load(needAdjustSalaryId.toArray(), personPosFileEntityType);
                
                logger.info("加载 {} 条职位档案记录用于更新", personPosFileArray.length);
                
                for (DynamicObject personPosFile : personPosFileArray) {
                    long jobLevelId = personPosFile.getLong(String.join(".", PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
                    long lastJobLevelId = personPosFile.getLong(String.join(".",PositionStructureConstant.NCKD_LASTPERSONPOSFILE, PositionStructureConstant.NCKD_JOBLEVELHR, FormConstant.ID_KEY));
                    DynamicObject jobLevel = jobLevelMap.get(jobLevelId);
                    DynamicObject lastJobLevel = jobLevelMap.get(lastJobLevelId);

                    if(jobLevel != null) {
                        DynamicObject person = personPosFile.getDynamicObject(FormConstant.NCKD_PERSON);
                        Date date = personPosFile.getDate(PositionStructureConstant.NCKD_BEGINDATE);
                        List<AdjFileServiceHelper.SalaryAdjustmentResult> salaryAdjustmentResults = salaryAdjustmentResultMap.get(person.getLong(FormConstant.ID_KEY));
                        if (salaryAdjustmentResults != null) {
                            AdjFileServiceHelper.SalaryAdjustmentResult salaryAdjustmentResult = salaryAdjustmentResults.get(0);
                            BigDecimal coefficient = jobLevel.getBigDecimal(PositionStructureConstant.NCKD_COEFFICIENT);
                            
                            logger.info("处理员工 {}, 职位档案ID: {}, 职级系数: {}", 
                                person.getString(FormConstant.NAME_KEY), 
                                personPosFile.getLong(FormConstant.ID_KEY), 
                                coefficient);
                            
                            //触发定调薪
                            Map<String, Object> applyBill = new HashMap<>();
                            applyBill.put("billname", StrFormatter.format("【{}】的职位体系调整（职位津贴）",person.getString(FormConstant.NAME_KEY)));
                            Long orgId = RequestContext.get().getOrgId();
                            String uniquecode = UUID.randomUUID().toString().replace("-", "");
                            applyBill.put("_uniquecode", uniquecode);
                            if(salaryAdjustmentResult.hcdmOrg != null){
                                applyBill.put("org", salaryAdjustmentResult.hcdmOrg.getLong(FormConstant.ID_KEY));
                            }else{
                                applyBill.put("org", orgId);
                            }
                            //定调薪明细字段显示方案   调薪明细字段
                            applyBill.put("billtype", billTypeId);
                            //国家
                            applyBill.put("billcountry", countryId);
                            //定调薪类型
                            applyBill.put("salaryadjrsn", salaryAdjuStrSnId);
                            //默认币种
                            applyBill.put("billcurrency", currencyId);
                            //定调薪方案
                            applyBill.put("salaryadjscm", adjApproveScmId);
                            //汇率日期
                            applyBill.put("exchangeratedate", new Date());
                            //汇率表
                            applyBill.put("exctable", exRateTableId);
                            //默认生效日期
                            applyBill.put("effectivedate", date);
                            //草稿状态
                            applyBill.put("isdraft", "1");
                            //审核状态
                            applyBill.put("auditstatus", "A");
                            //申请单数据来源   //1:手工新增  2:接口写入
                            applyBill.put("datasource", "2");

                            String typeStateStr = personPosFile.getString(PositionStructureConstant.NCKD_TYPESTATE);
                            TypeStateEnum typeState = TypeStateEnum.getByCode(typeStateStr);
                            String adjustTypeStr = personPosFile.getString(PositionStructureConstant.NCKD_ADJUSTTYPE);
                            AdjustTypeEnum adjustType = AdjustTypeEnum.getByCode(adjustTypeStr);
                            String description = StrFormatter.format("【{}】执行【{}】，调整生效时间【{}】，调整类别【{}】，由【{}（{}）】 -> 【{}（{}级）】。系数【{}】",
                                    DateUtil.format(personPosFile.getDate(FormConstant.CREATE_TIME_KEY),DateUtil.NORM_DATETIME_PATTERN),
                                    typeState.getName(),
                                    DateUtil.format(personPosFile.getDate(PositionStructureConstant.NCKD_BEGINDATE),DateUtil.NORM_DATE_PATTERN),
                                    adjustType != null ? adjustType.getName() : "初定",
                                    lastJobLevel == null ? "无" : lastJobLevel.getString(FormConstant.NAME_KEY),
                                    lastJobLevel == null ? "无" : lastJobLevel.getString(FormConstant.JOBLEVELSEQ)+"级",
                                    jobLevel.getString(FormConstant.NAME_KEY),
                                    jobLevel.getString(FormConstant.JOBLEVELSEQ),
                                    coefficient
                            );
                            applyBill.put("description", description);
                            List<Map<String, Object>> applyBillEntryData = new ArrayList<>();
                            Map<String, Object> applyBillEntry = new HashMap<>();
                            Long employeeId = person.getLong(FormConstant.ID_KEY);
                            Long positionId = personPosFile.getLong(String.join(".",PositionStructureConstant.NCKD_POSITIONHR, FormConstant.ID_KEY));
                            applyBillEntry.put("adjfile", salaryAdjustmentResult.adjFileInfo.getLong(FormConstant.ID_KEY));
                            applyBillEntry.put("employee", employeeId);
                            applyBillEntry.put("standarditem", salaryItemId);    //定调薪项目   职位系数
                            applyBillEntry.put("frequency", calFrequencyId);       //频度  月
                            applyBillEntry.put("amount", coefficient);
                            applyBillEntry.put("position", positionId);
                            applyBillEntry.put("joblevel", jobLevel.getLong(FormConstant.ID_KEY));
                            /*applyBillEntry.put("salarygrade", salaryAdjustmentResult.salaryGrade.getLong(FormConstant.ID_KEY));
                            applyBillEntry.put("salaryrank", salaryAdjustmentResult.salaryRank.getLong(FormConstant.ID_KEY));*/
                            applyBillEntry.put("reason", description);
                            applyBillEntryData.add(applyBillEntry);
                            applyBill.put("applybillent", applyBillEntryData);
                            List<Map<String, Object>> applyBillData = new ArrayList<>();
                            applyBillData.add(applyBill);
                            Map<String, Object> papams = new HashMap<>();
                            papams.put("data", applyBillData);
                            papams.put("isUseMatchAmount", Boolean.TRUE);
                            
                            logger.info("准备推送员工 {} 的定调薪申请单", person.getString(FormConstant.NAME_KEY));
                            Map<String, Object> result = DispatchServiceHelper.invokeService("nckd.jxccl.swc.hcdm.servicehelper", "hcdm", "ISwcService", "saveDraftApplyBill", papams);
                            if (!ConvertUtil.toBoolean(result.get("success")) || result.get("data") == null || ConvertUtil.toList(result.get("data")).isEmpty()) {
                                logger.error("【{}】推送定调薪失败，原因：{}", person.getString(FormConstant.NAME_KEY), JSON.toJSONString(result));
                                throw new ValidationException("【"+person.getString(FormConstant.NAME_KEY)+"】推送定调薪失败，原因：" + JSON.toJSONString(result));
                            }else{
                                personPosFile.set(PositionStructureConstant.NCKD_ISSALADJPUSH, Boolean.TRUE);
                                personPosFile.set(PositionStructureConstant.NCKD_SALADJPUSHTIME, new Date());
                                personPosFile.set(PositionStructureConstant.NCKD_SALADJID, ConvertUtil.toMap(ConvertUtil.toList(result.get("data")).get(0)).get("id"));
                                
                                logger.info("成功推送员工 {} 的定调薪申请单，申请单ID: {}", 
                                    person.getString(FormConstant.NAME_KEY), 
                                    ConvertUtil.toMap(ConvertUtil.toList(result.get("data")).get(0)).get("id"));

                                updatePersonPosFile.add(personPosFile);
                            }
                        } else {
                            logger.warn("未获取到员工【{}】最新岗位工资标准定薪记录01档的薪等金额，人员ID：{}", person.getString(FormConstant.NAME_KEY), person.getLong(FormConstant.ID_KEY));
                        }
                    } else {
                        logger.warn("员工 {} 的职级信息为空，跳过处理", personPosFile.getDynamicObject(FormConstant.NCKD_PERSON).getString(FormConstant.NAME_KEY));
                    }
                }

                if(!updatePersonPosFile.isEmpty()){
                    logger.info("开始保存 {} 条职位档案更新记录", updatePersonPosFile.size());
                    OperationResult operationResult = SaveServiceHelper.saveOperate(PositionStructureConstant.PERSONPOSFILE_ENTITYID, updatePersonPosFile.toArray(new DynamicObject[0]), OperateOption.create());
                    if (!operationResult.isSuccess()) {
                        StringJoiner errorMsg = new StringJoiner("\n");
                        for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
                            errorMsg.add(error.getMessage());
                        }
                        if (!ObjectUtils.isEmpty(operationResult.getMessage())) {
                            errorMsg.add(operationResult.getMessage());
                        }
                        logger.error("保存职位档案失败，原因：{}", errorMsg.toString());
                        throw new ValidationException("保存职位档案失败，原因：" + errorMsg.toString());
                    } else {
                        logger.info("成功保存 {} 条职位档案记录", updatePersonPosFile.size());
                    }
                } else {
                    logger.info("没有需要保存的职位档案更新记录");
                }

            } else {
                logger.warn("未获取到人员岗位工资标准定薪记录，人员ID：{}",needPersonId);
            }
        }else{
            logger.warn("没有需要推送的调薪数据");
        }
        
        logger.info("职位体系推送薪酬任务执行完成");
    }
}