package com.jiayue.insu.incloud.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jiayue.insu.incloud.constants.enums.StatusEnum;
import com.jiayue.insu.incloud.constants.vo.FileCreateLog;
import com.jiayue.insu.incloud.entity.Record;
import com.jiayue.insu.incloud.entity.Station;
import com.jiayue.insu.incloud.service.MinIoService;
import com.jiayue.insu.incloud.service.RecordService;
import com.jiayue.insu.incloud.utils.JsonResultUtil;
import com.jiayue.insu.incloud.utils.SystermUtils;
import com.jiayue.insu.minio.util.MinioUtilService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 预测数据业务实现
 *
 * @author yh
 * @version 1.0
 * @since 2022/5/22 11:29
 */
@Slf4j
@Service
public class MinIoServiceImpl implements MinIoService {

    @Value("${minio.pull.url}")
    String url;
    @Value("${minio.pull.fileurl}")
    String fileurl;
    @Value("${minio.fileurl}")
    String fileDir;
    @Value("${minio.bucketname}")
    private String bucketName;
    @Value("${minio.pull.cloudFileCreateLog}")
    private String cloudFileCreateLog;
    @Value("${minio.postBackUrl}")
    private String postBackUrl;
    @Value("${minio.pushCorrFileUrl}")
    private String pushCorrFileUrl;

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    private MinioUtilService minioUtilService;
    @Autowired
    public RecordService recordService;


    /**
     * 向minIo中放入文件
     *
     * @param file
     * @param stationCode
     * @return
     */
    public JSONObject pushFileToMinIo(File file, String stationCode) {
        // 存放完文件后返回的文件路径
        String minIoFileUrl;
        InputStream in = null;
        InputStream inB = null;
        try {
            // 查看桶名称是否存在
            boolean flag = minioUtilService.bucketExists(bucketName);
            if (!flag) {
                return JsonResultUtil.failure("MinIo桶不存在");
            }
            // 向minIo中放入文件
            in = new FileInputStream(file);
            String fileName = "/" + stationCode + "/" + file.getName();
            minIoFileUrl = minioUtilService.putObject(bucketName, fileName, in);
            // 如果是AB机，向B中也放入文件
            if (stationCode.indexOf("-A") > 0) {
                // InputStream 在被读取后，指针已经移动到了流的末尾，第二次上传B时就已经没有数据了，故新建一个输入流
                inB = new FileInputStream(file);
                String fileNameB = "/" + stationCode.replace("-A", "-B") + "/" + file.getName();
                minIoFileUrl = minIoFileUrl + ";" + minioUtilService.putObject(bucketName, fileNameB, inB);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return JsonResultUtil.failure("推送MinIo失败");
        } finally {
            close(in);
            close(inB);
        }
        return JsonResultUtil.success(minIoFileUrl);
    }

    /**
     * 请求V3云平台返回上传minIo文件信息
     *
     * @param stationCode
     * @param fileName
     * @param fileDownloadUrl
     */
    public void postFileCreateInfoToCloud(String stationCode, String fileName, String fileDownloadUrl) {
        fileDownloadUrl = fileDownloadUrl.split("\\?")[0];
        Map<String, Object> urlMap = new HashMap<>();
        urlMap.put("stationCode", stationCode);
        urlMap.put("stationName", stationCode);
        urlMap.put("fileName", fileName);
        urlMap.put("fileDownloadUrl", fileDownloadUrl);
        urlMap.put("sign", SystermUtils.caluMd5Sign(stationCode + DateUtil.today()));
        try {
            String body = HttpUtil.post(cloudFileCreateLog, urlMap, 10000);
            JSONObject result = JSONUtil.parseObj(body);
            if (!"0".equals(result.getStr(JsonResultUtil.CODE_TAG))) {
                log.info("请求V3云平台失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("请求V3云平台失败");
        }
    }

    /**
     * 从minIo下载文件
     *
     * @param station
     * @param type
     * @return
     */
    public File downLoadFileFromMinIo(Station station, String type, String startTime, String endTime, JSONObject errMsg) {
        // 如果场站信息为空
        if (station == null) {
            log.info("场站信息为空");
            errMsg.set("msg", "场站信息为空");
            return null;
        }

        if (startTime == null || "".equals(startTime)) {
            log.info("文件获取失败，开始时间为空");
            errMsg.set("msg", "文件获取失败，开始时间为空");
            return null;
        }

        // 校验日期格式
        if (startTime.indexOf("-") == -1) {
            log.info("文件获取失败，开始时间格式不正确，正确格式为yyyy-MM-dd");
            errMsg.set("msg", "文件获取失败，开始时间格式不正确，正确格式为yyyy-MM-dd");
            return null;
        }

        Record record = new Record();
        log.info("下载minIo原始RB文件 --> {}" + station.getStationCode());
        try {
            // 从云上获取minIo中指定日期的文件信息 格式https://117.78.19.70:9010/client/getFileLogsForAio/J00260/2023-08-11
            String getUrl = url + station.getStationCode() + "/" + startTime;
            HttpRequest httpRequest = HttpRequest.get(getUrl);
            httpRequest.setGlobalTimeout(20000);
            String body = httpRequest.execute().body();
            JSONObject json = JSONUtil.parseObj(body);
            String data = json.get("data").toString();
            String code = json.get("code").toString();
            if (!code.equals("0") || data.length() <= 0) {
                record.setState(StatusEnum.RESPONSE_FAIL.getCode());
                log.error("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode(), StatusEnum.RESPONSE_FAIL.getMsg());
                errMsg.set("msg", "下载原始文件失败");
                return null;
            }
            // 获取文件信息列表
            JSONArray array = JSONUtil.parseArray(data);
            // 文件列表
            List<FileCreateLog> list = array.toList(FileCreateLog.class);
            // 如果文件列表为空，则未获取到文件
            if (CollectionUtil.isEmpty(list)) {
                record.setState(StatusEnum.FILE_NULL.getCode());
                log.info("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode(), StatusEnum.FILE_NULL.getMsg());
                errMsg.set("msg", "下载原始文件失败");
                return null;
            }

            // 保存文件路径
            String fileSaveUrl = fileDir + File.separatorChar + "init" + File.separatorChar + station.getStationCode();
            log.info("文件保存路径" + fileSaveUrl);
            File dir = new File(fileSaveUrl);
            if (!dir.exists()) {// 判断目录是否存在
                dir.mkdirs();
                log.info("创建目录:" + fileSaveUrl);
            }
            // 筛选指定日期短期文件
            List<FileCreateLog> listFile = new ArrayList<>();
            String nowUrl = "";
            String downloadFileName = "";
            // 如果是短期
            if ("dq".equals(type)) {
                listFile = list.stream().filter(f -> f.getFileName().contains("DQ_" + startTime.replace("-", ""))).collect(Collectors.toList());
                //  如果文件为空，
                if (CollectionUtil.isEmpty(listFile)) {
                    record.setState(StatusEnum.FILE_NULL.getCode());
                    log.error("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode() + " DQ文件", StatusEnum.FILE_NULL.getMsg());
                    errMsg.set("msg", "下载原始文件失败");
                    return null;
                }
                // 将短期文件倒序，获取最新的文件
                listFile.sort(Comparator.comparing(FileCreateLog::getFileName).reversed());
                // 拼接下载文件url=fileUrl(下载文件请求地址)+从minIo获取的最新一条的文件id
                nowUrl = fileurl + listFile.get(0).getId();
                downloadFileName = listFile.get(0).getFileName();
                // 如果是超短期
            } else if ("cdq".equals(type)) {
                // 格式化开始时间 将时间2019-10-10 01:15 转为=》201910100115
                String formatStartTime = startTime.replace("-", "").replace(" ", "").replace(":", "");
                // 根据CDQ_201910100115 筛选超短期文件
                listFile = list.stream().filter(f -> f.getFileName().contains("CDQ_" + formatStartTime)).collect(Collectors.toList());
            } else if ("nwp".equals(type)) {
                listFile = list.stream().filter(f -> f.getFileName().contains("NWP_" + startTime.replace("-", ""))).collect(Collectors.toList());
                // 将短期文件倒序，获取最新的文件
//                listFile.sort(Comparator.comparing(FileCreateLog::getFileName).reversed());
                listFile.sort(Comparator.comparing(FileCreateLog::getFileName));
                // 拼接下载文件url=fileUrl(下载文件请求地址)+从minIo获取的最新一条的文件id
                nowUrl = fileurl + listFile.get(0).getId();
                downloadFileName = listFile.get(0).getFileName();
            }
            //  如果文件为空，
            if (CollectionUtil.isEmpty(listFile)) {
                log.error("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode(), StatusEnum.FILE_NULL.getMsg());
                record.setState(StatusEnum.FILE_NULL.getCode());
                errMsg.set("msg", "下载原始文件失败");
                return null;
            }

            try {
                // 通过url下载文件
                File nowFile = HttpUtil.downloadFileFromUrl(nowUrl, fileSaveUrl + File.separatorChar + downloadFileName);
                if (nowFile == null) {
                    record.setState(StatusEnum.DOWNLOAD_FILE_ERROR.getCode());
                    log.error("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode(), StatusEnum.FILE_NULL.getMsg());
                    errMsg.set("msg", "下载原始文件失败");
                    return null;
                }

                // 回传dq和nwp文件状态
                this.postBackMinIoState(station.getStationCode(), nowFile.getName(), "down", "是");
                // 返回文件
                return nowFile;
            } catch (Exception e) {
                record.setState(StatusEnum.DOWNLOAD_FILE_FAIL.getCode());
                log.error("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode(), StatusEnum.DOWNLOAD_FILE_FAIL.getMsg());
                e.printStackTrace();
                errMsg.set("msg", "下载原始文件失败");
                return null;
            }
        } catch (Exception e) {
            record.setState(StatusEnum.RESPONSE_FAIL.getCode());
            log.error("下载minIo原始RB文件 --> {} 失败，失败原因:{}", station.getStationCode(), StatusEnum.RESPONSE_FAIL.getMsg());
            e.printStackTrace();
            errMsg.set("msg", "下载原始文件失败");
            return null;
        }
    }


    /**
     * 从minIo下载文件后，回传状态
     *
     * @param stationCode
     * @param fileName
     * @param type
     * @param status
     */
    @Override
    public void postBackMinIoState(String stationCode, String fileName, String type, String status) {
        Map urlParams = new HashMap(4);
        urlParams.put("stationCode", stationCode);
        urlParams.put("forecastFileName", fileName);
        urlParams.put("type", type);
        urlParams.put("status", status);
        log.debug("回传文件状态给新平台,请求参数", JSONUtil.toJsonStr(urlParams));
        String repose = HttpUtil.post(postBackUrl, urlParams, 10000);
        log.info("回传文件状态给新平台，请求相应 {}", repose);
    }


    /**
     * 判断是否是NULL 和是否是数值
     *
     * @param data
     * @return
     */
    public BigDecimal isNumberOrNull(String data) {
        BigDecimal bigDecimal = new BigDecimal("-99");
        if (!data.contains("null") && !data.contains("NULL")) {

            Pattern pattern = Pattern.compile("-[0-9]+(.[0-9]+)?|[0-9]+(.[0-9]+)?");
            Matcher isNum = pattern.matcher(data);
            try {
                if (isNum.matches()) {
                    bigDecimal = new BigDecimal(data).setScale(2, BigDecimal.ROUND_DOWN);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        return bigDecimal;
    }

    // 封装一个安全的关闭方法
    private static void close(InputStream inputStream) {
        if (inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace(); // 可选：日志记录
            }
        }
    }
}
