package org.eco.als.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.eco.als.domain.DataImport;
import org.eco.als.domain.FaultDiagnosis;
import org.eco.als.domain.LifePrediction;
import org.eco.als.domain.PreProcessing;
import org.eco.als.domain.bo.*;
import org.eco.als.domain.vo.*;
import org.eco.als.service.*;
import org.eco.als.utils.CsvUtils;
import org.eco.als.utils.StatisticsCalculator;
import org.eco.common.core.config.EcoConfig;
import org.eco.common.core.constant.Constants;
import org.eco.common.core.exception.BusinessException;
import org.eco.common.core.utils.HttpUtils;
import org.eco.common.core.utils.StringUtils;
import org.eco.common.core.utils.file.FileUtils;
import org.eco.system.domain.vo.SysOssVo;
import org.eco.system.service.ISysOssService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;

/**
 * @Description: AlgorithmService
 *
 * @Author: GaoKun Wang
 * @Date: 2024/7/30
 */
@Service
@Slf4j
public class AlgorithmService implements IAlgorithmService {
    @Resource
    private IModelService modelService;

    @Resource
    private ISysOssService ossService;

    @Resource
    private IPreProcessingService processingService;

    @Resource
    private IWarningService warningService;

//    @Resource
//    private IFalseAlarmResultService falseAlarmResultService;

    @Resource
    private IFaultDiagnosisService faultDiagnosisService;
    @Resource
    private IFaultDiagnosisResultService faultDiagnosisResultService;
    @Resource
    private IAirConfigurationService airConfigurationService;
    @Resource
    private ILifePredictionService lifePredictionService;
    @Resource
    private IQaHistoryService qaHistoryService;
    @Resource
    private IJudgeFaultLogicService judgeFaultLogicService;

    @Resource
    private IFormulaService formulaService;
    @Resource
    private IDataImportService dataImportService;
    @Resource
    private IWarningResultService warningResultService;

    @Value("${kgqa.ask-url}")
    private String askUrl;

    private static ModelHttpVo sendHttp(ModelVo modelVo, Map<String, Object> map) {
        try {
            String result = HttpUtils.postJson(modelVo.getUrl(), map);
            JSONObject jsonObject = JSONUtil.parseObj(result);
            log.info("返回值：{}", jsonObject);
            String data = jsonObject.getStr("data");
            String status = jsonObject.getStr("status");
            String msg = jsonObject.getStr("msg");
            return ModelHttpVo.builder().data(data).status(Integer.valueOf(status)).msg(msg).build();
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException("算法服务连接异常,请联系管理员！");
        }
    }

    /**
     * executePro 预处理
     *
     * @param algorithmBo 参数
     * @return java.lang.String
     **/
    @Override
    @Transactional
    public String executePro(AlgorithmBo algorithmBo) {
        // 模型相关信息
        ModelVo modelVo = modelService.selectById(algorithmBo.getModelId());
        if (ObjectUtil.isNull(modelVo)) {
            throw new BusinessException("模型信息为空，请检查！");
        }

        SysOssVo sysOssVo = getSysOssVo(algorithmBo, null);
        if (sysOssVo == null) {
            return null;
        }
        PreProcessingBo processingBo =
            PreProcessingBo.builder()
                .ossId(sysOssVo.getOssId())
                .aircraftId(algorithmBo.getAircraftId())
                .modelType(modelVo.getType())
                .sortieNo(algorithmBo.getSortieNo())
                .param(algorithmBo.getParam())
                .status("0")
                .columnData(Arrays.toString(algorithmBo.getColumnData()))
                .build();
        PreProcessing preProcessing = processingService.insert(processingBo);
        // 参数
        Map<String, Object> map = StrUtil.isBlank(algorithmBo.getParam()) ? new HashMap<>() : new HashMap<>(JSONUtil.parseObj(algorithmBo.getParam()));
        map.put("url", sysOssVo.getUrl());
        // 请求
        ModelHttpVo httpVo = sendHttp(modelVo, map);
        if (httpVo != null && httpVo.getStatus() == 200) {
            File resultFile = CsvUtils.jsonToFileCsv(httpVo.getData(), CsvUtils.extractFilename("model_result"));
            SysOssVo sysOssVo2 = ossService.upload(resultFile);
            processingBo.setOssId(sysOssVo2.getOssId());
            processingBo.setStatus("1");
            processingBo.setVersion(preProcessing.getVersion());
            processingBo.setId(preProcessing.getId());
            processingService.update(processingBo);
        }
        return httpVo != null ? httpVo.getData() : null;
    }

    /**
     * executeFalseAlarm 虚警抑制
     *
     * @param algorithmBo 参数
     **/
    @Override
    @Transactional
    public void executeFalseAlarm(AlgorithmBo algorithmBo) {
        WarningBo warningBo = new WarningBo();
        if (StrUtil.isBlank(algorithmBo.getSortieNo())) {
            throw new BusinessException("架次号不能为空！");
        }
        if (ObjectUtil.isEmpty(algorithmBo.getOssId())) {
            throw new BusinessException("OssId不能为空！");
        }
        if (ObjectUtil.isEmpty(algorithmBo.getDataId())) {
            throw new BusinessException("dataId不能为空！");
        }
        warningBo.setSortieNo(algorithmBo.getSortieNo());
        // 警告列表
        List<WarningVo> warningList = warningService.selectList(warningBo);
        warningList.forEach(el -> {
            JudgeFaultLogicVo logicVo = judgeFaultLogicService.selectByHmc(el.getCode());
            int result = 3;
            WarningResultBo warningResultBo = new WarningResultBo();
            warningResultBo.setSortieNo(algorithmBo.getSortieNo());
            warningResultBo.setCode(el.getCode());
            warningResultBo.setHmc(el.getCode());
            warningResultBo.setAircraftId(algorithmBo.getAircraftId());
            warningResultBo.setName(el.getName());
            List<WarningResultVo> warningResultVos = warningResultService.selectList(warningResultBo);
            if (ObjectUtil.isNotNull(logicVo)) {
                ExpressBo expressBo = new ExpressBo();
                expressBo.setExpression(logicVo.getRemarks());
                expressBo.setOssId(algorithmBo.getOssId());
                JSONObject object = formulaService.evaluateExpression(expressBo);
                result = object.getInt("result");
                warningResultBo.setAttribute1(logicVo.getName());
                warningResultBo.setAttribute2(object.getStr("timeFlag"));
                warningResultBo.setResultContent(String.valueOf(result));
            }
            warningResultBo.setResultContent(String.valueOf(result));
            if (CollUtil.isNotEmpty(warningResultVos)) {
                warningResultBo.setId(warningResultVos.getFirst().getId());
                warningResultBo.setVersion(warningResultVos.getFirst().getVersion());
                warningResultService.update(warningResultBo);
            } else {
                warningResultService.insert(warningResultBo);
            }
        });
        if (CollUtil.isNotEmpty(warningList)) {
            DataImportVo dataImportVo = dataImportService.selectById(algorithmBo.getDataId());
            DataImport dataImport = new DataImport();
            dataImport.setId(dataImportVo.getId());
            dataImport.setVersion(dataImportVo.getVersion());
            dataImport.setDataStatus("2");
            dataImportService.updateById(dataImport);
        } else {
            throw new BusinessException("无警告信息！");
        }
    }

    /**
     * executeFault 故障诊断
     *
     * @param algorithmBo 参数
     **/
    @Override
    @Transactional
    public void executeFault(AlgorithmBo algorithmBo) {
        DataImportVo dataImportVo = dataImportService.selectById(algorithmBo.getDataId());
        DataImport dataImport = new DataImport();
        dataImport.setId(dataImportVo.getId());
        dataImport.setVersion(dataImportVo.getVersion());
        dataImport.setStatus("2");
        ModelBo modelBo = new ModelBo();
        modelBo.setAircraftType(algorithmBo.getAircraftType());
        modelBo.setType("5");
        List<ModelVo> list = modelService.selectList(modelBo);
        if (CollUtil.isEmpty(list)) {
            throw new BusinessException("模型信息为空，请检查！");
        }
        list.forEach(modelVo -> {
            algorithmBo.setColumnData(modelVo.getColumnData().split(","));
            SysOssVo sysOssVo = getSysOssVo(algorithmBo, "5");
            if (sysOssVo == null) {
                throw new BusinessException("架次数据为空，请检查！");
            }
            FaultDiagnosisBo diagnosisBo = FaultDiagnosisBo.builder()
                .ossId(sysOssVo.getOssId())
                .aircraftId(algorithmBo.getAircraftId())
                .modelType(modelVo.getType())
                .sortieNo(algorithmBo.getSortieNo())
                .param(algorithmBo.getPartId())
                .status("0")
                .columnData(Arrays.toString(algorithmBo.getColumnData()))
                .build();
            FaultDiagnosis faultDiagnosis = faultDiagnosisService.insert(diagnosisBo);
            // 参数
            Map<String, Object> map = StrUtil.isBlank(algorithmBo.getParam()) ? new HashMap<>() : new HashMap<>(JSONUtil.parseObj(algorithmBo.getParam()));
            map.put("url", sysOssVo.getUrl());
            // 请求
            ModelHttpVo httpVo = sendHttp(modelVo, map);
            if (httpVo != null && httpVo.getStatus() == 200) {
                diagnosisBo.setId(faultDiagnosis.getId());
                diagnosisBo.setVersion(faultDiagnosis.getVersion());
                diagnosisBo.setStatus("1");
                diagnosisBo.setResultContent(httpVo.getData());
                faultDiagnosisService.update(diagnosisBo);
                FaultDiagnosisResultBo resultBo = FaultDiagnosisResultBo.builder()
                    .diagnosisId(diagnosisBo.getId())
                    .aircraftId(diagnosisBo.getAircraftId())
                    .diagnosisId(diagnosisBo.getId())
                    .resultContent(httpVo.getData())
                    .sortieNo(diagnosisBo.getSortieNo())
                    .param(modelVo.getPartId())
                    .modelType(modelVo.getName())
                    .columnData(modelVo.getColumnData())
                    .remarks(modelVo.getParamType())
                    .build();
                faultDiagnosisResultService.insert(resultBo);
            } else {
                dataImport.setStatus("3");
                throw new BusinessException("算法服务异常");
            }
        });
        dataImportService.updateById(dataImport);
    }

    @Override
    @Transactional
    public String executeEvaluation(AlgorithmBo algorithmBo) {
        AirConfigurationVo airConfigurationVo = airConfigurationService.selectById(Long.valueOf(algorithmBo.getPartId()));
        // 模型相关信息
        ModelBo modelBo = new ModelBo();
        modelBo.setPartId(algorithmBo.getPartId());
        modelBo.setType("6");
        List<ModelVo> list = modelService.selectList(modelBo);
        if (CollUtil.isEmpty(list)) {
            throw new BusinessException("模型信息为空，请检查！");
        }
        ModelVo modelVo = list.getFirst();
        List<String> urls = new ArrayList<>();
        for (Long ossId : algorithmBo.getOssIds()) {
            SysOssVo sysOss = ossService.getById(ossId);
            if (ObjectUtil.isNotNull(sysOss)) {
                urls.add(sysOss.getUrl());
            }
        }
        // 插入退化评估记录
        LifePredictionBo lifePredictionBo = LifePredictionBo.builder()
            .name(airConfigurationVo.getName())
            .model(airConfigurationVo.getSpecsModel())
            .aircraftId(algorithmBo.getAircraftId())
            .aircraftType(airConfigurationVo.getAircraftType())
            .code(airConfigurationVo.getConCode())
            .timeRange(algorithmBo.getTimeRange())
            .sortiesCount(algorithmBo.getOssIds().length + "")
            .status("0")
            .build();
        LifePrediction lifePrediction = lifePredictionService.insert(lifePredictionBo);

        // 参数
        Map<String, Object> map = StrUtil.isBlank(algorithmBo.getParam()) ? new HashMap<>() : new HashMap<>(JSONUtil.parseObj(algorithmBo.getParam()));
        map.put("urls", urls);
        // 请求
        ModelHttpVo httpVo = sendHttp(modelVo, map);
        if (httpVo != null && httpVo.getStatus() == 200) {
            // 更新退化评估状态
            lifePredictionBo.setId(lifePrediction.getId());
            lifePredictionBo.setStatus("1");
            lifePredictionBo.setVersion(lifePrediction.getVersion());
            lifePredictionBo.setResultContent(httpVo.getData());
            lifePredictionService.update(lifePredictionBo);
        }
        return httpVo != null ? httpVo.getData() : null;
    }

    private SysOssVo getSysOssVo(AlgorithmBo algorithmBo, String modelType) {
        SysOssVo sysOss = ossService.getById(algorithmBo.getOssId());
        if (ObjectUtil.isNull(sysOss)) {
            throw new BusinessException("文件数据不存在!");
        }
        String path = StringUtils.substringAfter(sysOss.getFileName(), Constants.RESOURCE_PREFIX);
        String tempPathCsv = EcoConfig.getTempPath() + "/" + CsvUtils.getName(FileUtils.getNameNotSuffix(sysOss.getOriginalName()));
        JSONArray jsonArray;
        if (StrUtil.equals(modelType, "5")) {

            jsonArray = CsvUtils.getCsvDataByColumn(path, Arrays.asList(algorithmBo.getColumnData()), null);
        } else {
            jsonArray = CsvUtils.getCsvDataByHeaders(path, Arrays.asList(algorithmBo.getColumnData()), null);

        }
        if (CollUtil.isEmpty(jsonArray)) {
            throw new BusinessException("获取参数列为空。");
        }
        File file = CsvUtils.jsonToFileCsvByJsonArray(jsonArray, tempPathCsv);

        if (ObjectUtil.isNotNull(file)) {
            sysOss = ossService.upload(file);
        }
        FileUtil.del(tempPathCsv);
        return sysOss;
    }

    @Override
    public String batchExecute(TaskBo taskBo) {
        return null;
    }

    @Override
    public List<String> getDataHeader(Long ossId) {
        SysOssVo ossVo = ossService.getById(ossId);
        // 数据库资源地址
        String path = StringUtils.substringAfter(ossVo.getFileName(), Constants.RESOURCE_PREFIX);
        return CsvUtils.getCsvHeaders(path);
    }

    @Override
    public String getDataByOssId(Long ossId) {
        SysOssVo ossVo = ossService.getById(ossId);
        // 数据库资源地址
        String path = StringUtils.substringAfter(ossVo.getFileName(), Constants.RESOURCE_PREFIX);
        return CsvUtils.fileCsvToJson(path).toString();
    }
    @Override
    public JSONArray getArrayByOssId(Long ossId) {
        SysOssVo ossVo = ossService.getById(ossId);
        // 数据库资源地址
        String path = StringUtils.substringAfter(ossVo.getFileName(), Constants.RESOURCE_PREFIX);
        return CsvUtils.fileCsvToJsonRegex(path);
    }

    @Override
    public String executeQa(QaBo qaBo) {
        Map<String, Object> map = new HashMap<>();
        map.put("userId", qaBo.getUserId());
        map.put("question", qaBo.getQuestion());
        String result = HttpUtils.postJson(askUrl, map);
        JSONObject jsonObject = JSONUtil.parseObj(result);
        String data = jsonObject.getStr("data");
        String code = jsonObject.getStr("code");
        String msg = jsonObject.getStr("msg");
        if (!StrUtil.equals(code, "200")) {
            throw new BusinessException(msg);
        }
        JSONObject answerJson = JSONUtil.parseObj(data);
        String ossId = answerJson.getStr("ossId");
        String userId = answerJson.getStr("userId");
        String fileName = answerJson.getStr("fileName");
        Integer filePage = answerJson.getInt("filePage");
        String graph = answerJson.getStr("graphAnswer");
        QaHistoryBo qaHistoryBo = new QaHistoryBo();
        qaHistoryBo.setAnswer(answerJson.toString());
        if (StrUtil.isNotBlank(ossId)) {
            qaHistoryBo.setOssId(Long.valueOf(ossId));
        }
        qaHistoryBo.setUserId(userId);
        qaHistoryBo.setQuestion(qaBo.getQuestion());
        qaHistoryBo.setFileName(fileName);
        qaHistoryBo.setFilePage(filePage);
        qaHistoryBo.setGraph(graph);
        qaHistoryService.insert(qaHistoryBo);
        return data;
    }

    @Override
    public Map<String, Object> executeMath(Map<String, String> queryBo) {
        String code = queryBo.get("code");
        String sortieNo = queryBo.get("sortieNo");
        String beginTime = queryBo.get("beginTime");
        String endTime = queryBo.get("endTime");
        JudgeFaultLogicVo judgeFaultLogicVo = judgeFaultLogicService.selectByHmc(code);
        if (ObjectUtil.isEmpty(judgeFaultLogicVo)) {
            throw new BusinessException("判故逻辑不能为空，请配置.");
        }
        DataImportVo dataImportVo = dataImportService.selectBySortieNo(sortieNo);
        SysOssVo ossVo = ossService.getById(dataImportVo.getOssId());
//        SysOssVo ossVo = ossService.getById(252244732393746432L);
        // 数据库资源地址
        String path = StringUtils.substringAfter(ossVo.getFileName(), Constants.RESOURCE_PREFIX);
//        String columnData = "高压压气机转子转数,风扇转子转速";
        String columnData = judgeFaultLogicVo.getAttribute1();
        List<String> headerNames = Arrays.asList(columnData.split(","));
        JSONObject res = CsvUtils.getDataByHeaders(path, Arrays.asList(columnData.split(",")), beginTime, endTime);
        Map<String, Object> mapList = new HashMap<>();

        headerNames.forEach(header -> {
            JSONArray jsonArray = res.getJSONArray(header);
            if (StrUtil.equals("时间",header)) {
                return;
            }
            Map<String, Object> map = new HashMap<>();
            StatisticsCalculator.STATISTICS_MAP.forEach((k, v) -> {
                map.put(k, StatisticsCalculator.calculateStatistic(k, this.convert(jsonArray)));
            });
            mapList.put(header, map);
        });
        return mapList;
    }

    private double[] convert(JSONArray jsonArray) {
        if (jsonArray == null || jsonArray.isEmpty()) {
            return new double[0];
        }
        double[] doubleArray = new double[jsonArray.size()];
        for (int i = 0; i < jsonArray.size(); i++) {
            doubleArray[i] = Double.parseDouble(jsonArray.get(i).toString());
        }
        return doubleArray;
    }
}
