package org.eco.als.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
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.Warning;
import org.eco.als.domain.bo.AlgorithmBo;
import org.eco.als.domain.bo.FalseAlarmBo;
import org.eco.als.domain.bo.FalseAlarmResultBo;
import org.eco.als.domain.bo.FaultDiagnosisBo;
import org.eco.als.domain.bo.PreProcessingBo;
import org.eco.als.domain.bo.TaskBo;
import org.eco.als.domain.vo.ModelHttpVo;
import org.eco.als.domain.vo.ModelVo;
import org.eco.als.service.IAlgorithmService;
import org.eco.als.service.IDataImportService;
import org.eco.als.service.IFalseAlarmResultService;
import org.eco.als.service.IFalseAlarmService;
import org.eco.als.service.IFaultDiagnosisService;
import org.eco.als.service.IModelService;
import org.eco.als.service.IPreProcessingService;
import org.eco.als.service.ITaskService;
import org.eco.als.service.IWarningService;
import org.eco.als.utils.CsvUtils;
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.stereotype.Service;

import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

    @Resource
    private IDataImportService dataImportService;

    @Resource
    private ISysOssService ossService;

    @Resource
    private IPreProcessingService processingService;

    @Resource
    private IWarningService warningService;

    @Resource
    private IFalseAlarmService falseAlarmService;

    @Resource
    private IFalseAlarmResultService falseAlarmResultService;

    @Resource
    private IFaultDiagnosisService faultDiagnosisService;

    @Resource
    private ITaskService taskService;

    private static ModelHttpVo sendHttp(ModelVo modelVo, Map<String, Object> map) {
        try {
            String result = HttpUtils.postJson(modelVo.getUrl(), map);
            JSONObject jsonObject = JSONUtil.parseObj(result);
            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
    public String executePro(AlgorithmBo algorithmBo) {
        // 模型相关信息
        ModelVo modelVo = modelService.selectById(algorithmBo.getModelId());
        if (ObjectUtil.isNull(modelVo)) {
            throw new BusinessException("模型信息为空，请检查！");
        }

        SysOssVo sysOssVo = getSysOssVo(algorithmBo);
        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();
        processingService.insert(processingBo);
        // 参数
        Map<String, Object> map = 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");
            processingService.update(processingBo);
        }
        return httpVo != null ? httpVo.getData() : null;
    }

    /**
     * executeFalseAlarm 虚警抑制
     *
     * @param algorithmBo 参数
     * @return java.lang.String
     **/
    @Override
    public String executeFalseAlarm(AlgorithmBo algorithmBo) {
        // 虚警抑制校验警告列表
        if (ObjectUtil.isNull(algorithmBo.getWarningIds())) {
            throw new BusinessException("警告信息不能为空，请检查！");
        }
        // 模型相关信息
        ModelVo modelVo = modelService.selectById(algorithmBo.getModelId());
        if (ObjectUtil.isNull(modelVo)) {
            throw new BusinessException("模型信息为空，请检查！");
        }
        SysOssVo sysOssVo = getSysOssVo(algorithmBo);
        if (sysOssVo == null) {
            return null;
        }
        FalseAlarmBo falseAlarmBo = FalseAlarmBo.builder()
            .ossId(sysOssVo.getOssId())
            .aircraftId(algorithmBo.getAircraftId())
            .modelType(modelVo.getType())
            .sortieNo(algorithmBo.getSortieNo())
            .param(algorithmBo.getParam())
            .status("0")
            .columnData(Arrays.toString(algorithmBo.getColumnData()))
            .build();
        falseAlarmService.insert(falseAlarmBo);

        // 警告列表
        List<Warning> warnings = warningService.listByIds(Arrays.asList(algorithmBo.getWarningIds()));
        Warning warning = warnings.getFirst();
        warnings.forEach(el -> {
        });
        // 参数
        Map<String, Object> map = new HashMap<>(JSONUtil.parseObj(algorithmBo.getParam()));
        map.put("url", sysOssVo.getUrl());
        // 请求
        ModelHttpVo httpVo = sendHttp(modelVo, map);
        if (httpVo != null && httpVo.getStatus() == 200) {
            falseAlarmBo.setStatus("1");
            falseAlarmService.update(falseAlarmBo);
            FalseAlarmResultBo falseAlarmResultBo = FalseAlarmResultBo.builder()
                .falseAlarmId(falseAlarmBo.getId())
                .code(warning.getCode())
                .name(warning.getName())
                .aircraftId(warning.getAircraftId())
                .sortieNo(warning.getSortieNo())
                .status(httpVo.getData())
                .build();
            falseAlarmResultService.insert(falseAlarmResultBo);
        }
        return httpVo != null ? httpVo.getData() : null;
    }

    /**
     * executeFault 故障诊断
     *
     * @param algorithmBo 参数
     * @return java.lang.String
     **/

    @Override
    public String executeFault(AlgorithmBo algorithmBo) {
        // 模型相关信息
        ModelVo modelVo = modelService.selectById(algorithmBo.getModelId());
        if (ObjectUtil.isNull(modelVo)) {
            throw new BusinessException("模型信息为空，请检查！");
        }
        SysOssVo sysOssVo = getSysOssVo(algorithmBo);
        if (sysOssVo == null) {
            return null;
        }
        FaultDiagnosisBo diagnosisBo = FaultDiagnosisBo.builder()
            .ossId(sysOssVo.getOssId())
            .aircraftId(algorithmBo.getAircraftId())
            .modelType(modelVo.getType())
            .sortieNo(algorithmBo.getSortieNo())
            .param(algorithmBo.getParam())
            .status("0")
            .columnData(Arrays.toString(algorithmBo.getColumnData()))
            .build();
        faultDiagnosisService.insert(diagnosisBo);
        // 参数
        Map<String, Object> map = new HashMap<>(JSONUtil.parseObj(algorithmBo.getParam()));
        map.put("url", sysOssVo.getUrl());
        // 请求
        ModelHttpVo httpVo = sendHttp(modelVo, map);
        if (httpVo != null && httpVo.getStatus() == 200) {
            diagnosisBo.setStatus("1");
            diagnosisBo.setResultContent(httpVo.getData());
            faultDiagnosisService.update(diagnosisBo);
        }
        return httpVo != null ? httpVo.getData() : null;
    }

    private SysOssVo getSysOssVo(AlgorithmBo algorithmBo) {
        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 =CsvUtils.getCsvDataByHeaders(path, Arrays.asList(algorithmBo.getColumnData()), null);
        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) {
        // 数据编号
        Long dataId;
        // 预处理编号
        Long preId;
        // 虚警编号
        Long falseAlarmId;
        // 故障诊断编号
        Long faultId;
        // 决策编号
        Long decisionId;
        List<AlgorithmBo> algorithmList = taskBo.getAlgorithmList();
        // 批量执行
        algorithmList.forEach(el -> {
            executePro(el);
            executeFalseAlarm(el);
            executeFault(el);
        });
        taskService.insert(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();
    }
}
