package com.ruoyi.system.service.impl;


import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.dto.PrintExcelDTO;
import com.ruoyi.system.dto.TaskResultSortDTO;
import com.ruoyi.system.dto.WaterLevelDTO;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.paramet.AchievementQuery;
import com.ruoyi.system.paramet.ScattperPlotQuery;
import com.ruoyi.system.paramet.WaterLevelQuery;
import com.ruoyi.system.service.AchievementService;
import com.ruoyi.system.service.SiteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * classname: 站点信息
 * description  服务实现类
 */
@Service
@Slf4j
public class AchievementServiceImpl implements AchievementService {

    @Resource
    private TaskResultMapper taskResultMapper;

    @Resource
    private WaterLevelMapper waterLevelMapper;

    @Resource
    private SiteInfoMapper siteInfoMapper;

    @Resource
    private BerthingPointMapper berthingPointMapper;

    @Resource
    private SiteService siteService;

    @Autowired
    private BerthingPointConfigMapper berthingPointConfigMapper;


    @Override
    public Page<TaskResult> queryAchievement(AchievementQuery achievementQuery){
        if (achievementQuery.getPage() == null || achievementQuery.getSize() == null) {
            achievementQuery.setPage(1L);
            achievementQuery.setSize(10L);
        }
        return taskResultMapper.queryAllByLimit(achievementQuery ,new Page(achievementQuery.getPage(),achievementQuery.getSize()));
    }

    @Override
    public TaskResult queryAchievementByTaskid(String taskid){
        return taskResultMapper.queryByTaskid(taskid);
    }



    @Override
    public Page<WaterLevelDTO> getWaterLevelList(WaterLevelQuery waterLevelQuery){

        if (waterLevelQuery.getType() == null){
            waterLevelQuery.setType(1L);
        }
        if (waterLevelQuery.getPage() == null || waterLevelQuery.getSize() == null) {
            waterLevelQuery.setPage(1L);
            waterLevelQuery.setSize(10L);
        }
        return waterLevelMapper.queryAllByTime(waterLevelQuery,new Page(waterLevelQuery.getPage(),waterLevelQuery.getSize()));

    }

    @Override
    public void downAchievement(Long resultId, HttpServletResponse response) {
        ExcelWriter excelWriter = null;
        try {
            //查询resultId结果
            TaskResult taskResult = taskResultMapper.queryById(resultId);
            if (taskResult == null){
                throw new BaseException("该结果不存在");
            }
            if (taskResult.getStatus() != 2){
                throw new BaseException("结果未完成,不支持导出");
            }
            //查询站点信息
            SiteInfo siteInfo = siteInfoMapper.queryById(taskResult.getSiteId());
            if (siteInfo == null){
                throw new BaseException("该站点不存在");
            }
            //查站点详情
            SiteConfig siteConfig = siteService.queryConfig(siteInfo.getSiteId());
            if (siteConfig ==  null){
                throw new BaseException("该站点配置不存在");
            }

            //拿断面数据
            BerthingPoint berthingPoint = berthingPointMapper.queryById(taskResult.getBerthingId());
            if (berthingPoint == null){
                throw new BaseException("断面不存在");
            }
            //拿停泊点数据
            BerthingPointConfig berthingPointConfig = berthingPointConfigMapper.queryById(taskResult.getStopId());
            if (berthingPointConfig == null){
                throw new BaseException("停泊点配置不存在");
            }

            OutputStream outputStream = response.getOutputStream();
            // 模版文件
            ClassPathResource classPathResource = new ClassPathResource("excel/test.xlsx");
            String templateFileName = classPathResource.getFile().getPath();
            excelWriter = EasyExcel.write(outputStream).withTemplate(templateFileName).excelType(ExcelTypeEnum.XLSX).autoCloseStream(Boolean.FALSE).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            //先组装单数据
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("stieName", siteInfo.getSiteName());
            map.put("startTime", taskResult.getStarttime());
            map.put("endTime", taskResult.getEndtime());
            map.put("flowsum", taskResult.getFlowsum());
            map.put("width", taskResult.getWidth());
            map.put("waterlevel",taskResult.getWaterlevel());
            map.put("acreagesum",taskResult.getAcreagesum());
            List<Double> WspeedsList = JSONUtil.parseArray(taskResult.getWspeeds()).toList(Double.class);
            double averageWspeed = WspeedsList.stream().mapToDouble(d -> d).average().orElse(Double.NaN);
            BigDecimal averageWspeedBigDecimal = new BigDecimal(averageWspeed).setScale(2, RoundingMode.HALF_UP);
            Double maxWspeed = WspeedsList.stream().max(Double::compareTo).orElse(Double.NaN);
            List<Double> waterlevelList = JSONUtil.parseArray(taskResult.getWaterlevels()).toList(Double.class);
            double averageWaterlevel = waterlevelList.stream().mapToDouble(d -> d).average().orElse(Double.NaN);
            BigDecimal averageWaterlevelBigDecimal = new BigDecimal(averageWaterlevel).setScale(2, RoundingMode.HALF_UP);
            Double maxWaterlevel = waterlevelList.stream().max(Double::compareTo).orElse(Double.NaN);
            map.put("agWaterlevels",averageWaterlevelBigDecimal.toString());
            map.put("maxWaterlevels",String.valueOf(maxWaterlevel));
            map.put("agWspeeds",averageWspeedBigDecimal.toString());
            map.put("maxWspeeds",String.valueOf(maxWspeed));
            excelWriter.fill(map, writeSheet);

            //拿断面数据
            List<PrintExcelDTO> positionsList = JSONUtil.toList(berthingPoint.getPositions(), PrintExcelDTO.class);
            //组装列表
            List<Map<String, Object>> dataList = new ArrayList<>();
            List<Map<String, Object>> pgList = new ArrayList<>();
            List<Double> taskX = JSONUtil.toList(taskResult.getPositions(), Double.class);
            List<Double> taskY = JSONUtil.toList(taskResult.getElevations(), Double.class);
            List<String> pointConfigfactors = JSONUtil.toList(berthingPointConfig.getFactors(), String.class);
            List<String> taskWspeeds = JSONUtil.toList(taskResult.getWspeeds(), String.class);
            List<String> taskStopwspeeds = JSONUtil.toList(taskResult.getStopwspeeds(), String.class);
            List<String> tasKPartwspeeds = JSONUtil.toList(taskResult.getPartwspeeds(), String.class);
            List<String> acreages = JSONUtil.toList(taskResult.getAcreages(), String.class);
            List<String> taskFlows = JSONUtil.toList(taskResult.getFlows(), String.class);

            int pnIndex = 0;
            for (int i = 0; i < positionsList.size(); i++) {
                Map<String, Object> data = MapUtils.newHashMap();
                if (i == 0) {
                    String str = siteConfig.getLocal() == 0 ? "左水边" : "右水边";
                    data.put("index", str);
                } else if (i == positionsList.size() - 1) {
                    String str = siteConfig.getLocal() == 1 ? "左水边" : "右水边";
                    data.put("index", str);
                } else {
                    data.put("index", String.valueOf(i));
                }
                data.put("x", positionsList.get(i).getX().toString());
                data.put("y", positionsList.get(i).getY().toString());
                data.put("waterlevel",taskResult.getWaterlevel());
                data.put("subWlevel",BigDecimal.valueOf(taskResult.getWaterlevel()).subtract(BigDecimal.valueOf(positionsList.get(i).getY())));

                if (pnIndex < taskX.size()) {
                    if (taskX.get(pnIndex).equals(positionsList.get(i).getX()) && taskY.get(pnIndex).equals(positionsList.get(i).getY())) {
                        data.put("speed", String.valueOf(pnIndex + 1));
                        data.put("time", "12:00");
                        data.put("factors", pointConfigfactors.get(pnIndex));
                        data.put("wspeeds", taskWspeeds.get(pnIndex));
                        data.put("stopwspeeds", taskStopwspeeds.get(pnIndex));
                        pnIndex = pnIndex + 1;
                    } else {
                        data.put("speed", "");
                        data.put("time", "");
                        data.put("factors", "");
                        data.put("wspeeds", "");
                        data.put("stopwspeeds", "");
                    }
                } else {
                    data.put("speed", "");
                    data.put("time", "");
                    data.put("factors", "");
                    data.put("wspeeds", "");
                    data.put("stopwspeeds", "");
                }
                dataList.add(data);
            }
            pnIndex = 0;
            //新循环
            for (int i = 0; i < positionsList.size(); i++) {
                Map<String, Object> pgData = MapUtils.newHashMap();
                if (i < positionsList.size() - 1) {
                    if (pnIndex < taskX.size()) {
                        if (taskX.get(pnIndex).equals(positionsList.get(i).getX()) && taskY.get(pnIndex).equals(positionsList.get(i).getY())) {
                            pgData.put("partwspeeds", tasKPartwspeeds.get(pnIndex));
                            if (i < 2) {
                                pgData.put("add", acreages.get(0));//部分
                            } else {
                                BigDecimal bd1 = new BigDecimal(acreages.get(i));
                                BigDecimal bd2 = new BigDecimal(acreages.get(i - 1));
                                BigDecimal add = bd1.add(bd2);
                                pgData.put("add", add.toString());
                            }
                            pgData.put("flows", taskFlows.get(pnIndex));//部分流量
                            pnIndex = pnIndex + 1;
                        } else {
                            pgData.put("partwspeeds","");
                            pgData.put("add", "");
                            pgData.put("flows", "");
                        }
                    }
                    Map<String, Object> temp1 = dataList.get(i);
                    Map<String, Object> temp2 = dataList.get(i + 1);
                    // 将字符串转换为BigDecimal
                    BigDecimal bd1 = new BigDecimal(temp1.get("subWlevel").toString());
                    BigDecimal bd2 = new BigDecimal(temp2.get("subWlevel").toString());
                    // 求和
                    BigDecimal sum = bd1.add(bd2);
                    // 求平均值
                    BigDecimal average = sum.divide(new BigDecimal(2), 2, RoundingMode.HALF_UP);
                    pgData.put("subWlevel", average.toString());  //平均水深
                    bd1 = new BigDecimal(temp1.get("x").toString());
                    bd2 = new BigDecimal(temp2.get("x").toString());
                    BigDecimal subx = bd2.subtract(bd1);
                    pgData.put("subx", subx.toString()); //间距
                    pgData.put("acreages", acreages.get(i)); //垂线间
                    pgList.add(pgData);
                }
            }


            dataList = insertEmptyDataOnEvenRows(dataList);
            pgList = insertEmptyDataOnEvenRows(pgList);
            excelWriter.fill(new FillWrapper("details", dataList), writeSheet);
            excelWriter.fill(new FillWrapper("pg", pgList), writeSheet);

            // 设置输出流格式以及文件名：
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("质检任务", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        } catch (Exception e) {
            log.error("下载失败", e);
            throw new BaseException(e.getMessage());
        } finally {
            if (excelWriter != null) {
                excelWriter.close();
            }
        }
    }


    @Override
    public List<TaskResultSortDTO> getScatterPlot(ScattperPlotQuery scattperPlotQuery){
        try {
            return taskResultMapper.queryByTimeQuery(scattperPlotQuery);
        } catch (Exception e){
            log.error("获取数据失败", e);
            throw new BaseException("获取数据失败");
        }
    }

    @Override
    public void downWaterLevel(Long siteId, Long type, String startTime, String endTime, HttpServletResponse response){
        WaterLevelQuery waterLevelQuery = new WaterLevelQuery();
        FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
        try {
            Date startTimedDate = fdf.parse(startTime);
            Date endTimedDate = fdf.parse(endTime);
            waterLevelQuery.setSiteId(siteId);
            waterLevelQuery.setStartTime(startTimedDate);
            waterLevelQuery.setEndTime(endTimedDate);
            waterLevelQuery.setType(type);
            List<WaterLevelDTO> waterLevelList = waterLevelMapper.queryAllByTime(waterLevelQuery, new Page(1, 1000000)).getRecords();
            if (!waterLevelList.isEmpty()) {
                response.setContentType("application/octet-stream; charset=utf-8");
                String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
                String fileName = "downWaterLevel_".concat(today);
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                WriteSheet detailSheet = EasyExcel.writerSheet(0, "水位数据").head(WaterLevelDTO.class).build();
                excelWriter.write(waterLevelList, detailSheet);
                excelWriter.finish();
            }
        } catch (Exception e) {
            log.error("水位列表下载失败",e);
        }

    }


    @Override
    public void downScatterPlot(Long siteId, String startTime, String endTime, HttpServletResponse response){
        ScattperPlotQuery scattperPlotQuery = new ScattperPlotQuery();
        FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
        try {
            Date startTimedDate = fdf.parse(startTime);
            Date endTimedDate = fdf.parse(endTime);
            scattperPlotQuery.setSiteId(siteId);
            scattperPlotQuery.setStartTime(startTimedDate);
            scattperPlotQuery.setEndTime(endTimedDate);
            List<TaskResultSortDTO> taskResultList = taskResultMapper.queryByTimeQuery(scattperPlotQuery);
            if (!taskResultList.isEmpty()) {
                response.setContentType("application/octet-stream; charset=utf-8");
                String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
                String fileName = "downScatterPlot_".concat(today);
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
                ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                WriteSheet detailSheet = EasyExcel.writerSheet(0, "测流结果").head(TaskResultSortDTO.class).build();
                excelWriter.write(taskResultList, detailSheet);
                excelWriter.finish();
            }
        } catch (Exception e) {
            log.error("测流结果下载失败",e);
        }


    }





    public static <T> List<T> insertEmptyDataOnEvenRows(List<T> list) {
        List<T> modifiedList = new ArrayList<>(list.size() * 2 - 1); // 预估新列表的大小
        for (int i = 0; i < list.size(); i++) {
            modifiedList.add(list.get(i));  // 添加原始元素
            if (i < list.size() - 1) {  // 避免在最后一个元素后插入
                modifiedList.add(list.get(i));  // 在每个元素后插入空白数据
            }
        }
        return modifiedList;
    }




}
