package com.tuoheng.admin.service.airData.report;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tuoheng.admin.entity.domain.AirData;
import com.tuoheng.admin.entity.domain.AirDataExport;
import com.tuoheng.admin.entity.domain.AirDataType;
import com.tuoheng.admin.entity.domain.Inspection;
import com.tuoheng.admin.entity.request.report.ExportReportRequest;
import com.tuoheng.admin.enums.MarkEnum;
import com.tuoheng.admin.mapper.AirDataExportMapper;
import com.tuoheng.admin.mapper.AirDataMapper;
import com.tuoheng.admin.mapper.AirDataTypeMapper;
import com.tuoheng.admin.mapper.InspectionMapper;
import com.tuoheng.admin.utils.AliyunOSSUtil;
import com.tuoheng.admin.utils.CurrentUserUtil;
import com.tuoheng.common.core.config.UploadFileConfig;
import com.tuoheng.common.core.exception.ServiceException;
import com.tuoheng.common.core.utils.DateUtils;
import com.tuoheng.common.core.utils.FileUtils;
import com.tuoheng.common.core.utils.JsonResult;
import com.tuoheng.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ExportReportService {

    @Autowired
    private InspectionMapper inspectionMapper;

    @Autowired
    private AirDataMapper airDataMapper;

    @Autowired
    private AirDataTypeMapper airDataTypeMapper;

    @Autowired
    private AirDataExportMapper airDataExportMapper;

    @Autowired
    private GenerateReportWordService generateReportWordService;

    @Autowired
    private AliyunOSSUtil aliyunOSSUtil;

    public JsonResult exportReport(ExportReportRequest request) {
        JsonResult result = this.check(request);
        if (0 != result.getCode()) {
            log.info("导出报告：校验失败：{}", result.getMsg());
            return result;
        }
        AirDataType airDataType = airDataTypeMapper.selectOne(Wrappers.<AirDataType>lambdaQuery()
                .eq(AirDataType::getDataType, request.getAirDataType())
                .eq(AirDataType::getMark, MarkEnum.VALID.getCode()));
        if (ObjectUtil.isEmpty(airDataType)) {
            log.info("导出报告，大气类型不存在，airDataType={}", request.getAirDataType());
            throw new ServiceException("大气类型不存在");
        }
        AirDataExport airDataExport = this.checkAirDataExport(request, airDataType);
        if (ObjectUtil.isNotEmpty(airDataExport)) {
            return JsonResult.success(airDataExport.getOssUrl(), "导出成功");
        }
        Inspection inspection = (Inspection) result.getData();
        List<AirData> airDataList = airDataMapper.selectList(Wrappers.<AirData>lambdaQuery()
                .eq(AirData::getMark, MarkEnum.VALID.getCode())
                .eq(AirData::getInspectionId, request.getInspectionId())
                .orderByAsc(AirData::getCreateTime));
        String detectionTime = "";
        if (CollectionUtil.isNotEmpty(airDataList)) {
            detectionTime = this.getDetectionTime(airDataList);
            this.handle(request, airDataType, airDataList);
        }
        String filename = inspection.getName() + "-" + inspection.getCode() + "-" + airDataType.getDataType() + ".doc";
        String filePath = UploadFileConfig.uploadFolder + "/report/" + filename;
        File fd = new File(UploadFileConfig.uploadFolder + "/report");
        if (!fd.exists()) {
            fd.mkdirs();
        }
        // 生成word
        File f = new File(filePath);
        if (!f.exists() || f.length() < 1000) {
            result = generateReportWordService.buildWord(filePath, request, airDataType, detectionTime, inspection.getEquipmentMountCode());
            if (0 != result.getCode()) {
                log.info("导出报告业务：生成word失败：{}", result.getMsg());
                return result;
            }
        }

        // 上传到oss
        String ossUrl = this.uploadOss(filePath, filename);

        // 记录
        this.insertAirDataExport(request, inspection, airDataType, ossUrl);

        // 删除原文件
        FileUtils.deleteFile(filePath);

        return JsonResult.success(ossUrl, "导出成功");
    }

    /**
     * 检查参数
     *
     * @param request
     * @return
     */
    private JsonResult check(ExportReportRequest request) {
        if (StringUtils.isEmpty(request.getInspectionId())) {
            log.info("导出报告，任务ID为空，inspectionId={}", request.getInspectionId());
            throw new ServiceException("任务ID为空");
        }
        if (StringUtils.isEmpty(request.getAirDataType())) {
            log.info("导出报告，大气数据类型为空，airDataType={}", request.getAirDataType());
            throw new ServiceException("大气数据类型为空");
        }
        if (StringUtils.isEmpty(request.getOssUrl())) {
            log.info("导出报告，大气数据图片为空，ossUrl={}", request.getOssUrl());
            throw new ServiceException("大气数据图片为空");
        }
        Inspection inspection = inspectionMapper.selectById(request.getInspectionId());
        if (ObjectUtil.isEmpty(inspection)) {
            log.info("导出报告，任务不存在，inspectionId={}", request.getInspectionId());
            throw new ServiceException("任务不存在");
        }
        return JsonResult.success(inspection);
    }

    private AirDataExport checkAirDataExport(ExportReportRequest request, AirDataType airDataType) {
        AirDataExport airDataExport = airDataExportMapper.selectOne(new LambdaQueryWrapper<AirDataExport>()
                .eq(AirDataExport::getInspectionId, request.getInspectionId())
                .eq(AirDataExport::getAirDataTypeId, airDataType.getId())
                .eq(AirDataExport::getExportType, "report")
                .eq(AirDataExport::getGridSize, request.getGridSize())
                .eq(AirDataExport::getMark, MarkEnum.VALID.getCode())
                .last("limit 1"));
        return airDataExport;
    }

    /**
     * @param airDataList
     * @return
     */
    private String getDetectionTime(List<AirData> airDataList) {
        AirData beginAirData = airDataList.get(0);
        AirData endAirData = airDataList.get(airDataList.size() - 1);
        String detectionTime = "";
        if (ObjectUtil.isNotEmpty(beginAirData)) {
            detectionTime += beginAirData.getCUtcTime();
        }
        detectionTime += "至";
        if (ObjectUtil.isNotEmpty(endAirData)) {
            detectionTime += endAirData.getCUtcTime();
        }
        return detectionTime;
    }

    private void handle(ExportReportRequest request, AirDataType airDataType, List<AirData> airDataList) {
        List<Double> list = null;
        AirData airDataMax = null;
        AirData airDataMin = null;
        String singlePointConcentrationMax = "";
        String singlePointConcentrationMin = "";
        if ("co".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getCo())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getCo()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getCo()))).get();
            singlePointConcentrationMax = airDataMax.getCo();
            singlePointConcentrationMin = airDataMin.getCo();
        } else if ("pm_10".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getPm10())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getPm10()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getPm10()))).get();
            singlePointConcentrationMax = airDataMax.getPm10();
            singlePointConcentrationMin = airDataMin.getPm10();
        } else if ("pm_2_5".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getPm25())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getPm25()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getPm25()))).get();
            singlePointConcentrationMax = airDataMax.getPm25();
            singlePointConcentrationMin = airDataMin.getPm25();
        } else if ("so2".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getSo2())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getSo2()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getSo2()))).get();
            singlePointConcentrationMax = airDataMax.getSo2();
            singlePointConcentrationMin = airDataMin.getSo2();
        } else if ("vocs".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getVocs())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getVocs()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getVocs()))).get();
            singlePointConcentrationMax = airDataMax.getVocs();
            singlePointConcentrationMin = airDataMin.getVocs();
        } else if ("no2".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getNo2())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getNo2()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getNo2()))).get();
            singlePointConcentrationMax = airDataMax.getNo2();
            singlePointConcentrationMin = airDataMin.getNo2();
        } else if ("o3".equals(airDataType.getDataType())) {
            list = airDataList.stream().map(p -> Double.parseDouble(p.getO3())).collect(Collectors.toList());
            airDataMax = airDataList.stream().max(Comparator.comparing(x -> Double.parseDouble(x.getO3()))).get();
            airDataMin = airDataList.stream().min(Comparator.comparing(x -> Double.parseDouble(x.getO3()))).get();
            singlePointConcentrationMax = airDataMax.getO3();
            singlePointConcentrationMin = airDataMin.getO3();
        } else {
            log.info("大气类型，暂不提供, airDataType={}", airDataType.getDataType());
            return;
        }
        double average = list.stream().collect(Collectors.averagingDouble(Double::doubleValue));
        String averageConcentration = average + airDataType.getUnit();
        singlePointConcentrationMax = singlePointConcentrationMax + " " + airDataType.getUnit() + "(" + airDataMax.getLongitude() + "E, " + airDataMax.getLatitude() + "N) " + airDataMax.getCUtcTime();
        singlePointConcentrationMin = singlePointConcentrationMin + " " + airDataType.getUnit() + "(" + airDataMin.getLongitude() + "E, " + airDataMin.getLatitude() + "N) " + airDataMin.getCUtcTime();

        request.setSamplingPointsNum(String.valueOf(airDataList.size()));
        request.setAverageConcentration(averageConcentration);
        request.setSinglePointConcentrationMax(singlePointConcentrationMax);
        request.setSinglePointConcentrationMin(singlePointConcentrationMin);
    }

    private String uploadOss(String filePath, String filename) {
        File file = new File(filePath);
        InputStream in;
        String fileUrl;
        try {
            in = new FileInputStream(file);
            aliyunOSSUtil.uploadFile2OSS(in, filename);
            fileUrl = aliyunOSSUtil.getFileUrl(filename);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        return fileUrl;
    }

    /**
     * @param request
     * @param inspection
     * @param airDataType
     * @param ossUrl
     */
    private void insertAirDataExport(ExportReportRequest request, Inspection inspection, AirDataType airDataType, String ossUrl) {
        // 记录
        AirDataExport airDataExport = new AirDataExport();
        airDataExport.setTenantId(inspection.getTenantId());
        airDataExport.setInspectionId(request.getInspectionId());
        airDataExport.setExportType("report");
        airDataExport.setAirDataTypeId(airDataType.getId());
        airDataExport.setGridSize(request.getGridSize());
        airDataExport.setOssUrl(ossUrl);
        airDataExport.setCreateUser(CurrentUserUtil.getUserId());
        airDataExport.setCreateTime(DateUtils.now());
        Integer count = airDataExportMapper.insert(airDataExport);
        if (count <= 0) {
            log.info("添加大气数据报告导出记录失败");
        }
    }
}
