package com.inspect.analysis.utils;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspect.analysis.constant.AnalyseConstants;
import com.inspect.analysis.domain.AlgValue;
import com.inspect.analysis.domain.AnalyseResPoint;
import com.inspect.analysis.domain.ResultAnalysis;
import com.inspect.base.core.constant.AlgConstants;
import com.inspect.base.core.enums.PointStatusEnum;
import com.inspect.base.core.enums.ResStatusEnum;
import com.inspect.base.core.enums.ResultTypeEnum;
import com.inspect.base.core.utils.BigDecimalUtil;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.message.MessageUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
@Component
public class ResultAnalysisUtils {

    @Autowired
    private MessageUtils messageUtils;

    /**
     * 检查返回结果
     * code: 2000-正确 2001-图像数据错误 2002-算法分析失败
     * 图像数据错误是指未能获取到图像数据；算法分析失败是指算法本身分析过程中出错
     */
    public boolean checkCode(String code, String desc, ResultAnalysis resultAnalysis) {
        if (AnalyseConstants.ANALYSE_OK.equals(code)) {
            resultAnalysis.setCreateTime(new Date());
            resultAnalysis.setPointStatus("1");
            resultAnalysis.setResStatus("0");
            resultAnalysis.setResultType("1");
            return true;
        }
        if (AnalyseConstants.ANALYSE_FAIL_NO_FILE.equals(code)
                || AnalyseConstants.ANALYSE_FAIL_FILE_EXCEPT.equals(code)
                || AnalyseConstants.ANALYSE_FAIL_FILE_INCOMPATIBLE.equals(code)) {
            resultAnalysis.setDescription(desc);
        } else if (AnalyseConstants.ANALYSE_FAIL_ALG_EXCEPT.equals(code)) {
            resultAnalysis.setDescription(messageUtils.get("分析失败"));
        } else {
            resultAnalysis.setDescription(messageUtils.get("未知错误"));
            log.error("[ANALYSE RES] Error Return Code={}", code);
        }

        resultAnalysis.setPointStatus("0");
        resultAnalysis.setResultType("2");
        resultAnalysis.setResStatus("0");
        resultAnalysis.setCreateTime(new Date());
        if (!Arrays.asList(AlgConstants.CORRECTION, AlgConstants.GIS_METER_2).contains(resultAnalysis.getAlgType())) {
            resultAnalysis.setResValue("--");
        }
        return false;
    }

    /**
     * 解析算法结果
     * pointStatus点位状态: 点位状态 0-异常 1-正常 2-待人工确认 3-已撤销（忽略） 4-跟踪（告警） 5-确认（告警） 6-缺陷
     * resultType分析结果: 0-缺陷 1-正常 2-异常
     * resStatus告警确认状态: 0-未确认 1-已确认 2-已撤销 3-需要纠偏 4-完成纠偏
     */
    public void parseAlg(String algType, AlgValue algValue, String value, String defaultDesc, ResultAnalysis resultAnalysis) {
        log.info("PARSE_ALG algType: {}, algValue: {}, value: {}, defaultDesc: {}", algType, algValue, value, defaultDesc);

        // 初筛红外
        if ("1".equals(resultAnalysis.getFilter()) && !AlgConstants.INFRARED.equals(algType) && AlgConstants.ALG_INFRARED_LIST.contains(algType)) {
            // 绍兴初筛红外改成正常
            resultAnalysis.setResultType("1");
            resultAnalysis.setPointStatus("1");
            resultAnalysis.setResStatus("0");
            resultAnalysis.setCreateTime(new Date());
            resultAnalysis.setResValue("--");
            resultAnalysis.setDescription("-");
            return;
        }

        if (value == null || value == "null") {
            value = "";
        }

        final String correctionValue = value;
        // 读取字符串中的整数或浮点数（注意集合下只取第一个值，有坑，原值使用correctionValue）
        value = algValue.formatValue(value);
        // 初筛时, infrared算法要做阈值判断
        if ("1".equals(resultAnalysis.getFilter()) && !AlgConstants.INFRARED.equals(algType)) {
            algType = "";
        }

        if (StringUtils.isNull(algType)) {
            log.warn("parseAlg algType is null!");
            return;
        }

        if ("meter".equals(algType)) {
            boolean hasErrorValue = Arrays.stream(correctionValue.split(StringUtils.COMMA)).anyMatch(v -> StringUtils.isEmpty(v) || "null".equals(v)) ;
           if (hasErrorValue) {
               resultAnalysis.setResStatus("0");
               resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
               resultAnalysis.setResultType(ResultTypeEnum.DEFECT.getCode());
               resultAnalysis.setDescription("读数失败");
               return;
           }
        }

        if (value.isEmpty() || value.equals("-1") || "null".equals(value)) {
            log.info("PARSE_ALG_EMPTY algType: {}, algValue: {}, value: {}, defaultDesc: {}", algType, algValue, value, defaultDesc);
            resultAnalysis.setPointStatus("0");
            resultAnalysis.setResultType("2");
            resultAnalysis.setResStatus("0");
            if ("meter".equals(algType)) {
                resultAnalysis.setResultType("0");
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                defaultDesc = messageUtils.get("读数失败");
            } else if ("infrared".equals(algType)) {
                defaultDesc = messageUtils.get("读数失败");
            } else {
                defaultDesc = messageUtils.get("算法内部异常");
            }
            resultAnalysis.setResValue("--");
            resultAnalysis.setDescription(defaultDesc);
            resultAnalysis.setCreateTime(new Date());
            return;
        }
        if ("10003".equals(value) && "gis_meter".equals(algType)) {
            resultAnalysis.setPointStatus("0");
            resultAnalysis.setResultType("2");
            resultAnalysis.setResStatus("0");
            resultAnalysis.setCreateTime(new Date());
            resultAnalysis.setDescription(messageUtils.get("读数失败"));
            return;
        }

        if (algType.equals("qrcode")) {
            resultAnalysis.setResStatus("1");
            resultAnalysis.setPointStatus("1");
            resultAnalysis.setResultType("1");
        } else if (algType.equals("switch")) {
            String[] values = value.split(StringUtils.COMMA);
            // value值：空|null|1|未识别-异常，灭-缺陷，亮|开|合|投入|其他-正常
            boolean isDefect = Arrays.stream(values).anyMatch(v -> "灭".equals(v));
            boolean isAbnormal = Arrays.stream(values).anyMatch(v -> "".equals(v) || "null".equals(v) || "1".equals(v) || "未识别".equals(v));

            if (isDefect) {
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResultType(ResultTypeEnum.DEFECT.getCode());
                resultAnalysis.setResStatus(ResStatusEnum.UNCONFIRM.getCode());
            } else if (isAbnormal) {
                resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                resultAnalysis.setResultType(ResultTypeEnum.ABNORMAL.getCode());
                resultAnalysis.setResStatus(ResStatusEnum.UNCONFIRM.getCode());
            } else {
                resultAnalysis.setPointStatus(PointStatusEnum.NORMAL.getCode());
                resultAnalysis.setResultType(ResultTypeEnum.NORMAL.getCode());
                resultAnalysis.setResStatus(ResStatusEnum.CONFIRM.getCode());
            }
            defaultDesc = resultAnalysis.getResValue();
        } else if (algType.equals("light")) {
            resultAnalysis.setResStatus("1");
            resultAnalysis.setPointStatus("1");
            resultAnalysis.setResultType("1");
        } else if (algType.equals("meter") || algType.equals("gis_meter")) {
            log.info("------------------parseAlg : meter|gis_meter value: {}, originalValue: {}", value, correctionValue);
            if ("open".equalsIgnoreCase(value)
                    || "closed".equalsIgnoreCase(value) || "Off".equalsIgnoreCase(value) || "On".equalsIgnoreCase(value)) {
                resultAnalysis.setResStatus("0");
                resultAnalysis.setPointStatus("1");
                resultAnalysis.setResultType("1");
                defaultDesc = messageUtils.get("正常");
            } else {
                if (!algValue.isAlarm(value)) {
                    log.info("PARSE_ALG_METER_NO_ALARM value: {}, defaultDesc: {}", value, defaultDesc);
                    if (StringUtils.isNotEmpty(defaultDesc) && defaultDesc.contains("失败")) {
                        resultAnalysis.setResStatus("0");
                        resultAnalysis.setPointStatus("0");
                        resultAnalysis.setResultType("2");
                    } else {
                        resultAnalysis.setResStatus("0");
                        resultAnalysis.setPointStatus("1");
                        // result_type: 0-告警; 1-正常; 2-异常. 正常必然对应1
                        resultAnalysis.setResultType("1");
                        defaultDesc = messageUtils.get("正常");
                    }
                } else {
                    log.info("PARSE_ALG_METER_ALARM value: {}", value);
                    String[] valueArr = value.split(StringUtils.COMMA);
                    if (valueArr.length > 1) {
                        log.info("PARSE_ALG_METER_ALARM_VALUE_COMPOSITE value: {}", value);
                        resultAnalysis.setResStatus("0");
                        resultAnalysis.setPointStatus("1");
                        //resultAnalysis.setResultType("0");
                        resultAnalysis.setResultType("1");
                        defaultDesc = messageUtils.get("正常");
                    } else {
                        log.info("PARSE_ALG_METER_ALARM_VALUE_SINGLE value: {}", value);
                        if (value.contains("分OFF") || value.contains("分") || value.contains("合")) {
                            resultAnalysis.setResStatus("0");
                            resultAnalysis.setPointStatus("1");
//                            resultAnalysis.setResultType("0");
                            resultAnalysis.setResultType("1");
                            defaultDesc = messageUtils.get("正常");
                        } else {
                            try {
                                Double.parseDouble(valueArr[0]);
                                log.info("PARSE_ALG_METER_ALARM_VALUE_PARSE value: {}", valueArr[0]);
                                resultAnalysis.setResStatus("0");
                                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                                resultAnalysis.setResultType("0");
                                defaultDesc = messageUtils.get("表计超限");
                            } catch (Exception e) {
                                log.info("PARSE_ALG_METER_ALARM_VALUE_SINGLE_NO_DIGIT value: {}", value);
                                resultAnalysis.setResStatus("0");
                                //resultAnalysis.setPointStatus("1");
                                resultAnalysis.setPointStatus("0");
//                                resultAnalysis.setResultType("0");
                                resultAnalysis.setResultType("2");
                                defaultDesc = messageUtils.get("异常");
                            }
                        }
                    }
                }
            }
        } else if (algType.equals(AlgConstants.GIS_METER_2)) {
            // 华软无机人表计算法
            log.info("parseAlg : gis_meter2 correctionValue: {} code: {}", correctionValue, resultAnalysis.getResCode());
            // 异常
            boolean hasDefect = false;
            boolean hasAbnormal = false;
            try {
                // 1. 解析 JSON
                String[] values = JSON.parseArray(correctionValue, String.class).toArray(new String[0]);
                // 2. 转换：非空 → "正常"，空值 → "读数失败"，超限 → "表计超限"
                String[] descs = new String[values.length];
                for (int i = 0; i < values.length; i++) {
                    String item = values[i];
                    if (StringUtils.isEmpty(item)) {
                        hasAbnormal = true;
                        values[i] = "--";
                        descs[i] = "读数失败";
                    } else {
                        if (algValue.isAlarm(item)) {
                            hasDefect = true;
                            descs[i] = "表计超限";
                        } else {
                            descs[i] = "正常";
                        }
                    }
                }
                String valueStr = String.join(",", values);
                String descStr = String.join(",", descs);
                defaultDesc = descStr;
                resultAnalysis.setResValue(valueStr);
                // 无人机表计所有读数失败都应该是缺陷
                if (hasDefect || hasAbnormal) {
                    resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                    resultAnalysis.setResStatus("0");
                    resultAnalysis.setResultType("0");
                } else {
                    resultAnalysis.setPointStatus("1");
                    resultAnalysis.setResStatus("0");
                    resultAnalysis.setResultType("1");
                }
            } catch (Exception e) {
                log.error("PARSE_ALG_GIS_METER_2_ERROR correctionValue: {}", correctionValue, e);
                defaultDesc = "解析异常";
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResStatus("0");
                resultAnalysis.setResultType("0");
            }
        } else if (algType.equals("sound")) {
            if (value.equals("1")) {
                resultAnalysis.setResStatus("1");
                resultAnalysis.setPointStatus("1");
                resultAnalysis.setResultType("1");
                defaultDesc = messageUtils.get("正常");
            } else {
                resultAnalysis.setResStatus("0");
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResultType("0");
                defaultDesc = messageUtils.get("异常");
            }
        } else if (
                AlgConstants.ALG_INFRARED_LIST.contains(algType) ||
                        algType.equals("xb")) {
            if (!algValue.isAlarm(value)) {
                log.info("infrared no alarm value: {}, algValue: {}", value, algValue);
                resultAnalysis.setResStatus("1");
                resultAnalysis.setPointStatus("1");
                resultAnalysis.setResultType("1");
                //defaultDesc = device + messageUtils.get("正常");
                defaultDesc = messageUtils.get("正常");
            } else {
                log.info("infrared alarm value: {}, algValue: {}", value, algValue);
                resultAnalysis.setResStatus("0");
                //resultAnalysis.setPointStatus("2");
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResultType("0");
                //defaultDesc = device + messageUtils.get("告警");
                defaultDesc = messageUtils.get("温度异常告警");
            }
            if (messageUtils.get("分析失败").equals(defaultDesc)) {
                defaultDesc = "--";
            }
        } else if (algType.equals("isolator")) {
            log.info("ALG_TYPE isolator value: {}", value);
            if (value.equals("1")) {
                defaultDesc = "分";
            } else if (value.equals("2")) {
                defaultDesc = "合";
            } else if (value.equals("3")) {
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResultType("0");
                resultAnalysis.setResStatus("0");
                defaultDesc = "分位异常";
            } else if (value.equals("4")) {
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResultType("0");
                resultAnalysis.setResStatus("0");
                defaultDesc = "合位异常";
            } else {
                resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                resultAnalysis.setResultType(ResultTypeEnum.ABNORMAL.getCode());
                resultAnalysis.setResStatus(ResStatusEnum.UNCONFIRM.getCode());
                defaultDesc = "未检测到刀闸";
            }
            resultAnalysis.setResValue(defaultDesc);
        } else if (algType.equals("correction")) {
            log.info("correction correction, {}", resultAnalysis.getResValue());
            log.info("parseAlg algType correction 2000 resCode: {}, correctionValue: {}", resultAnalysis.getResCode(), correctionValue);
            if ("2000".equals(resultAnalysis.getResCode())) {
                ObjectMapper mapper = new ObjectMapper();
                List<List<Double>> list;
                try {
                    log.info("parseAlg algType correction 2000 correctionValue: {}", correctionValue);
                    list = mapper.readValue(correctionValue, new TypeReference<List<List<Double>>>() {
                    });
                    log.info("parseAlg algType correction 2000 correctionValue: {}", list);
                } catch (Exception e) {
                    log.error("parseAlg algType correction 2000 correctionValue exception", e);
                    list = new ArrayList<>();
                }

                if (list.size() == 2 && list.get(0).size() == 2 && list.get(1).size() == 2) {
                    final double EPSILON = 1e-8;
                    double value0 = list.get(0).get(0);
                    double value1 = list.get(0).get(1);
                    double value2 = list.get(1).get(0);
                    double value3 = list.get(1).get(1);
                    if (Math.abs(value0) < EPSILON &&
                            Math.abs(value1) < EPSILON &&
                            Math.abs(value2) < EPSILON &&
                            Math.abs(value3) < EPSILON) {
                        log.info("2000 correction no need value0: {}, value1: {}, value2: {}, value3: {}", value0, value1, value2, value3);
                        resultAnalysis.setPointStatus(PointStatusEnum.NORMAL.getCode());
                        resultAnalysis.setResultType(ResultTypeEnum.NORMAL.getCode());
                        resultAnalysis.setResStatus("2");
                        resultAnalysis.setResValue("");
                        defaultDesc = messageUtils.get("无需纠偏");
                    } else {
                        log.info("2000 correction need value0: {}, value1: {}, value2: {}, value3: {}", value0, value1, value2, value3);
                        resultAnalysis.setPointStatus(PointStatusEnum.NORMAL.getCode());
                        resultAnalysis.setResultType(ResultTypeEnum.NORMAL.getCode());
                        resultAnalysis.setResStatus("2");
                        resultAnalysis.setResValue("");
                        defaultDesc = "无需纠偏";
                    }
                } else {
                    log.info("parseAlg algType correction correctionValue abnormal");
                    resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                    resultAnalysis.setResultType("0");
                    resultAnalysis.setResStatus("0");
                    defaultDesc = "纠偏结果异常";
                }
            } else if ("2001".equals(resultAnalysis.getResCode())) {
                ObjectMapper mapper = new ObjectMapper();
                List<List<Double>> list;
                try {
                    log.info("parseAlg algType correction 2001 correctionValue: {}", correctionValue);
                    list = mapper.readValue(correctionValue, new TypeReference<List<List<Double>>>() {
                    });
                    log.info("parseAlg algType correction 2001 correctionValue: {}", list);
                } catch (Exception e) {
                    log.error("parseAlg algType correction 2001 correctionValue exception", e);
                    list = new ArrayList<>();
                }

                if (list.size() == 2 && list.get(0).size() == 2 && list.get(1).size() == 2) {
                    final double EPSILON = 1e-8;
                    double value0 = list.get(0).get(0);
                    double value1 = list.get(0).get(1);
                    double value2 = list.get(1).get(0);
                    double value3 = list.get(1).get(1);
                    if (Math.abs(value0) < EPSILON &&
                            Math.abs(value1) < EPSILON &&
                            Math.abs(value2) < EPSILON &&
                            Math.abs(value3) < EPSILON) {
                        log.info("2001 correction no need value0: {}, value1: {}, value2: {}, value3: {}", value0, value1, value2, value3);
                        resultAnalysis.setPointStatus("1");
                        resultAnalysis.setResultType("1");
                        resultAnalysis.setResStatus("0");
                        defaultDesc = messageUtils.get("纠偏码异常");
                    } else {
                        log.info("2001 correction need value0: {}, value1: {}, value2: {}, value3: {}", value0, value1, value2, value3);
                        resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                        resultAnalysis.setResultType("0");
                        resultAnalysis.setResStatus("3");
                        defaultDesc = "纠偏码异常请进行纠偏";
                    }
                } else {
                    log.info("2001 parseAlg algType correction correctionValue abnormal");
                    resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                    resultAnalysis.setResultType("0");
                    resultAnalysis.setResStatus("0");
                    defaultDesc = "纠偏码和值均异常";
                }

            } else if ("2002".equals(resultAnalysis.getResCode())) {
                resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                resultAnalysis.setResultType("0");
                resultAnalysis.setResStatus("0");
                defaultDesc = "超出比对范围";
            } else if ("2003".equals(resultAnalysis.getResCode())) {
                resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                resultAnalysis.setResultType("0");
                resultAnalysis.setResStatus("0");
                defaultDesc = "图像数据错误";
            } else {
                resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
                resultAnalysis.setResultType("0");
                resultAnalysis.setResStatus("0");
                defaultDesc = messageUtils.get("未知异常");
            }
            // 纠偏分析结果均为正常
            resultAnalysis.setResultType(ResultTypeEnum.NORMAL.getCode());
        } else {
            log.info("parseAlg algType: {}", algType);
            if (value.equals("0")) {
                resultAnalysis.setPointStatus("1");
                resultAnalysis.setResultType("1");
                resultAnalysis.setResStatus("2");
                defaultDesc = messageUtils.get("正常");
                resultAnalysis.setSuggestion(messageUtils.get("系统审核"));
            } else if (value.equals("1")) {
                resultAnalysis.setPointStatus(PointStatusEnum.DEFECT.getCode());
                resultAnalysis.setResultType("0");
                resultAnalysis.setResStatus("0");
            }
            if (StringUtils.isNotEmpty(defaultDesc) && defaultDesc.contains(messageUtils.get("分析失败"))) {
                resultAnalysis.setResultType("2");
                resultAnalysis.setPointStatus(PointStatusEnum.ABNORMAL.getCode());
            }
        }
        resultAnalysis.setDescription(defaultDesc);
        resultAnalysis.setCreateTime(new Date());
        log.info("------------------parseAlg resultAnalysis: {}", resultAnalysis);
    }

    /**
     * 将分析结果的辅助值进行合并展示
     *
     * @param analyseResPoint
     * @param resultAnalysis
     */
    public void mergeValue(AnalyseResPoint analyseResPoint, ResultAnalysis resultAnalysis) {
        String value2 = analyseResPoint.getValue2();
        if (StringUtils.isNotEmpty(value2)) {
            log.info("mergeValue analyseResPoint value2: {}", value2);
            String value = analyseResPoint.getValue();
            if (!NumberUtils.isCreatable(value2)) {
                value2 = "null";
            }
            String val = String.join(",", value, value2);
            resultAnalysis.setResValue(val);
        }
    }

    /**
     * 给可读数算法的值添加单位
     *
     * @param resValue 读数
     * @param algType  算法类型
     * @param unit     单位
     * @return
     */
    public String addUnit2Value(String resValue, String algType, String unit) {
        if (StringUtils.isNotEmpty(resValue) && StringUtils.isNotEmpty(unit) && AlgConstants.READABLE_ALG_LIST.contains(algType)) {
            log.info("addUnit2Value resValue: {}, algType: {}, unit: {}", resValue, algType, unit);
            String[] valueArr = resValue.split(",");
            String values = IntStream.range(0, valueArr.length)
                    .mapToObj(i -> {
                        String val = valueArr[i];
                        if (!NumberUtils.isCreatable(val)) {
                            return val;
                        }

                        if (AlgConstants.ALG_INFRARED_LIST.contains(algType)) {
                            return BigDecimalUtil.toOneDecimal(val, 1) + unit;
                        }

                        // 表计算法：避雷器只有第一个值带单位
                        if (AlgConstants.METER.equals(algType)) {
                            return i == 0 ? val + unit : val;
                        }

                        return val + unit;
                    })
                    .collect(Collectors.joining(","));
            return values;
        }
        return resValue;
    }
}
