package com.njcn.gather.result.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.njcn.gather.detection.pojo.vo.DetectionData;
import com.njcn.gather.report.pojo.enums.ItemReportKeyEnum;
import com.njcn.gather.storage.pojo.po.SimAndDigNonHarmonicResult;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * IMBV/IMBA 报告结果行装配：同一 sort 下的不平衡度 T 值与序分量 ABC 值合并为一行。
 */
public final class UnbalanceResultAssembler {

    private UnbalanceResultAssembler() {
    }

    public static List<Map<String, String>> assembleRows(List<SimAndDigNonHarmonicResult> results) {
        if (CollUtil.isEmpty(results)) {
            return java.util.Collections.emptyList();
        }
        Map<Integer, List<SimAndDigNonHarmonicResult>> bySort = results.stream()
                .filter(result -> result.getSort() != null)
                .collect(Collectors.groupingBy(SimAndDigNonHarmonicResult::getSort, TreeMap::new, Collectors.toList()));
        return bySort.values().stream()
                .map(UnbalanceResultAssembler::assembleRow)
                .filter(row -> row != null)
                .collect(Collectors.toList());
    }

    private static Map<String, String> assembleRow(List<SimAndDigNonHarmonicResult> sameSortResults) {
        Map<String, String> row = defaultRow();
        boolean hasData = false;
        for (SimAndDigNonHarmonicResult result : sameSortResults) {
            String code = result.getAdType();
            if (equalsAny(code, "V_UNBAN", "I_UNBAN")) {
                DetectionData data = parse(result.getTValue());
                if (data != null) {
                    putPrimary(row, data);
                    hasData = true;
                }
            } else if (equalsAny(code, "SeqV", "SeqA")) {
                hasData |= putSequence(row, result);
            }
        }
        return hasData ? row : null;
    }

    private static Map<String, String> defaultRow() {
        Map<String, String> row = new LinkedHashMap<>();
        for (ItemReportKeyEnum key : Arrays.asList(
                ItemReportKeyEnum.STANDARD,
                ItemReportKeyEnum.TEST,
                ItemReportKeyEnum.ERROR,
                ItemReportKeyEnum.ERROR_SCOPE,
                ItemReportKeyEnum.POS_SEQ,
                ItemReportKeyEnum.NEG_SEQ,
                ItemReportKeyEnum.ZERO_SEQ,
                ItemReportKeyEnum.RESULT)) {
            row.put(key.getKey(), "/");
        }
        return row;
    }

    private static void putPrimary(Map<String, String> row, DetectionData data) {
        row.put(ItemReportKeyEnum.STANDARD.getKey(), valueOrSlash(data.getResultData()));
        row.put(ItemReportKeyEnum.TEST.getKey(), valueOrSlash(data.getData()));
        row.put(ItemReportKeyEnum.ERROR.getKey(), data.getErrorData() == null ? "/" : format(data.getErrorData()));
        String errorScope = dealErrorScope(data.getRadius());
        if (StrUtil.isNotBlank(data.getUnit()) && !"/".equals(errorScope)) {
            errorScope = errorScope.concat(data.getUnit());
        }
        row.put(ItemReportKeyEnum.ERROR_SCOPE.getKey(), errorScope);
        row.put(ItemReportKeyEnum.RESULT.getKey(), resultText(data.getIsData()));
    }

    private static boolean putSequence(Map<String, String> row, SimAndDigNonHarmonicResult result) {
        boolean hasData = false;
        hasData |= putData(row, ItemReportKeyEnum.POS_SEQ.getKey(), parse(result.getAValue()));
        hasData |= putData(row, ItemReportKeyEnum.NEG_SEQ.getKey(), parse(result.getBValue()));
        hasData |= putData(row, ItemReportKeyEnum.ZERO_SEQ.getKey(), parse(result.getCValue()));
        return hasData;
    }

    private static boolean putData(Map<String, String> row, String key, DetectionData data) {
        if (data == null || data.getData() == null) {
            return false;
        }
        row.put(key, format(data.getData()));
        return true;
    }

    private static DetectionData parse(String value) {
        if (StrUtil.isBlank(value)) {
            return null;
        }
        return JSONUtil.toBean(value, DetectionData.class);
    }

    private static String resultText(Integer isData) {
        if (isData == null) {
            return "/";
        }
        if (isData == 1) {
            return "合格";
        }
        if (isData == 2) {
            return "不合格";
        }
        if (isData == 4) {
            return "无法比较";
        }
        return "/";
    }

    private static String valueOrSlash(Double value) {
        return value == null ? "/" : format(value);
    }

    private static String format(Double value) {
        return value == null ? "/" : format(BigDecimal.valueOf(value));
    }

    private static String format(BigDecimal value) {
        return value.setScale(4, RoundingMode.HALF_UP).toPlainString();
    }

    private static String dealErrorScope(String errorScope) {
        if (StrUtil.isBlank(errorScope)) {
            return "/";
        }
        if (errorScope.contains("~")) {
            String[] split = errorScope.split("~");
            String begin = split[0];
            if (begin.startsWith("-")) {
                begin = begin.substring(1);
            }
            if (split.length > 1 && split[1].equalsIgnoreCase(begin)) {
                return "±" + begin;
            }
        }
        return errorScope;
    }

    private static boolean equalsAny(String actual, String... expectedValues) {
        if (actual == null) {
            return false;
        }
        for (String expected : expectedValues) {
            if (expected.equalsIgnoreCase(actual)) {
                return true;
            }
        }
        return false;
    }
}
