package nckd.jxccl.hr.psms.plugin.operate.performance;

import kd.bos.common.enums.EnableEnum;
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.OperateOptionConst;
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.plugin.args.EndOperationTransactionArgs;
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.MetadataServiceHelper;
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.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.hrpi.helper.EmpPosOrgRelHelper;
import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant;
import nckd.jxccl.hr.psms.common.PositionStructureConstant;
import nckd.jxccl.hr.psms.plugin.operate.performance.validate.PerfRankMgmtSaveValidate;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
* 年度绩效排名管理-保存插件
* @author W.Y.C
* @date 2025/10/21 17:05
* @version 1.0
*/
public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn implements Plugin {

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

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

    @Override
    public void onAddValidators(AddValidatorsEventArgs e) {
        e.addValidator(new PerfRankMgmtSaveValidate());
    }

    private Map<Long,List<Long>> dbPersonMap = new HashMap<>();

    @Override
    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
        boolean dataMigration = false;
        Object invoker = this.getOption().getVariables().get(FormConstant.HR_INVOKER_PARAM_INVOKER);
        if(ObjectUtils.isEmpty(invoker)){
            Object invoker1 = this.getOption().getVariables().get("hr_hrdmvalidatetag_of_datasource");
            Object invoker2 = this.getOption().getVariables().get("hr_hrdmsynctag_of_datasource");
            if(!ObjectUtils.isEmpty(invoker1) || !ObjectUtils.isEmpty(invoker2)){
                dataMigration = true;
            }
        } else{
            dataMigration = FormConstant.DATA_MIGRATION.equalsIgnoreCase(invoker.toString());
        }
        List<Long> ids = new ArrayList<>();
        List<Long> personids = new ArrayList<>();
        //用来判断后续有没有必要查询任职经历，避免浪费资源
        boolean isQueryEmpPosOrg = false;
        for (DynamicObject dataEntity : e.getDataEntities()) {
            long id = dataEntity.getLong(FormConstant.ID_KEY);
            if(id > 0){
                ids.add(id);
            }
            DynamicObjectCollection entryList = dataEntity.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
            for (DynamicObject entry : entryList) {
                DynamicObject person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
                if(person != null) {
                    personids.add(person.getLong(FormConstant.ID_KEY));
                }
                if(entry.getDynamicObject(FormConstant.NCKD_DEP) == null){
                    isQueryEmpPosOrg = true;
                }
                if(entry.getDynamicObject(PositionStructureConstant.NCKD_POSITIONHR) == null){
                    isQueryEmpPosOrg = true;
                }
            }
        }

        String deleteRow = this.getOption().getVariableValue(FormConstant.DELETEENTRY_OP, StringUtils.EMPTY);
        Boolean removedEntries = ConvertUtil.toBoolean(this.getOption().getVariableValue("removedEntries",StringUtils.EMPTY),Boolean.FALSE);
        Map<Long, List<DynamicObject>> nonRankingEntriesMap = new HashMap<>();
        if(removedEntries){
            MainEntityType perfRankMgmtEntityType = EntityMetadataCache.getDataEntityType(PerfRankMgmtConstant.NCKD_PERFRANKMGMT_ENTITYID);
            DynamicObject[] load = BusinessDataServiceHelper.load(ids.toArray(), perfRankMgmtEntityType);
            // 由于前端第二步不显示未参与排名的数据，保存时需要重新加载出未参与排名的数据，避免保存时未参与排名的数据丢失
            nonRankingEntriesMap = Arrays.stream(load)
                    .filter(Objects::nonNull)
                    .collect(Collectors.groupingBy(
                            obj -> obj.getLong(FormConstant.ID_KEY),
                            Collectors.collectingAndThen(
                                    Collectors.toList(),
                                    list -> list.stream()
                                            .flatMap(obj -> obj.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY).stream())
                                            .filter(entry -> !entry.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING))
                                            .collect(Collectors.toList())
                            )
                    ));

        }

        Map<Long, List<DynamicObject>> dbEntryMap = new HashMap<>();
        if(!ids.isEmpty()) {
            // 获取数据库中存在的人员ID列表
            QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                    .add(FormConstant.ID_KEY)
                    .addIdNumberName(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY, FormConstant.NCKD_PERSON);
            QFilter qFilter = new QFilter(FormConstant.ID_KEY, QCP.in, ids);
            DynamicObjectCollection dbEntryList = QueryServiceHelper.query(PerfRankMgmtConstant.NCKD_PERFRANKMGMT_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{qFilter});
            // 获取数据库中存在的记录，按记录ID分组
            dbEntryMap = dbEntryList.stream()
                    .collect(Collectors.groupingBy(
                            entry -> entry.getLong(FormConstant.ID_KEY) // 按记录ID分组
                    ));
        }
        Map<Long, DynamicObject> empPosOrgRelByEmployeesMap =  new HashMap<>();
        if(!personids.isEmpty() && isQueryEmpPosOrg){
            //获取人员最新任职
            empPosOrgRelByEmployeesMap = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(personids);
        }



        for (DynamicObject dataEntity : e.getDataEntities()) {
            long id = dataEntity.getLong(FormConstant.ID_KEY);
            if(removedEntries && id > 0 && !nonRankingEntriesMap.isEmpty()){
                List<DynamicObject> nonRankingEntries = nonRankingEntriesMap.get(id);
                if(nonRankingEntries != null && !nonRankingEntries.isEmpty()){
                    DynamicObjectCollection entryCollection = dataEntity.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
                    // 获取当前列表中已有的所有条目ID
                    Set<Long> existingIds = entryCollection.stream()
                            .map(entry -> entry.getLong(FormConstant.ID_KEY))
                            .filter(obj -> true)
                            .collect(Collectors.toSet());

                    // 只添加不存在的数据
                    List<DynamicObject> entriesToAdd = nonRankingEntries.stream()
                            .filter(entry -> {
                                Long entryId = entry.getLong(FormConstant.ID_KEY);
                                return !existingIds.contains(entryId);
                            })
                            .collect(Collectors.toList());

                    entryCollection.addAll(entriesToAdd);
                }

            }
            //事务开始前先查询数据库中的排名名单，找出哪些是此次被删除的人员（删除的人员同步删除人员考评的考核结果）
            List<DynamicObject> dbEntryList = dbEntryMap.get(dataEntity.getLong(FormConstant.ID_KEY));
            List<Long> dbPersonIds = Optional.ofNullable(dbEntryList)
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(dbEntry -> dbEntry.getLong(String.join(".", PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY,FormConstant.NCKD_PERSON, FormConstant.ID_KEY)))
                    .collect(Collectors.toList());
            dbPersonMap.put(dataEntity.getLong(FormConstant.ID_KEY), dbPersonIds);


            DynamicObjectCollection entryList = dataEntity.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
            entryList.sort((o1, o2) -> {
                Integer toprank1 = (Integer) o1.get(PerfRankMgmtConstant.NCKD_TOPRANK);
                Integer toprank2 = (Integer) o2.get(PerfRankMgmtConstant.NCKD_TOPRANK);

                // 如果两个值都为空或为0，则认为相等
                if ((toprank1 == null || toprank1 == 0) && (toprank2 == null || toprank2 == 0)) {
                    return 0;
                }
                // 如果第一个值为空或为0，则排在后面
                if (toprank1 == null || toprank1 == 0) {
                    return 1;
                }
                // 如果第二个值为空或为0，则排在前面
                if (toprank2 == null || toprank2 == 0) {
                    return -1;
                }
                // 都不为空且不为0则比较数值大小
                return toprank1.compareTo(toprank2);
            });
            AtomicInteger rankIndex = new AtomicInteger(1);
            for (DynamicObject entry : entryList) {
                DynamicObject person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
                personids.add(person.getLong(FormConstant.ID_KEY));
                DynamicObject empPosOrg = empPosOrgRelByEmployeesMap.get(person.getLong(FormConstant.ID_KEY));
                if(entry.getDynamicObject(FormConstant.NCKD_DEP) == null){
                    //赋值组织
                    if(empPosOrg != null) {
                        entry.set(FormConstant.NCKD_DEP, empPosOrg.get(FormConstant.ADMINORG));
                    }else{
                        logger.warn("【{}】人员没有任职信息", person.getLong(FormConstant.ID_KEY));
                    }
                }
                if(entry.getDynamicObject(PositionStructureConstant.NCKD_POSITIONHR) == null){
                    //赋值岗位
                    if(empPosOrg != null) {
                        entry.set(PositionStructureConstant.NCKD_POSITIONHR, empPosOrg.get(FormConstant.POSITION_KEY));
                    }
                }

                //生成R排名
                boolean isRanking = entry.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING);
                boolean postAllowance = entry.getBoolean(PerfRankMgmtConstant.NCKD_POSTALLOWANCE);
                if(isRanking && postAllowance){
                    entry.set(PerfRankMgmtConstant.NCKD_ALLOWANCERANK, rankIndex.getAndIncrement());
                }else{
                    entry.set(PerfRankMgmtConstant.NCKD_ALLOWANCERANK, null);
                }

            }
            /*if(dataMigration){
                //数据迁移逻辑
                DynamicObject[] dbEmpPosOrgRelList = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployees(personids);
                for (DynamicObject entry : entryList) {
                    DynamicObject person = entry.getDynamicObject(FormConstant.NCKD_PERSON);
                    DynamicObject empPosOrgRel = entry.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL);
                    if(empPosOrgRel == null){
                        long personId = person.getLong(FormConstant.ID_KEY);
                        for (DynamicObject ebEmpPosOrgRel : dbEmpPosOrgRelList) {
                            long employeeId = ebEmpPosOrgRel.getDynamicObject(FormConstant.EMPLOYEE_KEY).getLong(FormConstant.ID_KEY);
                            if(Objects.equals(personId, employeeId)){
                                entry.set(FormConstant.NCKD_EMPPOSORGREL, ebEmpPosOrgRel);
                                break;
                            }
                        }
                    }
                }
            }*/
        }

    }

    @Override
    public void endOperationTransaction(EndOperationTransactionArgs e) {
        //-------------------------------- 同步人员考评 begin --------------------------------
        //先查询人员对应考核周期
        for (DynamicObject data : e.getDataEntities()) {
            int theYear = data.getInt(PerfRankMgmtConstant.NCKD_THEYEAR);
            int step = data.getInt(PerfRankMgmtConstant.NCKD_STEP);
            //当步骤为1时同步考核周期结果
            if(step == 1) {
                DynamicObjectCollection entryList = data.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);

                List<Long> personIds = entryList.stream()
                        .map(entry -> entry.getDynamicObject(FormConstant.NCKD_PERSON))
                        .filter(Objects::nonNull)
                        .map(person -> person.getLong(FormConstant.ID_KEY))
                        .filter(id -> id > 0)
                        .collect(Collectors.toList());

                Map<Long, DynamicObject> personAppraisalMap = entryList.stream()
                        .filter(entry -> Objects.nonNull(entry.getDynamicObject(FormConstant.NCKD_PERSON)))
                        .filter(entry -> Objects.nonNull(entry.getDynamicObject(PerfRankMgmtConstant.NCKD_APPRAISALRESULT)))
                        .collect(Collectors.toMap(
                                entry -> entry.getDynamicObject(FormConstant.NCKD_PERSON).getLong(FormConstant.ID_KEY),
                                entry -> entry.getDynamicObject(PerfRankMgmtConstant.NCKD_APPRAISALRESULT)
                        ));


                List<Long> dbPersonIds = dbPersonMap.get(data.getLong(FormConstant.ID_KEY));
                // 找出在数据库中存在但在当前列表中不存在的人员ID（即被删除的人员）
                List<Long> deletedPersonIds = dbPersonIds.stream()
                        .filter(dbPersonId -> !personIds.contains(dbPersonId))
                        .collect(Collectors.toList());
                if(!deletedPersonIds.isEmpty()){
                    personIds.addAll(deletedPersonIds);
                }


                //获取考核周期
                List<Long> perfManagerIds = findPerfManager(theYear, personIds);
                QFilter filter = QFilterCommonHelper.getIdInFilter(perfManagerIds);
                MainEntityType dataEntityType = MetadataServiceHelper.getDataEntityType(PerfRankMgmtConstant.PERFMANAGER_ENTITYID);
                DynamicObject[] perfManagerArray = BusinessDataServiceHelper.load(perfManagerIds.toArray(new Long[0]), dataEntityType);
                LocalDate appraisalYearLocalDate = LocalDate.of(theYear, 1, 1);
                Date appraisalYearDate = DateUtil.toDate(appraisalYearLocalDate);

                for (DynamicObject perfManager : perfManagerArray) {
                    DynamicObject person = perfManager.getDynamicObject(FormConstant.NCKD_PERSON);
                    long personId = person.getLong(FormConstant.ID_KEY);
                    if(deletedPersonIds.contains(personId)){
                        //此次删除的人员同步删除人员考评的考核结果
                        DynamicObjectCollection perfManagerEntryColl = perfManager.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY);
                        Iterator<DynamicObject> iterator = perfManagerEntryColl.iterator();
                        while (iterator.hasNext()) {
                            DynamicObject perfManagerEntry = iterator.next();
                            LocalDateTime appraisalYear = DateUtil.toLocalDateTime(perfManagerEntry.getDate(PerfRankMgmtConstant.NCKD_APPRAISALYEAR));
                            int year = appraisalYear.getYear();
                            if(year == theYear){
                                iterator.remove();
                            }
                        }
                    }else{
                        DynamicObjectCollection perfManagerEntryColl = perfManager.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFMANAGERENTRY);
                        boolean isExist = false;
                        for (DynamicObject perfManagerEntry : perfManagerEntryColl) {
                            LocalDateTime appraisalYear = DateUtil.toLocalDateTime(perfManagerEntry.getDate(PerfRankMgmtConstant.NCKD_APPRAISALYEAR));
                            int year = appraisalYear.getYear();
                            if(year == theYear){
                                perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALRESULT, personAppraisalMap.get(personId));
                                isExist = true;
                                break;
                            }
                        }
                        if(!isExist){
                            DynamicObject perfManagerEntry = perfManagerEntryColl.addNew();
                            perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALYEAR,appraisalYearDate);
                            perfManagerEntry.set(PerfRankMgmtConstant.NCKD_APPRAISALRESULT, personAppraisalMap.get(personId));
                            perfManagerEntry.set(PerfRankMgmtConstant.NCKD_ISALLRANKSOURCE, EnableEnum.YES.getCode());
                        }
                    }

                }
                OperateOption option = OperateOption.create();
                option.setVariableValue(OperateOptionConst.IGNOREINTERACTION, Boolean.TRUE+"");
                //告诉OP此次操作类型
                option.setVariableValue("isUpdate", Boolean.TRUE+"");
                OperationResult operationResult = SaveServiceHelper.saveOperate(FormConstant.SAVE_OP, PerfRankMgmtConstant.PERFMANAGER_ENTITYID, perfManagerArray, option);
                if (!operationResult.isSuccess()) {
                    StringJoiner errorMsgJoiner = new StringJoiner(StrFormatter.LINE_SEPARATOR);
                    for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
                        errorMsgJoiner.add(error.getMessage());
                    }
                    String errorMsg = errorMsgJoiner.toString();
                    if(StringUtils.isBlank(errorMsg)){
                        errorMsg = operationResult.getMessage();
                    }
                    throw new ValidationException("保存失败，原因：同步考核周期结果失败。\r\n"+errorMsg);
                }
            }
        }
        //-------------------------------- 同步人员考评 end --------------------------------
    }





    /**
     * 根据人员和年度查询人员考核周期
     * @param theYear 年份
     * @param personIds 人员ID
     * @return: java.util.List<java.lang.Long>
     * @author W.Y.C
     * @date: 2025/11/12 22:10
     */
    private List<Long> findPerfManager(int theYear,List<Long> personIds) {
        //根据年度校验人员只能在同一个组
        LocalDate startDate = LocalDate.of(theYear, 1, 1);
        QFilter filter = new QFilter(PerfRankMgmtConstant.NCKD_PERSON, QCP.in, personIds);
        filter.and(PerfRankMgmtConstant.NCKD_BEGINYEAR,QCP.less_equals,startDate);
        filter.and(PerfRankMgmtConstant.NCKD_ENDYEAR,QCP.large_equals,startDate);
        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                .add(FormConstant.ID_KEY);
        DynamicObjectCollection query = QueryServiceHelper.query(PerfRankMgmtConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
        List<Long> ids = query.stream()
                .map(obj -> obj.getLong(FormConstant.ID_KEY))
                .collect(Collectors.toList());
        return ids;
    }
}