package com.kingdee.eas.hr.emp.web.handler.wordtemplate.service.impl;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.eas.hr.base.SqlParam;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.hr.emp.web.handler.wordtemplate.service.ResumeWordTemplateService;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.shr.baseconfig.StructureConfigColumnsInfo;
import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
import com.kingdee.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 员工履历 Word 导出 — 服务层二开扩展。
 * coyle
 * 202605
 *   PersonFamily：按 familyRelation.number（基础资料编码 FNumber）升序排序
 *   ygzzk（年度考核结果）：按 kaoheshij 降序取最新 3 条，升序合并为单行；考核时间展示为 yyyy年
 */
public class ResumeWordTemplateServiceImplEx extends ResumeWordTemplateServiceImpl {

    private static final Logger LOGGER = LoggerFactory.getLogger(ResumeWordTemplateServiceImplEx.class);

    private static final String PERSON_FAMILY_ENTITY = "PERSONFAMILY";
    private static final String PERSON_FAMILY_SORT_FIELD = "familyRelation.number";

    /** 年度考核结果表体（结构配置 clientNumber） ygzzk */
    private static final String YGZZK_ENTITY = "YGZZK";
    private static final String YGZZK_SORT_FIELD = "kaoheshij";
    private static final int YGZZK_ROW_LIMIT = 3;
    private static final String YGZZK_SEGMENT_SEPARATOR = ",";
    private static final String YGZZK_YEAR_SUFFIX = "年";

    /** 记录内字段拼接顺序（模板未出现的字段自动跳过） */
    private static final String[] YGZZK_FIELD_ORDER = {
            "kaoheshij",
            "kaohe2.name",
            "kaohezzwenb"
    };

    private static final String ROW_SORT_VALUE = "__sortValue";

    private static final int PERSON_FAMILY_ROW_LIMIT = 0;

    private static volatile ResumeWordTemplateService INSTANCE;

    public static ResumeWordTemplateService instance() {
        if (INSTANCE == null) {
            synchronized (ResumeWordTemplateServiceImplEx.class) {
                if (INSTANCE == null) {
                    INSTANCE = new ResumeWordTemplateServiceImplEx();
                }
            }
        }
        return INSTANCE;
    }

    @Override
    protected void rowHandle(
            Context ctx,
            SqlParam sqlParam,
            Map<String, String> selectKeyToWordKeyMap,
            Map<String, Object> resultMap,
            Map<String, StructureConfigColumnsInfo> columnsInfoMap
    ) throws EASBizException, BOSException, ShrWebBizException, SQLException {
        if (containsYgzzkEntity(sqlParam)) {
            prepareYgzzkSortBeforeQuery(sqlParam);
        } else if (containsPersonFamilyEntity(sqlParam)) {
            LOGGER.info("ResumeWordTemplateServiceImplEx.rowHandle: apply PersonFamily sort before query, field="
                    + PERSON_FAMILY_SORT_FIELD);
            preparePersonFamilySortBeforeQuery(sqlParam);
        }
        super.rowHandle(ctx, sqlParam, selectKeyToWordKeyMap, resultMap, columnsInfoMap);
    }

    @Override
    protected void sorterHandler(Context ctx, SqlParam param) {
        super.sorterHandler(ctx, param);
        if (containsYgzzkEntity(param)) {
            applyYgzzkSorter(param);
        } else {
            applyPersonFamilySorter(param);
        }
    }

    @Override
    protected void multiNotOne(
            IRowSet rowSet,
            Context ctx,
            SqlParam sqlParam,
            Map<String, String> selectKeyToWordKeyMap,
            Map<String, Object> resultMap,
            Map<String, StructureConfigColumnsInfo> columnsInfoMap
    ) throws SQLException {
        if (containsYgzzkEntity(sqlParam)) {
            handleYgzzkMultiNotOne(rowSet, ctx, sqlParam, selectKeyToWordKeyMap, resultMap, columnsInfoMap);
            return;
        }
        if (containsPersonFamilyEntity(sqlParam)) {
            handlePersonFamilyMultiNotOne(rowSet, ctx, sqlParam, selectKeyToWordKeyMap, resultMap, columnsInfoMap);
            return;
        }
        super.multiNotOne(rowSet, ctx, sqlParam, selectKeyToWordKeyMap, resultMap, columnsInfoMap);
    }

    private void handleYgzzkMultiNotOne(
            IRowSet rowSet,
            Context ctx,
            SqlParam sqlParam,
            Map<String, String> selectKeyToWordKeyMap,
            Map<String, Object> resultMap,
            Map<String, StructureConfigColumnsInfo> columnsInfoMap
    ) throws SQLException {
        String sortSelectKey = resolveSelectKeyByFieldSuffix(selectKeyToWordKeyMap, YGZZK_SORT_FIELD);
        List<String> orderedWordKeys = buildYgzzkOrderedWordKeys(selectKeyToWordKeyMap);
        List<Map<String, String>> rowList = new ArrayList<Map<String, String>>();

        while (rowSet.next()) {
            Map<String, String> rowData = new HashMap<String, String>();
            for (Map.Entry<String, String> entry : selectKeyToWordKeyMap.entrySet()) {
                String wordKey = entry.getValue();
                Object dbValue = rowSet.getObject(entry.getKey());
                String displayValue = dataTypeHandle(ctx, dbValue, columnsInfoMap.get(wordKey));
                if (matchesYgzzkFieldSuffix(entry.getKey(), YGZZK_SORT_FIELD)) {
                    displayValue = formatYgzzkKaoheshij(displayValue);
                }
                if (!StringUtils.isEmpty(displayValue)) {
                    rowData.put(wordKey, displayValue);
                }
            }
            if (sortSelectKey != null) {
                rowData.put(ROW_SORT_VALUE, resolveRowSortValue(rowSet, sortSelectKey));
            }
            if (!rowData.isEmpty()) {
                rowList.add(rowData);
            }
        }

        if (sortSelectKey != null) {
            sortRowListDesc(rowList);
            limitRowList(rowList, YGZZK_ROW_LIMIT);
            sortRowListAsc(rowList);
        } else {
            LOGGER.warn("ResumeWordTemplateServiceImplEx.handleYgzzkMultiNotOne: sortSelectKey missing for "
                    + YGZZK_SORT_FIELD);
            limitRowList(rowList, YGZZK_ROW_LIMIT);
        }

        String merged = mergeYgzzkSegments(rowList, orderedWordKeys);
        if (StringUtils.isEmpty(merged) || orderedWordKeys.isEmpty()) {
            return;
        }

        Map<String, String> singleRow = new HashMap<String, String>();
        String primaryWordKey = orderedWordKeys.get(0);
        singleRow.put(primaryWordKey, merged);
        resultMap.putAll(singleRow);

        LOGGER.info("ResumeWordTemplateServiceImplEx.handleYgzzkMultiNotOne: merged into wordKey="
                + primaryWordKey + ", value=[" + merged + "], sourceRows=" + rowList.size());
    }

    private void handlePersonFamilyMultiNotOne(
            IRowSet rowSet,
            Context ctx,
            SqlParam sqlParam,
            Map<String, String> selectKeyToWordKeyMap,
            Map<String, Object> resultMap,
            Map<String, StructureConfigColumnsInfo> columnsInfoMap
    ) throws SQLException {
        List<Map<String, String>> rowList = new ArrayList<Map<String, String>>();
        String entityKey = null;
        String sortSelectKey = resolveSortSelectKey(selectKeyToWordKeyMap, PERSON_FAMILY_SORT_FIELD);
        boolean sortInMemory = sortSelectKey != null;

        while (rowSet.next()) {
            Map<String, String> rowData = new HashMap<String, String>();
            for (Map.Entry<String, String> entry : selectKeyToWordKeyMap.entrySet()) {
                String wordKey = entry.getValue();
                Object dbValue = rowSet.getObject(entry.getKey());
                String displayValue = dataTypeHandle(
                        ctx,
                        dbValue,
                        columnsInfoMap.get(wordKey)
                );
                if (!StringUtils.isEmpty(displayValue)) {
                    rowData.put(wordKey, displayValue);
                }
                if (StringUtils.isEmpty(entityKey)) {
                    int splitIndex = wordKey.indexOf('_');
                    if (splitIndex > 0) {
                        entityKey = wordKey.substring(0, splitIndex);
                    }
                }
            }
            if (sortInMemory) {
                rowData.put(ROW_SORT_VALUE, resolveRowSortValue(rowSet, sortSelectKey));
            }
            if (rowData.size() > 0) {
                rowList.add(rowData);
            }
        }

        if (sortInMemory) {
            sortRowListAsc(rowList);
            logSortPreview(rowList);
            for (Map<String, String> rowData : rowList) {
                rowData.remove(ROW_SORT_VALUE);
            }
        } else {
            LOGGER.warn("ResumeWordTemplateServiceImplEx.multiNotOne: PersonFamily detected but sortSelectKey missing, "
                    + "entityKey=" + entityKey);
        }

        applyPersonFamilyRowLimit(entityKey, rowList);

        if (rowList.size() > 1) {
            resultMap.put(entityKey, rowList);
        } else if (rowList.size() == 1) {
            resultMap.putAll(rowList.get(0));
        }
    }

    private void preparePersonFamilySortBeforeQuery(SqlParam param) {
        applyPersonFamilySorter(param);
    }

    private void prepareYgzzkSortBeforeQuery(SqlParam param) {
        applyYgzzkSorter(param);
    }

    private void applyYgzzkSorter(SqlParam param) {
        if (!containsYgzzkEntity(param)) {
            return;
        }
        String sortField = YGZZK_ENTITY.toLowerCase() + "." + YGZZK_SORT_FIELD;
        param.setSortStr(sortField + " desc");
        addSortFieldToSelectMapping(param.getSelectMapping(), sortField);
        LOGGER.info("ResumeWordTemplateServiceImplEx: ygzzk sortStr=" + param.getSortStr());
    }

    private void applyPersonFamilySorter(SqlParam param) {
        if (!containsPersonFamilyEntity(param)) {
            return;
        }
        param.setSortStr(PERSON_FAMILY_SORT_FIELD + " asc");
        addSortFieldToSelectMapping(param.getSelectMapping(), PERSON_FAMILY_SORT_FIELD);
        LOGGER.info("ResumeWordTemplateServiceImplEx: sortStr=" + param.getSortStr());
    }

    private boolean containsYgzzkEntity(SqlParam param) {
        if (containsEntity(param.getInfoCtr(), YGZZK_ENTITY)) {
            return true;
        }
        Map<String, String> selectMapping = param.getSelectMapping();
        if (selectMapping == null) {
            return false;
        }
        for (String key : selectMapping.keySet()) {
            if (isYgzzkQuerySelectKey(key)) {
                return true;
            }
        }
        return false;
    }

    /**
     * ygzzk 主表字段以 YGZZK. 开头；关联字段如 kaohe2.name、kaohezzwenb 为独立 clientNumber，不在此前缀下。
     */
    private boolean isYgzzkQuerySelectKey(String selectKey) {
        if (selectKey == null) {
            return false;
        }
        if (selectKey.toUpperCase().startsWith(YGZZK_ENTITY + ".")) {
            return true;
        }
        for (int i = 0; i < YGZZK_FIELD_ORDER.length; i++) {
            if (matchesYgzzkFieldSuffix(selectKey, YGZZK_FIELD_ORDER[i])) {
                return true;
            }
        }
        return false;
    }

    private boolean matchesYgzzkFieldSuffix(String selectKey, String fieldSuffix) {
        if (selectKey == null || fieldSuffix == null) {
            return false;
        }
        if (selectKey.equalsIgnoreCase(fieldSuffix)) {
            return true;
        }
        return selectKey.toUpperCase().endsWith("." + fieldSuffix.toUpperCase());
    }

    private List<String> buildYgzzkOrderedWordKeys(Map<String, String> selectKeyToWordKeyMap) {
        List<String> orderedSelectKeys = new ArrayList<String>();
        for (int i = 0; i < YGZZK_FIELD_ORDER.length; i++) {
            appendMatchingSelectKeys(orderedSelectKeys, selectKeyToWordKeyMap, YGZZK_FIELD_ORDER[i]);
        }
        if (selectKeyToWordKeyMap != null) {
            for (String selectKey : selectKeyToWordKeyMap.keySet()) {
                if (!orderedSelectKeys.contains(selectKey)) {
                    orderedSelectKeys.add(selectKey);
                }
            }
        }
        List<String> orderedWordKeys = new ArrayList<String>();
        for (int i = 0; i < orderedSelectKeys.size(); i++) {
            String wordKey = selectKeyToWordKeyMap.get(orderedSelectKeys.get(i));
            if (wordKey != null && !orderedWordKeys.contains(wordKey)) {
                orderedWordKeys.add(wordKey);
            }
        }
        return orderedWordKeys;
    }

    private void appendMatchingSelectKeys(
            List<String> orderedSelectKeys,
            Map<String, String> selectKeyToWordKeyMap,
            String fieldSuffix
    ) {
        if (selectKeyToWordKeyMap == null) {
            return;
        }
        for (String selectKey : selectKeyToWordKeyMap.keySet()) {
            if (matchesYgzzkFieldSuffix(selectKey, fieldSuffix) && !orderedSelectKeys.contains(selectKey)) {
                orderedSelectKeys.add(selectKey);
            }
        }
    }

    private String mergeYgzzkSegments(List<Map<String, String>> rowList, List<String> orderedWordKeys) {
        if (rowList == null || rowList.isEmpty() || orderedWordKeys == null || orderedWordKeys.isEmpty()) {
            return "";
        }
        StringBuilder merged = new StringBuilder();
        for (int i = 0; i < rowList.size(); i++) {
            String segment = buildYgzzkRecordSegment(rowList.get(i), orderedWordKeys);
            if (StringUtils.isEmpty(segment)) {
                continue;
            }
            if (merged.length() > 0) {
                merged.append(YGZZK_SEGMENT_SEPARATOR);
            }
            merged.append(segment);
        }
        return merged.toString();
    }

    private String buildYgzzkRecordSegment(Map<String, String> rowData, List<String> orderedWordKeys) {
        if (rowData == null || orderedWordKeys == null) {
            return "";
        }
        StringBuilder segment = new StringBuilder();
        for (int i = 0; i < orderedWordKeys.size(); i++) {
            String value = rowData.get(orderedWordKeys.get(i));
            if (!StringUtils.isEmpty(value)) {
                segment.append(value);
            }
        }
        return segment.toString();
    }

    /** 考核时间合并展示：仅保留 yyyy，并追加「年」，如 2026年 */
    private String formatYgzzkKaoheshij(String displayValue) {
        if (StringUtils.isEmpty(displayValue)) {
            return displayValue;
        }
        String trimmed = displayValue.trim();
        if (trimmed.endsWith(YGZZK_YEAR_SUFFIX) && trimmed.length() >= 5) {
            String yearPart = trimmed.substring(0, trimmed.length() - YGZZK_YEAR_SUFFIX.length());
            if (yearPart.length() == 4 && isFourDigitYear(yearPart)) {
                return trimmed;
            }
        }
        String year = extractFourDigitYear(trimmed);
        if (year != null) {
            return year + YGZZK_YEAR_SUFFIX;
        }
        return trimmed;
    }

    private String extractFourDigitYear(String text) {
        StringBuilder year = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            char ch = text.charAt(i);
            if (ch >= '0' && ch <= '9') {
                year.append(ch);
                if (year.length() == 4) {
                    return year.toString();
                }
            } else if (year.length() > 0) {
                break;
            }
        }
        return year.length() == 4 ? year.toString() : null;
    }

    private boolean isFourDigitYear(String year) {
        if (year == null || year.length() != 4) {
            return false;
        }
        for (int i = 0; i < 4; i++) {
            char ch = year.charAt(i);
            if (ch < '0' || ch > '9') {
                return false;
            }
        }
        return true;
    }

    private boolean containsPersonFamilyEntity(SqlParam param) {
        if (containsEntity(param.getInfoCtr(), PERSON_FAMILY_ENTITY)) {
            return true;
        }
        Map<String, String> selectMapping = param.getSelectMapping();
        if (selectMapping == null) {
            return false;
        }
        for (String key : selectMapping.keySet()) {
            if (isPersonFamilyFieldKey(key)) {
                return true;
            }
        }
        return false;
    }

    private boolean isPersonFamilyFieldKey(String key) {
        if (key == null) {
            return false;
        }
        return key.toUpperCase().startsWith(PERSON_FAMILY_ENTITY + ".");
    }

    private boolean isPersonFamilyEntityKey(String entityKey) {
        return entityKey != null && PERSON_FAMILY_ENTITY.equalsIgnoreCase(entityKey);
    }

    private boolean containsEntity(Map infoCtr, String entityName) {
        if (infoCtr == null || StringUtils.isEmpty(entityName)) {
            return false;
        }
        if (infoCtr.containsKey(entityName) || infoCtr.containsKey(entityName.toUpperCase())) {
            return true;
        }
        for (Object key : infoCtr.keySet()) {
            if (entityName.equalsIgnoreCase(String.valueOf(key))) {
                return true;
            }
        }
        return false;
    }

    private void addSortFieldToSelectMapping(Map<String, String> selectMapping, String sortField) {
        if (StringUtils.isEmpty(sortField) || selectMapping == null) {
            return;
        }
        if (!containsKeyIgnoreCase(selectMapping, sortField)) {
            selectMapping.put(sortField, sortField);
        }
    }

    private String resolveSortSelectKey(Map<String, String> selectKeyToWordKeyMap, String sortField) {
        return resolveSelectKeyByFieldSuffix(selectKeyToWordKeyMap, sortField);
    }

    private String resolveSelectKeyByFieldSuffix(Map<String, String> selectKeyToWordKeyMap, String fieldSuffix) {
        if (selectKeyToWordKeyMap == null || StringUtils.isEmpty(fieldSuffix)) {
            return null;
        }
        for (String key : selectKeyToWordKeyMap.keySet()) {
            if (key != null && key.equalsIgnoreCase(fieldSuffix)) {
                return key;
            }
        }
        String dottedSuffix = "." + fieldSuffix;
        for (String key : selectKeyToWordKeyMap.keySet()) {
            if (key != null && key.toUpperCase().endsWith(dottedSuffix.toUpperCase())) {
                return key;
            }
        }
        if (fieldSuffix.toUpperCase().endsWith(".NUMBER")) {
            for (String key : selectKeyToWordKeyMap.keySet()) {
                if (key != null && key.toUpperCase().endsWith(".NUMBER")) {
                    return key;
                }
            }
        }
        return null;
    }

    private String resolveRowSortValue(IRowSet rowSet, String sortSelectKey) throws SQLException {
        if (!StringUtils.isEmpty(sortSelectKey)) {
            Object value = rowSet.getObject(sortSelectKey);
            if (value != null && !StringUtils.isEmpty(String.valueOf(value))) {
                return String.valueOf(value).trim();
            }
        }
        return "";
    }

    private void logSortPreview(List<Map<String, String>> rowList) {
        if (rowList == null || rowList.isEmpty()) {
            return;
        }
        StringBuilder preview = new StringBuilder();
        for (Map<String, String> row : rowList) {
            if (preview.length() > 0) {
                preview.append(" | ");
            }
            preview.append(row.get(ROW_SORT_VALUE));
        }
        LOGGER.info("ResumeWordTemplateServiceImplEx.multiNotOne: sorted by " + PERSON_FAMILY_SORT_FIELD
                + ", sortValues=[" + preview + "], count=" + rowList.size());
    }

    private void sortRowListAsc(List<Map<String, String>> rowList) {
        sortRowList(rowList, false);
    }

    private void sortRowListDesc(List<Map<String, String>> rowList) {
        sortRowList(rowList, true);
    }

    private void sortRowList(List<Map<String, String>> rowList, boolean descending) {
        if (rowList == null || rowList.size() <= 1) {
            return;
        }
        Collections.sort(rowList, new Comparator<Map<String, String>>() {
            @Override
            public int compare(Map<String, String> left, Map<String, String> right) {
                String leftValue = left.get(ROW_SORT_VALUE);
                String rightValue = right.get(ROW_SORT_VALUE);
                if (leftValue == null) {
                    leftValue = "";
                }
                if (rightValue == null) {
                    rightValue = "";
                }
                int result = leftValue.compareTo(rightValue);
                return descending ? -result : result;
            }
        });
    }

    private void limitRowList(List<Map<String, String>> rowList, int limit) {
        if (limit <= 0 || rowList == null || rowList.size() <= limit) {
            return;
        }
        rowList.subList(limit, rowList.size()).clear();
    }

    private void applyPersonFamilyRowLimit(String entityKey, List<Map<String, String>> rowList) {
        if (PERSON_FAMILY_ROW_LIMIT <= 0 || rowList == null || rowList.isEmpty()) {
            return;
        }
        if (!isPersonFamilyEntityKey(entityKey)) {
            return;
        }
        limitRowList(rowList, PERSON_FAMILY_ROW_LIMIT);
    }
}
