package com.tofly.custom.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haiqiu.tools.common.utils.HttpServletUtils;
import com.tofly.common.ExcelTool.ExcelColumn;
import com.tofly.common.ExcelTool.ExcelTool;
import com.tofly.common.constant.CalendarHelper;
import com.tofly.common.core.entity.ResultRespone;
import com.tofly.common.log.annotation.ToFlyAppLog;
import com.tofly.custom.entity.dto.ScadaReportDto;
import com.tofly.custom.entity.dto.WisdomDisplayDto;
import com.tofly.custom.entity.vo.*;
import com.tofly.custom.service.CustomDisplayService;
import com.tofly.scada.entity.DeviceArchiveManage;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author JF
 * @date 2023-1-6
 * @description 自定义智慧综合展示相关
 */
@RestController
@RequestMapping("/customDisplay")
/*@AllArgsConstructor*/
@RefreshScope
@Api(tags = "自定义智慧综合展示")
public class CustomDisplayController {

    @Autowired
    private CustomDisplayService customDisplayService;

    /**
     * 水厂进指标
     */
//    @Value("${waterSupplyJin.codesAll}")
    private String waterSupplyJinAll;
    /**
     * 水厂出指标
     */
//    @Value("${waterSupplyChu.codesAll}")
    private String waterSupplyChuAll;

    /**
     * 水厂总瞬时流量
     */
//    @Value("${waterSupplyChu.codesFlow}")
    private String waterSupplyChuFlow;


    /**
     * @param wisdomDisplayDto 自定义智慧综合展示筛选字段对象
     */
    @PostMapping("/viewStationDeviceIndex")
    @ApiOperation(value = "查询厂站设备指标数据（厂站分组）")
    public ResultRespone<List<WaterStationVo>> viewStationDeviceIndex(WisdomDisplayDto wisdomDisplayDto) {
        try {

            return ResultRespone.success(customDisplayService.viewStationDeviceIndex(wisdomDisplayDto,waterSupplyJinAll,waterSupplyChuAll));
        } catch (Exception e) {
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    /**
     * @param wisdomDisplayDto 自定义智慧综合展示筛选字段对象
     */
    @PostMapping("/viewStationIndex")
    @ApiOperation(value = "查询厂站指标数据（厂站分组）")
    public ResultRespone<List<WaterStationVo>> viewStationIndex(WisdomDisplayDto wisdomDisplayDto) {
        try {
            return ResultRespone.success(customDisplayService.viewStationIndex(wisdomDisplayDto,waterSupplyJinAll,waterSupplyChuAll));
        } catch (Exception e) {
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    /**
     * @param wisdomDisplayDto 自定义智慧综合展示筛选字段对象
     */
    @PostMapping("/viewDeviceIndex")
    @ApiOperation(value = "查询设备指标数据（设备分组）")
    public ResultRespone<List<DeviceArchiveManage>> viewDeviceIndex(WisdomDisplayDto wisdomDisplayDto) {
        try {
            return ResultRespone.success(customDisplayService.viewDeviceIndex(wisdomDisplayDto));
        } catch (Exception e) {
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    /**
     * @param startDate  开始时间（yyyy-MM-dd HH:mm:ss）
     * @param endDate    结束时间（yyyy-MM-dd HH:mm:ss）
     * @param indexTypes 指标类型（多个用,分隔）
     */
    @GetMapping("/getWaterSourceScada")
    @ApiOperation(value = "统计不同水源的SCADA数据")
    public ResultRespone<List<WaterSourceScadaVo>> getWaterSourceScada(@ApiParam("开始时间（yyyy-MM-dd HH:mm:ss）") @RequestParam(value = "startDate") String startDate,
                                                                       @ApiParam("结束时间（yyyy-MM-dd HH:mm:ss）") @RequestParam(value = "endDate") String endDate,
                                                                       @ApiParam("指标类型（多个用,分隔）") @RequestParam(value = "indexTypes", required = false) String indexTypes) {
        try {
            return ResultRespone.success(customDisplayService.getWaterSourceScada(startDate, endDate, indexTypes));
        } catch (Exception e) {
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    /**
     * @param
     * @description 指标相关值统计
     */
    @GetMapping("/indexValCensus")
    @ApiOperation(value = "指标相关值统计")
    public ResultRespone<IndexValCensusVo> indexValCensus() {
        try {
            return ResultRespone.success(customDisplayService.indexValCensus());
        } catch (Exception e) {
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    @PostMapping("/getScadaIndexData")
    @ApiOperation(value = "查询SCADA指标数据")
    @ToFlyAppLog(title = "查询SCADA指标数据")
    public ResultRespone<List<ScadaIndexVo>> getScadaIndexData(WisdomDisplayDto dto){
        try {
            return ResultRespone.success(customDisplayService.getScadaIndexData(dto));
        }catch (Exception e){
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    @PostMapping("/getScadaHistoryData")
    @ApiOperation(value = "查询SCADA历史数据")
    @ToFlyAppLog(title = "查询SCADA历史数据")
    public ResultRespone getHistoryPageData(Page page,WisdomDisplayDto dto){
        try {
            return ResultRespone.success(customDisplayService.getHistoryPageData(page,dto));
        }catch (Exception e){
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    @GetMapping("/getUserTotalMonth")
    @ApiOperation(value = "按月统计用户总数")
    @ToFlyAppLog(title = "按月统计用户总数")
    public ResultRespone<List<UserTotalVo>> getUserTotalMonth(@ApiParam("开始时间（yyyy-MM-dd HH:mm:ss）") @RequestParam(value = "startDate") String startDate,
                                                               @ApiParam("结束时间（yyyy-MM-dd HH:mm:ss）") @RequestParam(value = "endDate") String endDate){
        try {
            return ResultRespone.success(customDisplayService.getUserTotalMonth(startDate, endDate));
        }catch (Exception e){
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    @GetMapping("/getDeviceByType")
    @ApiOperation(value = "通过设备类型分组获取设备列表")
    @ToFlyAppLog(title = "通过设备类型分组获取设备列表")
    public ResultRespone<List<DeviceByTypeVo>> getDeviceByType(@ApiParam("设备名称（模糊查询）") @RequestParam(value = "deviceName", required = false) String deviceName){
        try {
            return ResultRespone.success(customDisplayService.getDeviceByType(deviceName));
        }catch (Exception e){
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }


    @GetMapping("/getIndexListByType")
    @ApiOperation(value = "根据指标类型查询指标")
    @ToFlyAppLog(title = "根据指标类型查询指标")
    public ResultRespone getIndexListByType(
            @ApiParam("水厂类型，支持多个") @RequestParam(value = "waterType", required = false)
          String waterType,
        @ApiParam("指标类型，支持多个") @RequestParam(value = "indexType", required = false)String indexType){

        try {
            return ResultRespone.success(customDisplayService.getIndexListByType(waterType,indexType));
        }catch (Exception e){
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    @PostMapping("/getScadaCommReport")
    @ApiOperation(value = "查询SCADA指标数据")
    @ToFlyAppLog(title = "查询SCADA指标数据")
    public ResultRespone<List<ScadaIndexReportVo>> getScadaIndexReport(
           @Validated @RequestBody ScadaReportDto dto){
        try {
            List<ScadaIndexReportVo>  list=customDisplayService.getScadaCommReport(waterSupplyChuFlow,dto);
            if(dto.getExportStatus()!=null &&dto.getExportStatus()==1){
                 exportScadaIndexReport(list,dto.getExportTitle());
                return ResultRespone.success(null);
            }else{
               return ResultRespone.success(list);
            }
        }catch (Exception e){
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }

    /**
     * 构建树形结构导出
     * @param list 数据集合
     * @param exportTitle 导出标题
     * @throws Exception
     */
    public  void exportScadaIndexReport(List<ScadaIndexReportVo> list,String exportTitle) throws Exception {
        List<Map<String,String>> titleList=new ArrayList<>();

        //构建导出的表头，树形结构，包含标题
        Map<String,String> titleMap= new HashMap<>();
        //表头标题
        titleMap.put("id","-1");titleMap.put("pid","0");titleMap.put("content",exportTitle);titleMap.put("fielName",null);
        titleList.add(titleMap);
        Map<String,String> titleMap1= new HashMap<>();
        //多表头第一行固定，时间
        titleMap1.put("id","time");titleMap1.put("pid","-1");titleMap1.put("content","时间");titleMap1.put("fielName","time");
        titleList.add(titleMap1);

        Map<String,String> titleMap2=new HashMap<String,String>();
        //多表头第二行固定，总流量(m³)
        titleMap2.put("id","totalFlow");titleMap2.put("pid","-1");
        titleMap2.put("content","总流量(m³)");titleMap2.put("fielName","totalFlow");
        titleList.add(titleMap2);
        //取list第一个数据构建动态表头
        List<WaterNameVo> waterNameVos=list.get(0).getWaterNameVos();
        waterNameVos.forEach(waterName->{

             Map<String,String> titleMapWater= new HashMap<>();
             //一级表头，水厂
             titleMapWater.put("id",waterName.getWaterId());
             titleMapWater.put("pid","-1");
             titleMapWater.put("content",waterName.getWaterName());
             titleMapWater.put("fielName",null);
             titleList.add(titleMapWater);
            //一级表头，水厂下二级表头，根据指标来构建
             waterName.getScadaList().forEach(scada->{
                 Map<String,String> scadaMapWater= new HashMap<>();
                 scadaMapWater.put("id",scada.getCode());scadaMapWater.put("pid",scada.getWaterId());
                 if(StringUtils.isNotBlank(scada.getUnit()) && !scada.getUnit().equals("null")){
                     scadaMapWater.put("content",scada.getVariableName()+"("+scada.getUnit()+")");
                 }else{
                     scadaMapWater.put("content",scada.getVariableName());

                 }
                scadaMapWater.put("fielName",scada.getCode());
                 //fielName很重要，填充数据时候，根据fileName对应的值来的
                 titleList.add(scadaMapWater);

         });




       });

        //填充行数据 rowList
        List<Map<String,String>> rowList=new ArrayList<>();
        //列表里面的数据放到listVo里面，方便找最大值，最小值所对应的时间
        List<ScadaFlowVo> listVo=new ArrayList<>();
        //循环填充数据
        list.forEach(item->{
            Map<String,String> rowMap= new HashMap<>();
            rowMap.put("time",item.getDateTime());
            rowMap.put("totalFlow",item.getTotalFlow());
            item.getWaterNameVos().forEach(waterNameVo->{
                 waterNameVo.getScadaList().forEach(scadaFlowVo -> {
                     rowMap.put(scadaFlowVo.getCode(),scadaFlowVo.getValue()+"");
                     listVo.add(scadaFlowVo);

                 });

             });
            rowList.add(rowMap);

        });

        //取总流量最小值，最大值和对应的时间
        Comparator<ScadaIndexReportVo> scadaTotalFlowVoComparator=Comparator.comparing(scada->Double.parseDouble(scada.getTotalFlow()));
        ScadaIndexReportVo totalFlowMin=list.stream().min(scadaTotalFlowVoComparator).orElse(null);
        ScadaIndexReportVo totalFlowMax=list.stream().max(scadaTotalFlowVoComparator).orElse(null);

        Map<String,String> rowMinTotalMap=new HashMap<String,String>();
        Map<String,String> rowMaxTotalMap=new HashMap<String,String>();

        rowMinTotalMap.put("time","最小值");
        if(totalFlowMin!=null){
            rowMinTotalMap.put("totalFlow",totalFlowMin.getTotalFlow()+"("+totalFlowMin.getDateTime()+")");
        }
        if(totalFlowMax!=null){
            rowMaxTotalMap.put("totalFlow",totalFlowMax.getTotalFlow()+"("+totalFlowMax.getDateTime()+")");
        }
        rowMaxTotalMap.put("time","最大值");
        String simpleDateFormat="yyyy-MM-dd HH:mm:ss";
       Map<String,List<ScadaFlowVo>> listMaps=listVo.stream().collect(Collectors.groupingBy(ScadaFlowVo::getCode));
       //按照指标编码分组，取里面的最大值和最小值和对应的时间
          listMaps.forEach((code,voList)->{
                Comparator<ScadaFlowVo> scadaFlowVoComparator=Comparator.comparing(scada->Double.parseDouble(scada.getValue()));
                ScadaFlowVo maxScadaFlowVo=voList.stream().max(scadaFlowVoComparator).orElse(null);
                ScadaFlowVo minScadaFlowVo=voList.stream().min(scadaFlowVoComparator).orElse(null);
               if(minScadaFlowVo!=null){
                   rowMinTotalMap.put(code,minScadaFlowVo.getValue()+"("+CalendarHelper.getFormatDate(minScadaFlowVo.getScadaTime(),simpleDateFormat)+")");
               }
                if(maxScadaFlowVo!=null){
                    rowMaxTotalMap.put(code,maxScadaFlowVo.getValue()+"("+ CalendarHelper.getFormatDate(maxScadaFlowVo.getScadaTime(),simpleDateFormat)+")");
                }
            });
        rowList.add(rowMinTotalMap);

        rowList.add(rowMaxTotalMap);

        //导出测试
        ExcelTool excelTool = new ExcelTool(exportTitle);
        List<ExcelColumn>  titleData=excelTool.columnTransformer(titleList,"id","pid","content","fielName","0");
        //excelTool.exportExcel(titleData,rowList,"D://Demo//test6.xlsx",true,true);
        excelTool.export(exportTitle, excelTool.exportWorkbook(titleData,rowList,true,true), HttpServletUtils.getServletResponse());

    }

    /**
     * @param
     * @description 手动同步缓存表
     */
    @GetMapping("/synStatisticsScada")
    @ApiOperation(value = "手动同步缓存表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "同步类型 0同步小时 1同步天 2同步月 3同步年", dataType = "String"),
            @ApiImplicitParam(name = "startTime", value = "开始时间 yyyy-MM-dd HH:mm:ss", dataType = "String"),
            @ApiImplicitParam(name = "endTime", value = "结束时间 yyyy-MM-dd HH:mm:ss", dataType = "String")
    })
    public ResultRespone synStatisticsScada(String type, String startTime, String endTime) {
        try {
            customDisplayService.synStatisticsScada(type, startTime, endTime);
            return ResultRespone.success();
        } catch (Exception e) {
            e.printStackTrace();
            return ResultRespone.failed(e.getMessage());
        }
    }
}
