package com.njcn.gather.icd.mapping.component;

import com.njcn.gather.icd.mapping.pojo.param.BuildIndexSelectionRequest;
import com.njcn.gather.icd.mapping.pojo.param.ConfirmedIndexGroupRequest;
import com.njcn.gather.icd.mapping.pojo.param.ConfirmedLabelItemRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexCandidateReportItemRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexCandidateRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexConfirmGroupRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexConfirmLabelItemRequest;
import com.njcn.gather.icd.mapping.pojo.param.IndexConfirmTargetRequest;
import com.njcn.gather.icd.mapping.pojo.vo.IndexBindingResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexConfirmGroupResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexConfirmLabelItemResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexConfirmTargetResponse;
import com.njcn.gather.icd.mapping.pojo.vo.IndexSelectionGroupResponse;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ICD 结构确认弹窗编排服务。
 * 第一阶段：把 indexCandidates 整理成前端可确认的 label 级模型。
 * 第二阶段：根据前端确认结果展开为最终 indexSelection。
 */
@Service
public class IndexSelectionBuildService {

    private static final String GROUP_KEY_STATISTIC = "统计数据__DSSTATISTICDATA";
    private static final String GROUP_KEY_REALTIME = "实时数据__DSREALTIMEDATA";
    private static final String DATA_SET_STATISTIC_UNGROUPED = "dsStatisticData";
    private static final String DATA_SET_STATISTIC_INTER = "dsStIHarm";
    private static final String DATA_SET_REALTIME_UNGROUPED = "dsRealTimeData";
    private static final String DATA_SET_REALTIME_INTER = "dsRtIHarm";
    private static final String LABEL_REALTIME_INTER = "间谐波实时数据";

    private static final Comparator<IndexBindingResponse> INDEX_BINDING_COMPARATOR = (left, right) -> {
        int result = normalizeSortValue(left == null ? null : left.getReportName())
                .compareTo(normalizeSortValue(right == null ? null : right.getReportName()));
        if (result != 0) {
            return result;
        }
        result = normalizeSortValue(left == null ? null : left.getDataSetName())
                .compareTo(normalizeSortValue(right == null ? null : right.getDataSetName()));
        if (result != 0) {
            return result;
        }
        return compareLnInstValues(left == null ? null : left.getLnInst(), right == null ? null : right.getLnInst());
    };

    /**
     * 根据页面回传的 indexCandidates 生成弹窗确认模型。
     */
    public List<IndexConfirmGroupResponse> buildConfirmData(List<IndexCandidateRequest> indexCandidates) {
        if (indexCandidates == null || indexCandidates.isEmpty()) {
            return Collections.emptyList();
        }

        List<IndexConfirmGroupResponse> result = new ArrayList<IndexConfirmGroupResponse>();
        for (IndexCandidateRequest candidate : indexCandidates) {
            if (candidate == null) {
                continue;
            }

            IndexConfirmGroupResponse groupResponse = new IndexConfirmGroupResponse();
            groupResponse.setGroupKey(candidate.getGroupKey());
            groupResponse.setGroupDesc(candidate.getGroupDesc());

            if (candidate.getTemplateLabels() != null) {
                Set<String> uniqueLabels = new LinkedHashSet<String>(candidate.getTemplateLabels());
                for (String label : uniqueLabels) {
                    if (isBlank(label)) {
                        continue;
                    }

                    List<IndexCandidateReportItemRequest> targets = resolveTargets(candidate, label);
                    if (targets.isEmpty()) {
                        continue;
                    }

                    IndexConfirmLabelItemResponse labelItem = new IndexConfirmLabelItemResponse();
                    labelItem.setLabel(label);
                    labelItem.setRequired(false);
                    labelItem.setConfigurableOnce(true);

                    List<List<String>> targetLnInstLists = new ArrayList<List<String>>();
                    for (IndexCandidateReportItemRequest target : targets) {
                        IndexConfirmTargetResponse targetResponse = new IndexConfirmTargetResponse();
                        targetResponse.setReportName(target.getReportName());
                        targetResponse.setDataSetName(target.getDataSetName());
                        targetResponse.setReportDesc(target.getReportDesc());
                        List<String> labelSpecificValues = resolveAvailableLnInstValues(candidate, target, label);
                        targetResponse.getAvailableLnInstValues().addAll(labelSpecificValues);
                        targetLnInstLists.add(labelSpecificValues);
                        labelItem.getTargets().add(targetResponse);
                    }

                    List<String> commonLnInstValues = intersectLnInstValues(targetLnInstLists);
                    labelItem.getCommonLnInstValues().addAll(commonLnInstValues);
                    if (commonLnInstValues.size() == 1) {
                        labelItem.setDefaultLnInst(commonLnInstValues.get(0));
                    }
                    if (commonLnInstValues.isEmpty()) {
                        labelItem.setConfigurableOnce(false);
                    }

                    groupResponse.getLabelItems().add(labelItem);
                }
            }

            result.add(groupResponse);
        }
        return result;
    }

    /**
     * 根据确认模型和前端最终确认结果展开生成 indexSelection。
     */
    public List<IndexSelectionGroupResponse> buildIndexSelection(BuildIndexSelectionRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("请求体不能为空");
        }
        if (request.getConfirmData() == null || request.getConfirmData().isEmpty()) {
            throw new IllegalArgumentException("confirmData 不能为空");
        }

        Map<String, IndexConfirmGroupRequest> confirmGroupMap = toConfirmGroupMap(request.getConfirmData());
        Map<String, ConfirmedIndexGroupRequest> confirmedGroupMap = toConfirmedGroupMap(request.getConfirmedData());
        validateConfirmedGroups(confirmGroupMap, confirmedGroupMap);

        List<IndexSelectionGroupResponse> result = new ArrayList<IndexSelectionGroupResponse>();
        for (IndexConfirmGroupRequest confirmGroup : request.getConfirmData()) {
            if (confirmGroup == null || isBlank(confirmGroup.getGroupKey())) {
                continue;
            }

            ConfirmedIndexGroupRequest confirmedGroup = confirmedGroupMap.get(confirmGroup.getGroupKey());
            if (confirmedGroup == null) {
                continue;
            }

            Map<String, ConfirmedLabelItemRequest> confirmedLabelMap = toConfirmedLabelMap(confirmedGroup.getLabelItems());
            validateConfirmedLabels(confirmGroup, confirmedLabelMap);
            IndexSelectionGroupResponse selectionGroup = new IndexSelectionGroupResponse();
            selectionGroup.setGroupKey(confirmGroup.getGroupKey());
            selectionGroup.setGroupDesc(confirmGroup.getGroupDesc());

            if (confirmGroup.getLabelItems() != null) {
                for (IndexConfirmLabelItemRequest confirmLabel : confirmGroup.getLabelItems()) {
                    if (confirmLabel == null || isBlank(confirmLabel.getLabel())) {
                        continue;
                    }

                    ConfirmedLabelItemRequest confirmedLabel = confirmedLabelMap.get(confirmLabel.getLabel());
                    if (confirmedLabel == null || !confirmedLabel.isEnabled()) {
                        continue;
                    }

                    validateConfirmedLabel(confirmGroupMap, confirmGroup, confirmLabel, confirmedLabel);
                    expandBindings(selectionGroup, confirmLabel, confirmedLabel.getLnInst());
                }
            }

            if (!selectionGroup.getBindings().isEmpty()) {
                // 返回前统一排序，避免前端展示顺序受展开过程影响。
                selectionGroup.getBindings().sort(INDEX_BINDING_COMPARATOR);
                result.add(selectionGroup);
            }
        }
        return result;
    }

    private void validateConfirmedGroups(Map<String, IndexConfirmGroupRequest> confirmGroupMap,
                                         Map<String, ConfirmedIndexGroupRequest> confirmedGroupMap) {
        for (String groupKey : confirmedGroupMap.keySet()) {
            if (!confirmGroupMap.containsKey(groupKey)) {
                throw new IllegalArgumentException("confirmedData 中存在未知分组：" + groupKey);
            }
        }
    }

    private void validateConfirmedLabels(IndexConfirmGroupRequest confirmGroup,
                                         Map<String, ConfirmedLabelItemRequest> confirmedLabelMap) {
        if (confirmedLabelMap.isEmpty()) {
            return;
        }
        Set<String> allowedLabels = new LinkedHashSet<String>();
        if (confirmGroup.getLabelItems() != null) {
            for (IndexConfirmLabelItemRequest labelItem : confirmGroup.getLabelItems()) {
                if (labelItem != null && !isBlank(labelItem.getLabel())) {
                    allowedLabels.add(labelItem.getLabel());
                }
            }
        }
        for (String label : confirmedLabelMap.keySet()) {
            if (!allowedLabels.contains(label)) {
                throw new IllegalArgumentException("分组【" + confirmGroup.getGroupDesc() + "】中存在未知标签：" + label);
            }
        }
    }

    private Map<String, IndexConfirmGroupRequest> toConfirmGroupMap(List<IndexConfirmGroupRequest> confirmData) {
        Map<String, IndexConfirmGroupRequest> result = new LinkedHashMap<String, IndexConfirmGroupRequest>();
        if (confirmData == null) {
            return result;
        }
        for (IndexConfirmGroupRequest group : confirmData) {
            if (group != null && !isBlank(group.getGroupKey())) {
                result.put(group.getGroupKey(), group);
            }
        }
        return result;
    }

    private Map<String, ConfirmedIndexGroupRequest> toConfirmedGroupMap(List<ConfirmedIndexGroupRequest> confirmedData) {
        Map<String, ConfirmedIndexGroupRequest> result = new LinkedHashMap<String, ConfirmedIndexGroupRequest>();
        if (confirmedData == null) {
            return result;
        }
        for (ConfirmedIndexGroupRequest group : confirmedData) {
            if (group != null && !isBlank(group.getGroupKey())) {
                result.put(group.getGroupKey(), group);
            }
        }
        return result;
    }

    private Map<String, ConfirmedLabelItemRequest> toConfirmedLabelMap(List<ConfirmedLabelItemRequest> labelItems) {
        Map<String, ConfirmedLabelItemRequest> result = new LinkedHashMap<String, ConfirmedLabelItemRequest>();
        if (labelItems == null) {
            return result;
        }
        for (ConfirmedLabelItemRequest item : labelItems) {
            if (item != null && !isBlank(item.getLabel())) {
                result.put(item.getLabel(), item);
            }
        }
        return result;
    }

    /**
     * 统计数据、实时数据存在“同一 label 只配一次”的特殊归并规则，
     * 其他分组默认把同名 label 展开到当前分组下全部报告。
     */
    private List<IndexCandidateReportItemRequest> resolveTargets(IndexCandidateRequest candidate, String label) {
        List<IndexCandidateReportItemRequest> reports = candidate.getReports();
        if (reports == null || reports.isEmpty()) {
            return Collections.emptyList();
        }

        boolean hasRealtimeInterReport = hasDataSet(reports, DATA_SET_REALTIME_INTER);
        List<IndexCandidateReportItemRequest> result = new ArrayList<IndexCandidateReportItemRequest>();
        for (IndexCandidateReportItemRequest report : reports) {
            if (report == null) {
                continue;
            }

            if (GROUP_KEY_STATISTIC.equals(candidate.getGroupKey())) {
                if (isInterHarmonicLabel(label)) {
                    if (DATA_SET_STATISTIC_INTER.equals(report.getDataSetName()) || reports.size() == 1) {
                        result.add(report);
                    }
                    continue;
                }
                if (!DATA_SET_STATISTIC_INTER.equals(report.getDataSetName())) {
                    result.add(report);
                }
                continue;
            }

            if (GROUP_KEY_REALTIME.equals(candidate.getGroupKey())) {
                if (LABEL_REALTIME_INTER.equals(label)) {
                    if (DATA_SET_REALTIME_INTER.equals(report.getDataSetName())) {
                        result.add(report);
                    } else if (!hasRealtimeInterReport && DATA_SET_REALTIME_UNGROUPED.equals(report.getDataSetName())) {
                        result.add(report);
                    }
                    continue;
                }
                if (!DATA_SET_REALTIME_INTER.equals(report.getDataSetName())) {
                    result.add(report);
                }
                continue;
            }

            result.add(report);
        }
        return result;
    }

    private boolean hasDataSet(List<IndexCandidateReportItemRequest> reports, String dataSetName) {
        if (reports == null || reports.isEmpty() || isBlank(dataSetName)) {
            return false;
        }
        for (IndexCandidateReportItemRequest report : reports) {
            if (report != null && dataSetName.equals(report.getDataSetName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 计算多个目标报告可共同接受的 lnInst 候选，保持首个目标报告的顺序。
     */
    private List<String> intersectLnInstValues(List<List<String>> targetLnInstLists) {
        if (targetLnInstLists == null || targetLnInstLists.isEmpty()) {
            return Collections.emptyList();
        }

        List<String> firstValues = targetLnInstLists.get(0);
        if (firstValues == null || firstValues.isEmpty()) {
            return Collections.emptyList();
        }

        List<String> result = new ArrayList<String>();
        for (String value : firstValues) {
            if (isBlank(value)) {
                continue;
            }
            boolean existsInAllTargets = true;
            for (int i = 1; i < targetLnInstLists.size(); i++) {
                List<String> currentValues = targetLnInstLists.get(i);
                if (currentValues == null || !currentValues.contains(value)) {
                    existsInAllTargets = false;
                    break;
                }
            }
            if (existsInAllTargets) {
                result.add(value);
            }
        }
        return result;
    }

    /**
     * 某些未分组报告会把多种 label 的候选值拼在同一个 availableLnInstValues 里，
     * 这里按当前业务规则先拆开后再返回给前端。
     */
    private List<String> resolveAvailableLnInstValues(IndexCandidateRequest candidate,
                                                      IndexCandidateReportItemRequest target,
                                                      String label) {
        if (target == null || target.getAvailableLnInstValues() == null) {
            return Collections.emptyList();
        }

        List<String> values = target.getAvailableLnInstValues();
        if (GROUP_KEY_STATISTIC.equals(candidate.getGroupKey())
                && DATA_SET_STATISTIC_UNGROUPED.equals(target.getDataSetName())
                && values.size() > 1) {
            int splitIndex = values.size() / 2;
            return isInterHarmonicLabel(label)
                    ? new ArrayList<String>(values.subList(splitIndex, values.size()))
                    : new ArrayList<String>(values.subList(0, splitIndex));
        }

        if (GROUP_KEY_REALTIME.equals(candidate.getGroupKey())
                && DATA_SET_REALTIME_UNGROUPED.equals(target.getDataSetName())
                && values.size() > 1) {
            return LABEL_REALTIME_INTER.equals(label)
                    ? new ArrayList<String>(values.subList(1, values.size()))
                    : new ArrayList<String>(values.subList(0, 1));
        }

        return new ArrayList<String>(values);
    }

    private void validateConfirmedLabel(Map<String, IndexConfirmGroupRequest> confirmGroupMap,
                                        IndexConfirmGroupRequest confirmGroup,
                                        IndexConfirmLabelItemRequest confirmLabel,
                                        ConfirmedLabelItemRequest confirmedLabel) {
        if (!confirmGroupMap.containsKey(confirmGroup.getGroupKey())) {
            throw new IllegalArgumentException("未找到确认分组：" + confirmGroup.getGroupKey());
        }
        if (isBlank(confirmedLabel.getLnInst())) {
            throw new IllegalArgumentException("分组【" + confirmGroup.getGroupDesc() + "】的标签【"
                    + confirmLabel.getLabel() + "】未选择 lnInst");
        }
        if (confirmLabel.getCommonLnInstValues() == null || !confirmLabel.getCommonLnInstValues().contains(confirmedLabel.getLnInst())) {
            throw new IllegalArgumentException(
                    "分组【" + confirmGroup.getGroupDesc() + "】的标签【" + confirmLabel.getLabel()
                            + "】选择的 lnInst【" + confirmedLabel.getLnInst() + "】不在共同候选范围内："
                            + confirmLabel.getCommonLnInstValues()
            );
        }
        if (confirmLabel.getTargets() != null) {
            for (IndexConfirmTargetRequest target : confirmLabel.getTargets()) {
                if (target == null || target.getAvailableLnInstValues() == null) {
                    continue;
                }
                if (!target.getAvailableLnInstValues().contains(confirmedLabel.getLnInst())) {
                    throw new IllegalArgumentException(
                            "标签【" + confirmLabel.getLabel() + "】在目标报告【" + target.getReportName()
                                    + "】下不支持 lnInst【" + confirmedLabel.getLnInst() + "】"
                    );
                }
            }
        }
    }

    private void expandBindings(IndexSelectionGroupResponse selectionGroup,
                                IndexConfirmLabelItemRequest confirmLabel,
                                String lnInst) {
        if (confirmLabel.getTargets() == null) {
            return;
        }
        for (IndexConfirmTargetRequest target : confirmLabel.getTargets()) {
            if (target == null) {
                continue;
            }
            IndexBindingResponse binding = new IndexBindingResponse();
            binding.setReportName(target.getReportName());
            binding.setDataSetName(target.getDataSetName());
            binding.setLabel(confirmLabel.getLabel());
            binding.setLnInst(lnInst);
            selectionGroup.getBindings().add(binding);
        }
    }

    private boolean isInterHarmonicLabel(String label) {
        return label != null && label.startsWith("间谐波");
    }

    private static String normalizeSortValue(String value) {
        return value == null ? "" : value;
    }

    private static int compareLnInstValues(String left, String right) {
        Long leftNumeric = parseNumericLnInst(left);
        Long rightNumeric = parseNumericLnInst(right);
        if (leftNumeric != null && rightNumeric != null) {
            int result = leftNumeric.compareTo(rightNumeric);
            if (result != 0) {
                return result;
            }
        }
        return normalizeSortValue(left).compareTo(normalizeSortValue(right));
    }

    private static Long parseNumericLnInst(String value) {
        if (value == null) {
            return null;
        }
        String trimmedValue = value.trim();
        if (trimmedValue.isEmpty()) {
            return null;
        }
        try {
            return Long.valueOf(trimmedValue);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

    private boolean isBlank(String value) {
        return value == null || value.trim().isEmpty();
    }
}
