package nckd.jxccl.opmc.pm.plugin.form.print;

import kd.bos.algo.Algo;
import kd.bos.algo.AlgoContext;
import kd.bos.algo.DataSet;
import kd.bos.algo.GroupbyDataSet;
import kd.bos.algo.Row;
import kd.bos.common.enums.EnableEnum;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.entity.plugin.args.CustomPrintDataEntitiesArgs;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.print.core.data.DataRowSet;
import kd.bos.print.core.data.datasource.CustomDataSource;
import kd.bos.print.core.data.datasource.MainDataSource;
import kd.bos.print.core.data.datasource.PrtDataSource;
import kd.bos.print.core.data.field.CollectionField;
import kd.bos.print.core.data.field.Field;
import kd.bos.print.core.data.field.IntegerField;
import kd.bos.print.core.plugin.AbstractPrintPlugin;
import kd.bos.print.core.plugin.event.AfterLoadDataEvent;
import kd.bos.print.core.plugin.event.CustomDataLoadEvent;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.hr.hbp.common.cache.HRAppCache;
import kd.sdk.plugin.Plugin;
import nckd.jxccl.base.common.algo.GroupMaxStrFunction;
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 java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 绩效结果打印
* @author W.Y.C
* @date 2026/1/6 15:15
* @version 1.0
*/
public class EmployeePrintPlugin extends AbstractPrintPlugin implements Plugin {

    //记录主数据源
    private MainDataSource mainDataSource;

    @Override
    public void loadCustomData(CustomDataLoadEvent evt) {
        Date printYear = HRAppCache.get("nckd_pm").get("printYear", Date.class);

        // 1. 获取数据源标识
        CustomDataSource dataSource = evt.getDataSource();
        if (!"custom".equals(dataSource.getDsName())) {
            return;
        }

        // 2. 获取或创建数据结果集
        List<DataRowSet> customRows = evt.getCustomDataRows();

        // 3. 组装数据（例如：从数据库查询、计算衍生字段等）

        DataRowSet rowSet = new DataRowSet();
        rowSet.put("year", new IntegerField(DateUtil.getYear(printYear)));
        int printYearValue = DateUtil.getYear(printYear);
        rowSet.put("yearIndex", new IntegerField(getYearIndexFromPrintYear(printYearValue)));

        // 4. 将数据添加到结果集
        customRows.add(rowSet);
        evt.setDataSource(dataSource);
    }

    /**
     * 根据年份获取对应的序号，近5年（以当前年份为基准）的序号分别为5/4/3/2/1
     * 例如：当前年是2026，printYear 为2025，则序号为5（上年）
     * @param year 年份
     * @return 序号，最近的年份序号为5，依次递减
     */
    private int getYearIndexFromPrintYear(int year) {
        int currentYear = LocalDate.now().getYear();

        // 计算最近5年的范围，即从当前年份往前推5年到前1年（不包含当前年）
        // 例如：当前年是2026年，最近5年是2021-2025，即 [2021, 2022, 2023, 2024, 2025]
        int startYear = currentYear - 5; // 最早的年份
        int endYear = currentYear - 1;   // 最近的年份

        // 检查年份是否在最近5年范围内
        if (year >= startYear && year <= endYear) {
            // 计算序号：最近的年份（endYear）序号为5，前一年为4，以此类推
            // 序号 = (year - startYear) + 1
            // 例如：当前年是2026年，startYear=2021，endYear=2025
            // 2025 (最近): 2025 - 2021 + 1 = 5 ✓
            // 2024: 2024 - 2021 + 1 = 4 ✓
            // 2023: 2023 - 2021 + 1 = 3 ✓
            // 2022: 2022 - 2021 + 1 = 2 ✓
            // 2021 (最远): 2021 - 2021 + 1 = 1 ✓
            return year - startYear + 1;
        } else {
            // 如果不在最近5年内，返回0表示超出范围
            return 0;
        }
    }

    @Override
    public void afterLoadData(AfterLoadDataEvent evt) {
        PrtDataSource dataSource = evt.getDataSource();
        if(!(dataSource instanceof MainDataSource)){
            return;//非主数据源，立即返回
        }
        //记录主数据源，用于自定义数据源查询时，获取需要的信息
        mainDataSource = (MainDataSource) dataSource;
        Date printYear = HRAppCache.get("nckd_pm").get("printYear", Date.class);
        Map<Integer, Long> selectPrintPersonIdMap = HRAppCache.get("nckd_pm").get("employeePrintIdMap", Map.class);
        if(selectPrintPersonIdMap == null){
            throw new ValidationException("请选择要打印的日期！");
        }
        List<String> seqs = ConvertUtil.toList(selectPrintPersonIdMap.keySet(), ArrayList::new);
        LocalDate now = LocalDate.now();
        // 获取5年前的年份
        int fiveYearsAgo = LocalDate.now().minusYears(5).getYear();
        Date beginDate = DateUtil.toDate(LocalDate.of(fiveYearsAgo, 1, 1));

        int currentYear = LocalDate.now().getYear() - 1; // 不包含今年
        Date endDate = DateUtil.toDate(LocalDate.of(currentYear, 1, 1));

        Map<String, String> positionMap = new HashMap<>();
        Map<String, Integer> perfRankMgmtMap = new HashMap<>();
        try (AlgoContext context = Algo.newContext()) {
            Collection<Long> personIds = selectPrintPersonIdMap.values();
            DataSet positionDateSet = getPositions(fiveYearsAgo, currentYear, personIds);
            if (positionDateSet != null) {
                while (positionDateSet.hasNext()) {
                    Row next = positionDateSet.next();
                    Long personId = next.getLong(String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY));
                    int tempIndex = 1;
                    for (int year = fiveYearsAgo; year <= currentYear; year++) {
                        String positionName = next.getString("position_" + tempIndex);
                        positionMap.put(personId + "nckd_position_" + tempIndex, positionName);
                        tempIndex++;
                    }
                }
            }

            DataSet perfRankMgmtDataSet = getPerfRankMgmt(personIds, fiveYearsAgo, currentYear);
            if (perfRankMgmtDataSet != null) {
                while (perfRankMgmtDataSet.hasNext()) {
                    Row next = perfRankMgmtDataSet.next();
                    Long personId = next.getLong(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY));
                    int tempIndex = 1;
                    for (int year = fiveYearsAgo; year <= currentYear; year++) {
                        Integer topran = next.getInteger("perfrank_topran_" + tempIndex);
                        Integer topranks = next.getInteger("perfrank_topranks_" + tempIndex);
                        perfRankMgmtMap.put(personId + "nckd_perfrank_topran_" + tempIndex, topran);
                        perfRankMgmtMap.put(personId + "nckd_perfrank_topranks_" + tempIndex, topranks);
                        tempIndex++;
                    }
                }
            }
        }


        // 获取当前打印的数据集并准备过滤后的集合
        // 2. 获取当前打印的数据集
        List<DataRowSet> dataRowSets = evt.getDataRowSets();
        List<DataRowSet> filteredDataRowSets = new ArrayList<>();

        for (DataRowSet dataRowSet : dataRowSets) {
            if (dataRowSet.containerKey("reportEntry")) {
                CollectionField entryField = (CollectionField) dataRowSet.getField("reportEntry");
                List<DataRowSet> entryRows = entryField.getValue();
                List<DataRowSet> filteredEntryRows = new ArrayList<>();
                for (DataRowSet entryRow : entryRows) {
                    String seq = ConvertUtil.toStr(entryRow.getField(FormConstant.SEQ_KEY).getValue());
                    Long personId = selectPrintPersonIdMap.get(seq + "");
                    // 判断该分录行是否在用户勾选的列表中
                    if (seqs.contains(seq)) {
                        for (String fieldKey : entryRow.getFieldKeys()) {
                            if (fieldKey.startsWith("nckd_position_")) {
                                String positionName = positionMap.get(personId + fieldKey);
                                Field field = entryRow.getField(fieldKey);
                                field.setValue(positionName != null ? positionName : "");
                                entryRow.put(fieldKey, field);
                            }
                            if (fieldKey.startsWith("nckd_perfrank_topran_")) {
                                Integer perfRankMgmt = perfRankMgmtMap.get(personId + fieldKey);
                                Field field = entryRow.getField(fieldKey);
                                field.setValue(perfRankMgmt != null ? perfRankMgmt : 0);
                                entryRow.put(fieldKey, field);
                            }
                            if (fieldKey.startsWith("nckd_perfrank_topranks_")) {
                                Integer perfRankMgmt = perfRankMgmtMap.get(personId + fieldKey);
                                Field field = entryRow.getField(fieldKey);
                                field.setValue(perfRankMgmt != null ? perfRankMgmt : 0);
                                entryRow.put(fieldKey, field);
                            }
                        }
                        filteredEntryRows.add(entryRow);
                    }

                }
                // 用过滤后的分录数据替换原数据
                if (!filteredEntryRows.isEmpty()) {
                    DataRowSet newDataRowSet = dataRowSet.deepCopy(); // 深拷贝，避免影响原数据
                    newDataRowSet.put("reportEntry", new CollectionField(filteredEntryRows));
                    filteredDataRowSets.add(newDataRowSet);
                }
            }
        }

        // 将过滤后的数据集设置回事件，实现只打印勾选行
        evt.setDataRowSets(filteredDataRowSets);

    }


    private static DataSet getPerfRankMgmt(Collection<Long> personIds, int beginYear, int endYear) {
        // 年度绩效排名管理
        QueryFieldBuilder perfRankMgmtFieldBuilder = QueryFieldBuilder.create()
                .addIdNumberName(FormConstant.NCKD_PERSON)
                .add("nckd_toprank")
                .addGroup(new String[]{"nckd_perfrankmgmt"},"nckd_topranks","nckd_theyear");
        QFilter perfRankMgmtFilter = new QFilter("nckd_isranking", "=", EnableEnum.YES.getCode())
                .and(FormConstant.NCKD_PERSON, QCP.in, personIds)
                .and("nckd_perfrankmgmt.nckd_theyear",QCP.large_equals, beginYear)
                .and("nckd_perfrankmgmt.nckd_theyear",QCP.less_equals, endYear);
        DataSet perfRankMgmtDataSet = QueryServiceHelper.queryDataSet("PrintPerfDetailReportListDataPlugin_perfRank", "nckd_perfrankmgmtentry", perfRankMgmtFieldBuilder.buildSelect(), new QFilter[]{perfRankMgmtFilter}, perfRankMgmtFieldBuilder.buildOrder(), 10000);
        int tempIndex = 1;
        for (int year = beginYear; year <= endYear; year++) {
            //排名
            String toprankField = "CASE WHEN nckd_perfrankmgmt.nckd_theyear = "+year+" THEN nckd_toprank ELSE null END";
            perfRankMgmtDataSet = perfRankMgmtDataSet.addField(toprankField, "perfrankmgmt_topran_temp_" + tempIndex);
            //总人数
            String topranksField = "CASE WHEN nckd_perfrankmgmt.nckd_theyear = "+year+" THEN nckd_perfrankmgmt.nckd_topranks ELSE null END";
            perfRankMgmtDataSet = perfRankMgmtDataSet.addField(topranksField, "perfrankmgmt_topranks_temp_" + tempIndex);
            tempIndex++;
        }
        GroupbyDataSet groupbyDataSet = perfRankMgmtDataSet.groupBy(new String[]{String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY)});
        tempIndex = 1;
        for (int year = beginYear; year <= endYear; year++) {
            groupbyDataSet.max("perfrankmgmt_topran_temp_"+tempIndex, "perfrank_topran_"+tempIndex);
            groupbyDataSet.max("perfrankmgmt_topranks_temp_"+tempIndex, "perfrank_topranks_"+tempIndex);
            tempIndex++;
        }
        return groupbyDataSet.finish();
    }


    /**
     * 获取近N年的岗位信息
     * 用于查询每个员工在指定年份范围内每年年底（12月31日）所在的有效岗位
     * 当一个员工在同一年有多个有效岗位时，选择结束日期最晚的那个岗位
     *
     * @param beginYear 起始年份（包含）
     * @param endYear   结束年份（包含）
     * @return 包含每个员工每年岗位信息的数据集
     */
    private DataSet getPositions(int beginYear,int endYear,Collection<Long> personIds){
        // 查询全职任职关系，获取员工、岗位、任职起止时间等信息
        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                .add(FormConstant.STARTDATE)  // 任职开始日期
                .add(FormConstant.ENDDATE)    // 任职结束日期
                .addIdNumberName(FormConstant.POSITION_KEY)  // 岗位信息（ID、编码、名称）
                .addIdNumberNameWithExtras(new String[]{FormConstant.EMPLOYEE_KEY},FormConstant.EMP_NUMBER_KEY)  // 员工信息（ID、编码、姓名）+ 工号
                .orderDesc(FormConstant.EMPLOYEE_KEY,FormConstant.STARTDATE);  // 按员工ID和开始日期降序排列
        // 筛选条件：只查询全职任职（IS_PRIMARY = YES）
        QFilter qFilter = new QFilter(FormConstant.IS_PRIMARY,QCP.equals, EnableEnum.YES.getCode());
        if(!personIds.isEmpty()){
            qFilter = new QFilter(FormConstant.EMPLOYEE_KEY,QCP.in,personIds.toArray());
        }
        DataSet dataSet = QueryServiceHelper.queryDataSet("PrintPerfDetailReportListDataPlugin_EMPREL", FormConstant.HRPI_EMPPOSORGREL, queryFieldBuilder.buildSelect(), new QFilter[]{qFilter}, queryFieldBuilder.buildOrder(), 1000000);

        int tempIndex = 1;
        // 遍历指定年份范围，为每一年生成对应的岗位查询字段
        for (int year = beginYear; year <= endYear; year++) {
            // 获取每年12-31 23:59:59作为目标日期，用于判断该员工当年年底的岗位状态
            Date targetDate = DateUtil.toDate(LocalDateTime.of(year, 12, 31, 23, 59, 59));
            String targetDateStr = DateUtil.format(targetDate, DateUtil.NORM_DATE_PATTERN); // 使用日期格式而非日期时间格式

            // 创建复合字段：如果在目标日期员工处于有效任职状态，则生成"结束日期|岗位名称"格式的字符串
            // 这样使用GroupMaxStrFunction时，会根据结束日期选择最晚的那个任职记录
            //为什么用“00000000000000|”，不用null。因为当GroupMaxStrFunction进行字符串比较时，有效的日期值（如'20231231235959|经济技术部部长'）会比'00000000000000|'大，从而被正确选择
            String combinedField = "CASE WHEN " + FormConstant.STARTDATE + " <= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
                    "AND " + FormConstant.ENDDATE + " >= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
                    "THEN CONCAT(TO_CHAR(" + FormConstant.ENDDATE + ", 'YYYYMMDDHHmmss'), '|', " +
                    String.join(".", FormConstant.POSITION_KEY, FormConstant.NAME_KEY) + ") ELSE '00000000000000|' END";

            // 添加岗位复合字段（包含结束日期和岗位名称）
            dataSet = dataSet.addField(combinedField, "position_temp_" + tempIndex);

            // 同时创建仅包含日期部分的字段，用于后续解析时去除日期部分，只保留岗位名称
            String dateField = "CASE WHEN " + FormConstant.STARTDATE + " <= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
                    "AND " + FormConstant.ENDDATE + " >= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
                    "THEN CONCAT(TO_CHAR(" + FormConstant.ENDDATE + ", 'YYYYMMDDHHmmss'),'|') ELSE '00000000000000|' END";
            dataSet = dataSet.addField(dateField, "position_date_" + tempIndex);

//            dataSet = dataSet.addField("'"+year+"'", "position_year_" + tempIndex);
            tempIndex++;
        }

        // 行转列处理：按员工ID分组，使用GroupMaxStrFunction获取每个员工每年结束日期最晚的任职记录
        tempIndex = 1;
        GroupMaxStrFunction groupMaxStr = new GroupMaxStrFunction();
        // 按员工ID进行分组聚合
        GroupbyDataSet groupbyDataSet = dataSet.groupBy(new String[]{String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)});
        // 对每一年的数据进行聚合，获取结束日期最晚的任职记录
        for (int year = beginYear; year <= endYear; year++) {
            // 获取岗位复合字段的最大值（即结束日期最晚的记录）
            groupbyDataSet.agg(new GroupMaxStrFunction(),"position_temp_"+tempIndex, "position_max_"+tempIndex);
            // 同时获取日期字段的最大值，用于后续解析
            groupbyDataSet.agg(groupMaxStr,"position_date_"+tempIndex, "position_date_max_"+tempIndex);
            tempIndex++;
        }
        DataSet result = groupbyDataSet.finish();

        // 解析复合字段，提取真正的岗位名称
        // 通过去除日期部分（YYYYMMDDHHmmss|）来获取原始的岗位名称
        tempIndex = 1;
        for (int year = beginYear; year <= endYear; year++) {
            final int currentYearIndex = year - beginYear + 1;
            result = result.addField(
                    // 如果岗位字段有效（不为默认值'00000000000000|'），则去除日期部分，只保留岗位名称
                    "CASE WHEN position_max_" + tempIndex + " IS NOT NULL AND position_max_" + tempIndex + " != '00000000000000|' THEN " +
                            "REPLACE(position_max_" + tempIndex + ",position_date_max_"+tempIndex+",'') " +  // 去除日期部分，得到岗位名称
                            "ELSE null END",
                    "position_" + tempIndex  // 最终的岗位名称字段
            );
            tempIndex++;
        }
        return result;
    }
}