package nckd.jxccl.hr.ijp.plugin.operate;

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.ExtendedDataEntity;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.operate.result.IOperateInfo;
import kd.bos.entity.operate.result.OperationResult;
import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
import kd.bos.entity.plugin.AddValidatorsEventArgs;
import kd.bos.entity.plugin.PreparePropertysEventArgs;
import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
import kd.bos.entity.validate.AbstractValidator;
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.servicehelper.BusinessDataServiceHelper;
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.ijp.TalentTypeEnum;
import nckd.jxccl.base.common.exception.ValidationException;
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.hrpi.helper.EmpPosOrgRelHelper;
import nckd.jxccl.hr.ijp.common.IntJobPostConstant;
import nckd.jxccl.hr.psms.common.PositionStructureConstant;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
* 内部人力资源市场-三类人员记录生成-审批通过
* 实体标识：nckd_intjobpost
* @author W.Y.C
* @date 2026/1/8 21:34
* @version 1.0
*/
public class IntJobPostAuditedOpPlugin extends AbstractOperationServicePlugIn implements Plugin {

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

    @Override
    public void onPreparePropertys(PreparePropertysEventArgs e) {
        e.getFieldKeys().addAll(billEntityType.getAllFields().keySet());
    }

    @Override
    public void onAddValidators(AddValidatorsEventArgs e) {
        e.addValidator(new AbstractValidator(){
            @Override
            public void validate() {
                List<Long> personIds = new ArrayList<>();
                for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
                    DynamicObject data = rowDataEntity.getDataEntity();
                    DynamicObjectCollection entryEntity = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
                    for (DynamicObject entry : entryEntity) {
                        DynamicObject person = entry.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
                        if(person == null){
                            this.addFatalErrorMessage(rowDataEntity,"请选择人员");
                        }else{
                            long personId = person.getLong(FormConstant.ID_KEY);
                            personIds.add(personId);
                        }
                    }

                }
                Map<Long, DynamicObject> empPosOrgRelMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
                for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
                    DynamicObject data = rowDataEntity.getDataEntity();
                    DynamicObjectCollection entryEntity = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
                    for (DynamicObject entry : entryEntity) {
                        DynamicObject person = entry.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
                        if (person != null) {
                            long personId = person.getLong(FormConstant.ID_KEY);
                            if (empPosOrgRelMap.get(personId) == null) {
                                this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("人员【{}】没有在岗状态的任职经历", person.getString(FormConstant.NAME_KEY)));
                            }
                        }
                    }
                }
            }
        });
    }

    @Override
    public void beginOperationTransaction(BeginOperationTransactionArgs e) {

        logger.info("开始执行内部人力资源市场审批通过操作");
        List<Long> personIds = new ArrayList<>();
        List<Long> entityIds = new ArrayList<>();
        for (DynamicObject dataEntity : e.getDataEntities()) {
            DynamicObjectCollection entryEntity = dataEntity.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
            for (DynamicObject entry : entryEntity) {
                DynamicObject person = entry.getDynamicObject(PositionStructureConstant.NCKD_PERSON);
                boolean isEnter = entry.getBoolean(IntJobPostConstant.NCKD_ISENTER);
                if(isEnter){
                    personIds.add(person.getLong(IntJobPostConstant.ID_KEY));
                }
                entityIds.add(entry.getLong(IntJobPostConstant.ID_KEY));
            }
        }
        logger.info("需要处理的人员ID数量: {}, 分录ID数量: {}", personIds.size(), entityIds.size());
        Map<Long, DynamicObject> empPosOrgRelMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personIds);
        logger.info("获取到的员工岗位组织关系数量: {}", empPosOrgRelMap.size());

        // --- A. 处理旧记录 ---
        // 1. 查询该员工最近的一条记录（排除当前单据产生的记录，按创建时间倒序取第一条）
        long currUserId = RequestContext.get().getCurrUserId();
        List<DynamicObject> savedRecords = new ArrayList<>();
        //由于轨迹需要关联本次新增的记录，需要等记录保存成功后再set内部人力资源市场记录。 以分录id作为key，记录待新增的轨迹。
        Map<Long, DynamicObject> savedLocusMap = new HashMap<>();
        List<DynamicObject> savedLocus = new ArrayList<>();
        logger.info("开始查询人员最新记录");
        Map<Long, DynamicObject> latestRecordMap = getLatestRecordIdsByPersons(personIds, entityIds);
        logger.info("获取到人员最新记录数量: {}", latestRecordMap.size());

        logger.info("开始查询人员最新轨迹");
        Map<Long, DynamicObject> latestLocusMap = findLatestLocusByPerson(personIds);
        logger.info("获取到人员最新轨迹数量: {}", latestLocusMap.size());
        for (DynamicObject dataEntity : e.getDataEntities()) {
            Date auditDate = dataEntity.getDate(IntJobPostConstant.AUDIT_DATE_KEY);
            String talentType = dataEntity.getString(IntJobPostConstant.NCKD_TALENTTYPE);
            TalentTypeEnum talentTypeEnum = TalentTypeEnum.getByCode(talentType);
            DynamicObjectCollection entryEntity = dataEntity.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
            for (DynamicObject entry : entryEntity) {
                long id = entry.getLong(IntJobPostConstant.ID_KEY);
                boolean isEnter = entry.getBoolean(IntJobPostConstant.NCKD_ISENTER);
                long personId = entry.getLong(String.join(".", IntJobPostConstant.NCKD_PERSON, IntJobPostConstant.ID_KEY));
                String name = entry.getString(String.join(".", IntJobPostConstant.NCKD_PERSON, IntJobPostConstant.NAME_KEY));
                if(isEnter){
                    logger.info("处理进入市场的人员: {}, 人员ID: {}", name, personId);
                    DynamicObject latestRecord = latestRecordMap.get(personId);
                    if(latestRecord != null) {
                        // 2. 备份旧值
                        latestRecord.set(IntJobPostConstant.NCKD_OLDTOFOURDATE, latestRecord.get(IntJobPostConstant.NCKD_TOFOURDATE));
                        latestRecord.set(IntJobPostConstant.NCKD_OLDSTATE, latestRecord.get(IntJobPostConstant.NCKD_STATE));
                        //退出市场时间
                        latestRecord.set(IntJobPostConstant.NCKD_TOFOURDATE, auditDate);
                        //标记上一条为退出市场
                        latestRecord.set(IntJobPostConstant.NCKD_STATE, "4");
                        latestRecord.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST, Boolean.FALSE);
                        latestRecord.set(IntJobPostConstant.NCKD_BACKUP, StrFormatter.format("以【{}】身份新进入市场，退出原市场。",talentTypeEnum.getName()));
                        savedRecords.add(latestRecord);
                        logger.info("已添加旧记录至更新列表，人员: {}, 旧状态: 1(在市场中) -> 新状态: 4(退出市场)",name);
                    }

                    // --- B. 插入新记录 ---
                    DynamicObject newRecord = EntityHelper.newEntity(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID);
                    DynamicObject empPosOrgRel = empPosOrgRelMap.get(personId);
                    newRecord.set(IntJobPostConstant.NCKD_EMPPOSORGREL, empPosOrgRel);
                    newRecord.set(IntJobPostConstant.NCKD_ADMINORG,empPosOrgRel.get(IntJobPostConstant.ADMINORG));
                    newRecord.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST, Boolean.TRUE);
                    //初始状态：进入市场
                    newRecord.set(IntJobPostConstant.NCKD_STATE,"1");
                    newRecord.set(IntJobPostConstant.NCKD_TALENTTYPE,dataEntity.get(IntJobPostConstant.NCKD_TALENTTYPE));
                    newRecord.set(IntJobPostConstant.NCKD_BEGINDATE,dataEntity.get(IntJobPostConstant.NCKD_BIZDAY));
                    newRecord.set(IntJobPostConstant.NCKD_YEAR,dataEntity.get(IntJobPostConstant.NCKD_YEAR));
                    //分录
                    newRecord.set(IntJobPostConstant.NCKD_INTJOBPOSTENTRY, entry);
                    newRecord.set(IntJobPostConstant.NCKD_APPRAISALRESULT,entry.get(IntJobPostConstant.NCKD_APPRAISALRESULT));
                    newRecord.set(IntJobPostConstant.NCKD_BEFORELAST,entry.get(IntJobPostConstant.NCKD_BEFORELAST));
                    newRecord.set(FormConstant.CREATOR_KEY,currUserId);
                    if ("A".equals(dataEntity.getString(IntJobPostConstant.NCKD_TALENTTYPE))) {
                        //优秀员工-预计退出时间
                        Date date = DateUtil.addYears(auditDate, 1);
                        newRecord.set(IntJobPostConstant.NCKD_PREDICTTOFOURDATE, date);
                        logger.info("A类人才，设置预计退出时间为: {}", date);
                    }
                    savedRecords.add(newRecord);
                    logger.info("已添加新记录至保存列表，人员: {}, 状态: 1(进入市场)", name);

                    // --- C. 处理轨迹 (Locus) ---
                    // 1. 查询最近的轨迹
                    DynamicObject latestLocus = latestLocusMap.get(personId);
                    if(latestLocus != null){
                        latestLocus.set(IntJobPostConstant.NCKD_OLDENDDAY, latestLocus.get(IntJobPostConstant.ENDDATE));
                        latestLocus.set(IntJobPostConstant.ENDDATE, auditDate);
                        latestLocus.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST, Boolean.FALSE);
                        savedLocus.add(latestLocus);
                    }
                    // 2. 插入新轨迹
                    DynamicObject newLocus = EntityHelper.newEntity(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID);
                    newLocus.set(IntJobPostConstant.NCKD_EMPPOSORGREL, empPosOrgRel);
                    newLocus.set(IntJobPostConstant.NCKD_ADMINORG,empPosOrgRel.get(IntJobPostConstant.ADMINORG));
                    newLocus.set(IntJobPostConstant.NCKD_ISCURRENTNEWEST, Boolean.TRUE);
                    newLocus.set(IntJobPostConstant.NCKD_INTJOBPOSTRECORD, newRecord);
                    newLocus.set(IntJobPostConstant.NCKD_STARTDATE, dataEntity.get(IntJobPostConstant.NCKD_BIZDAY));
                    newLocus.set(IntJobPostConstant.NCKD_TALENTTYPE, dataEntity.get(IntJobPostConstant.NCKD_TALENTTYPE));
                    newLocus.set(IntJobPostConstant.NCKD_STATE, "1");
                    newLocus.set(FormConstant.CREATOR_KEY,currUserId);
                    savedLocusMap.put(id, newLocus);
                    logger.info("已添加新轨迹至保存映射，分录ID: {}, 人员: {}", id, name);
                }
            }
        }
        logger.info("准备保存记录总数: {}, 轨迹总数: {}", savedRecords.size(), savedLocusMap.size());

        if(!savedRecords.isEmpty()){
            logger.info("开始保存内部人力资源市场记录，记录数量: {}", savedRecords.size());
            //保存记录
            OperationResult operationResult = SaveServiceHelper.saveOperate(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID, savedRecords.toArray(new DynamicObject[0]), OperateOption.create());
            if(operationResult.isSuccess()){
                logger.info("内部人力资源市场记录保存成功");
                //新增实体
                savedLocus.addAll(savedLocusMap.values());
                logger.info("准备保存轨迹记录，数量: {}", savedLocus.size());
                OperationResult locusOperationResult = SaveServiceHelper.saveOperate(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID, savedLocus.toArray(new DynamicObject[0]), OperateOption.create());
                if(!locusOperationResult.isSuccess()){
                    StringJoiner errorMsg = new StringJoiner("\n");
                    for (IOperateInfo error : locusOperationResult.getAllErrorOrValidateInfo()) {
                        errorMsg.add(error.getMessage());
                    }
                    if (!ObjectUtils.isEmpty(locusOperationResult.getMessage())) {
                        errorMsg.add(locusOperationResult.getMessage());
                    }
                    logger.error("保存轨迹记录失败，原因：{}", errorMsg.toString());
                    throw new ValidationException("保存职位档案失败，原因：" + errorMsg.toString());
                }
                logger.info("轨迹记录保存成功");

            }else{
                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());
            }
        }





        // --- A. 处理旧记录 ---
        // 1. 查询该员工最近的一条记录（排除当前单据产生的记录，按创建时间倒序取第一条）


        //1、阶段1：备份原有记录
        // 条件：单据中要进入市场(CFIsenter=1)的员工 + 他们最新的记录 + 记录来源不是当前单据
        //目的：为反审批时恢复数据做准备

        //阶段2：关闭原记录
        //逻辑：一个员工只能有一条活跃记录(FIsSingle=1)
        //状态变化：1(在市场中) → 4(退出市场)

        //阶段3：创建新记录
        //新记录状态：FIsSingle=1, CFInsidehrRecordState='1'

        //阶段3：特殊处理
        //A类员工：有预计退出时间（1年后）
        //非A类员工：预计退出时间为null

    }

    /**
     * 获取每个人员最新一条记录
     * @param personIds 人员ID
     * @param entityIds 分录ID
     * @return: java.util.Map<java.lang.Long, java.util.List < kd.bos.dataentity.entity.DynamicObject>>
     * @author W.Y.C
     * @date: 2026/01/13 15:56
     */
    public Map<Long, DynamicObject> getLatestRecordIdsByPersons(List<Long> personIds,List<Long> entityIds) {
        QueryFieldBuilder intJobPostRecord = QueryFieldBuilder.create().add(IntJobPostConstant.ID_KEY)
                .add(FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY,FormConstant.ID_KEY)
                .add(IntJobPostConstant.NCKD_ISCURRENTNEWEST)
                .orderDesc(IntJobPostConstant.CREATE_TIME_KEY);
        QFilter filter = new QFilter(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY), QCP.in, personIds)
                .and(IntJobPostConstant.NCKD_INTJOBPOSTENTRY,QCP.not_in,entityIds);
        DynamicObjectCollection records = QueryServiceHelper.query(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID, intJobPostRecord.buildSelect(), new QFilter[]{filter});
        Set<Long> uniquePersonIds = new HashSet<>();
        List<Long> result = new ArrayList<>();
        for (DynamicObject record : records) {
            Long personId = record.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY));
            if (uniquePersonIds.add(personId)) { // 如果是新的personId，添加到结果中
                result.add(record.getLong(IntJobPostConstant.ID_KEY));
            }
        }
        MainEntityType intJobPostRecordEntityType = EntityMetadataCache.getDataEntityType(IntJobPostConstant.INTJOBPOSTRECORD_ENTITYID);
        DynamicObject[] load = BusinessDataServiceHelper.load(result.toArray(new Long[0]), intJobPostRecordEntityType);
        return Arrays.stream(load)
                .collect(Collectors.toMap(
                        obj -> obj.getLong(String.join(".", FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)),
                        obj -> obj
                ));
    }

    /**
     * 查询最近的轨迹
     * @param personIds 人员ID
     * @return: java.util.Map<java.lang.Long, java.util.List < kd.bos.dataentity.entity.DynamicObject>>
     * @author W.Y.C
     * @date: 2026/01/13 15:56
     */
    public Map<Long, DynamicObject> findLatestLocusByPerson(List<Long> personIds) {
        QueryFieldBuilder intJobPostLocus = QueryFieldBuilder.create().add(IntJobPostConstant.ID_KEY)
                .add(FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY,FormConstant.ID_KEY)
                .add(IntJobPostConstant.NCKD_ISCURRENTNEWEST)
                .orderDesc(IntJobPostConstant.CREATE_TIME_KEY);
        QFilter filter = new QFilter(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY), QCP.in, personIds);
        DynamicObjectCollection records = QueryServiceHelper.query(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID, intJobPostLocus.buildSelect(), new QFilter[]{filter});
        Set<Long> uniquePersonIds = new HashSet<>();
        List<Long> result = new ArrayList<>();
        for (DynamicObject record : records) {
            Long personId = record.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY));
            if (uniquePersonIds.add(personId)) { // 如果是新的personId，添加到结果中
                result.add(record.getLong(IntJobPostConstant.ID_KEY));
            }
        }
        MainEntityType intJobPostLocusEntityType = EntityMetadataCache.getDataEntityType(IntJobPostConstant.INTJOBPOSTLOCUS_ENTITYID);
        DynamicObject[] load = BusinessDataServiceHelper.load(result.toArray(new Long[0]), intJobPostLocusEntityType);
        return Arrays.stream(load)
                .collect(Collectors.toMap(
                        obj -> obj.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)),
                        obj -> obj
                ));
    }
}