package com.jiayue.ipfcst.dataexchange.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONObject;
import com.jiayue.ipfcst.aop.SaveValidate;
import com.jiayue.ipfcst.common.core.exception.BusinessException;
import com.jiayue.ipfcst.common.core.web.vo.ResponseVO;
import com.jiayue.ipfcst.common.data.abst.equipmentinfo.AbstractEquipmentInfo;
import com.jiayue.ipfcst.common.data.constant.enums.DataSourceEnum;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.dataexchange.container.ProtocolTunnelContainer;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.repository.ForecastForSendAttributeRepository;
import com.jiayue.ipfcst.dataexchange.service.EquipmentAttributeService;
import com.jiayue.ipfcst.dataexchange.service.ProtocolGatherDataPointService;
import com.jiayue.ipfcst.dataexchange.service.ProtocolSenderDataPointService;
import com.jiayue.ipfcst.dataexchange.service.TunnelInfoService;
import com.jiayue.ipfcst.dataexchange.service.equipmentstatusdata.EquipmentInfoService;
import com.jiayue.ipfcst.dataexchange.tunnelworker.senders.DataSenderInterface;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 转发点表的controller
 *
 * @author zy
 * @version 3.0
 */
@Slf4j
@RestController
@RequestMapping("/dataExchange/senderProtocolDataPoint")
//TODO 路径名未符合驼峰
public class ProtocolSenderDataPointController {
  @Autowired
  EquipmentAttributeService equipmentAttributeService;
  private ProtocolSenderDataPointService protocolSenderDataPointService;
  private ProtocolGatherDataPointService protocolGatherDataPointService;
  private ForecastForSendAttributeRepository forecastForSendAttributeRepository;

  @Autowired
  public ProtocolSenderDataPointController(ProtocolSenderDataPointService protocolSenderDataPointService, ProtocolGatherDataPointService protocolGatherDataPointService, ForecastForSendAttributeRepository forecastForSendAttributeRepository) {
    this.protocolSenderDataPointService = protocolSenderDataPointService;
    this.protocolGatherDataPointService = protocolGatherDataPointService;
    this.forecastForSendAttributeRepository = forecastForSendAttributeRepository;
  }
  @Autowired TunnelInfoService tunnelInfoService;
  @Autowired EquipmentInfoService equipmentInfoService;
  /**
   * 查询所有转发点位
   *
   * @return ResponseVO response vo
   */
  @GetMapping("/senderDataPoint")
  public ResponseVO getSenderDataPoint() {
    try {
      return ResponseVO.success(protocolSenderDataPointService.get());
    } catch (Exception e) {
      e.printStackTrace();
      log.error("查询异常");
      return ResponseVO.fail();
    }
  }

  @GetMapping("/DataPoint")
  public ResponseVO getDataPoint() {
    try {
      List list = new ArrayList();
      List<ProtocolSenderDataPoint> senderDataPoints = protocolSenderDataPointService.get();
      List<ProtocolGatherDataPoint> gatherDataPoints = protocolGatherDataPointService.getAll();
      senderDataPoints.sort(Comparator.comparing(ProtocolSenderDataPoint::getTunnelId).thenComparing(ProtocolSenderDataPoint::getProtocolPointNo));
      for (int i = 0; i < senderDataPoints.size(); i++) {
        HashMap map = new HashMap();

        if (senderDataPoints.get(i).getGatherPoint() != null) {
          for (int j = 0; j < gatherDataPoints.size(); j++) {
            if (senderDataPoints.get(i).getGatherPoint().equals(gatherDataPoints.get(j).getId())) {
              map.put("sender", senderDataPoints.get(i));
              map.put("equipmentId", gatherDataPoints.get(j).getEquipmentId());
              map.put("equipmentAttribute", gatherDataPoints.get(j).getEquipmentAttribute());
              list.add(map);
            }
          }
        } else {
          map.put("sender", senderDataPoints.get(i));
          map.put("equipmentId", null);
          map.put("equipmentAttribute", null);
          list.add(map);
        }
      }
      return ResponseVO.success(list);
    } catch (Exception e) {
      e.printStackTrace();
      log.error("查询异常");
      return ResponseVO.fail();
    }
  }


  @GetMapping("/maxProtocolNoInTunnel")
  public ResponseVO getMaxProtocolNoInTunnel(String tunnelId) {
    return ResponseVO.success(protocolSenderDataPointService.getMaxProtocolNoInTunnel(tunnelId));
  }

  /**
   * 通过通道id查询转发点表
   *
   * @param tunnelId 通道id
   * @return ProtocolSenderDataPoint  protocol data  point
   */
  @GetMapping("/findByTunnelId/{tunnelId}")
  public ResponseVO findByTunnelId(@PathVariable("tunnelId") String tunnelId) {
    try {
      List<Map> list = protocolSenderDataPointService.getPointByTunnelId(tunnelId);
      return ResponseVO.success(list);
    } catch (Exception e) {
      e.printStackTrace();
      log.error("根据通道id查询异常");
      return ResponseVO.fail();
    }
  }

  /**
   * 通过通道id和采集id查询转发表
   *
   * @param tunnelId
   * @param equipmentId
   * @param equipmentType
   * @return ProtocolSenderDataPoint  protocol data  point
   */
  @GetMapping("/findByTunnelIdAndGatherPoint/{tunnelId}/{equipmentId}/{equipmentType}")
  public ResponseVO findByTunnelIdAndGatherPoint(@PathVariable("tunnelId") String tunnelId, @PathVariable("equipmentId") String equipmentId, @PathVariable("equipmentType") Integer equipmentType) {
    //TODO 代码不合理  需郑媛修改   方法所放置的类也不对   @CreateBy 修唯
    try {
      List list = protocolSenderDataPointService.getPointByTunnelIdAndPointId(tunnelId, equipmentId, equipmentType);
      return ResponseVO.success(list);
    } catch (Exception e) {
      e.printStackTrace();
      log.error("根据采集点表查询异常");
      return ResponseVO.fail();
    }
  }

  /**
   * 保存转发点位
   *
   * @param protocolSenderDataPoint 点位实体
   * @return ResponseVO response vo
   */
  @PostMapping("/saveDataPoint")
  @SaveValidate
  public ResponseVO saveSenderDataPoint(@RequestBody ProtocolSenderDataPoint protocolSenderDataPoint) {
    try {
      return ResponseVO.success(protocolSenderDataPointService.save(protocolSenderDataPoint));
    } catch (Exception e) {
      e.printStackTrace();
      log.error("保存转发点表异常");
      return ResponseVO.fail();
    }
  }


  /**
   * 批量保存转发点位
   *
   * @return ResponseVO response vo
   */
  @PostMapping("/batchSaveForecastPoint")
  @SaveValidate
  public ResponseVO batchSaveSenderDataPoint(@RequestBody JSONObject param) throws BusinessException {
    String tunnelId = param.getString("tunnelId");
    String protocolPointType = param.getString("protocolPointType");
    String forecastType = param.getString("forecastType");
    Integer[] forecastNodes = param.getObject("forecastNodes", Integer[].class);
    Integer[] pointNumbers = param.getObject("pointNumbers", Integer[].class);
    if (StringUtils.isEmpty(tunnelId) ||
      StringUtils.isEmpty(protocolPointType) ||
      StringUtils.isEmpty(forecastType) ||
      forecastNodes == null ||
      forecastNodes.length == 0 ||
      pointNumbers == null ||
      pointNumbers.length == 0
    ) {
      throw new BusinessException("查询参数不足");
    }
    ProtocolSenderDataPoint protocolSenderDataPoint = null;
    List<ForecastForSendAttribute> forecastForSendAttributes = null;
    Integer maxPointNum = protocolSenderDataPointService.getMaxProtocolNoInTunnel(tunnelId);
    if (maxPointNum == null) {
      maxPointNum = 0;
    }
    for (int i : forecastNodes) {
      for (int j : pointNumbers) {
        //依次批量添加转发点位
        protocolSenderDataPoint = new ProtocolSenderDataPoint();
        protocolSenderDataPoint.setTunnelId(tunnelId);
        protocolSenderDataPoint.setDataSource(DataSourceEnum.FORECAST);
        protocolSenderDataPoint.setProtocolPointType(ProtocolDataType.valueOf(protocolPointType));
        //根据预测 类型 的天数 和 天数内的点位来找到 数据库里的具体属性
        forecastForSendAttributes = forecastForSendAttributeRepository.findByPointNumberAndForecastNodeAndForecastType(j, i, ForecastForSendAttribute.ForecastType.valueOf(forecastType));
        if (forecastForSendAttributes.size() == 1) {
          protocolSenderDataPoint.setProtocolPointNo(++maxPointNum);
          protocolSenderDataPoint.setForecastForSendAttribute(forecastForSendAttributes.get(0));
          protocolSenderDataPointService.save(protocolSenderDataPoint);
        }
      }
    }
    return ResponseVO.success();
  }

  /**
   * 修改转发点表
   *
   * @param protocolSenderDataPoint 点位实体
   * @return ResponseVO response vo
   */
  @PutMapping("/updateDataPoint")
  @SaveValidate
  public ResponseVO updateSenderDataPoint(@RequestBody ProtocolSenderDataPoint protocolSenderDataPoint) {
    try {
      return ResponseVO.success(protocolSenderDataPointService.save(protocolSenderDataPoint));
    } catch (Exception e) {
      e.printStackTrace();
      log.error("修改转发点表异常");
      return ResponseVO.fail();
    }
  }

  /**
   * 删除转发点表
   *
   * @param id 点表id
   * @return ResponseVO response vo
   */
  @DeleteMapping("/deleteDataPoint/{id}")
  @SaveValidate
  public ResponseVO deleteById(@PathVariable("id") Integer id) {
    try {
      protocolSenderDataPointService.deleteById(id);
      return ResponseVO.success();
    } catch (Exception e) {
      e.printStackTrace();
      log.error("删除转发点表异常");
      return ResponseVO.fail();
    }
  }

  @DeleteMapping("/batchDeleteSenderDataPoint/{pointIds}")
  @SaveValidate
  public ResponseVO batchDeleteGatherDataPoint(@PathVariable Integer[] pointIds) {
    try {
      for (int i = 0; i < pointIds.length; i++) {
        ProtocolSenderDataPoint point = new ProtocolSenderDataPoint();
        point.setId(pointIds[i]);
        protocolSenderDataPointService.deleteAll(point);
      }
      return ResponseVO.success(1);
    } catch (Exception e) {
      e.printStackTrace();
      log.error("批量删除异常");
      return ResponseVO.fail(e);
    }
  }

  /**
   * 手动置数
   *
   * @param pointId 点id
   * @param value   值
   * @return {@link ResponseVO}* @throws DataExchangeException 数据交换异常
   */
  @GetMapping("/setValueByManual/{pointId}/{value}")
  @SaveValidate
  public ResponseVO setValueByManual(@PathVariable Integer pointId,@PathVariable Double value) throws DataExchangeException {
    ProtocolSenderDataPoint dataPoint=new ProtocolSenderDataPoint();
    dataPoint.setId(pointId);
    List<ProtocolSenderDataPoint> dataPointList = protocolSenderDataPointService.get(dataPoint);
    if(dataPointList!=null && dataPointList.size()==1){
      dataPoint=dataPointList.get(0);
      DataSenderInterface tunnel = (DataSenderInterface)ProtocolTunnelContainer.getInstance().getTunnel(dataPoint.getTunnelId());
      if(tunnel==null){
        return ResponseVO.fail(new BusinessException("关联的通道未启用或未关联通道"));
      }
      tunnel.setValueByManual(dataPoint,value);
    }
    return ResponseVO.success();
  }

  /*
  *
  * 导出
  */
  @RequestMapping("/export")
  @SaveValidate
  public void export(HttpServletResponse response) {
    try{
      ExcelWriter writer = ExcelUtil.getWriter();
      List<String> row2 = CollUtil
        .newArrayList("id", "数据源", "倍率", "通道名", "通道点位", "通道数据类型", "设备名", "设备类型", "设备属性", "预测数据属性", "预测天数（天/时）", "预测数据点位");
      List<List<String>> rows1 = CollUtil.newArrayList();
      rows1.add(row2);
      List<ProtocolSenderDataPoint> senderDataPoints = protocolSenderDataPointService.get();
      List<ProtocolGatherDataPoint> gatherDataPoints = protocolGatherDataPointService.getAll();
      List<BaseTunnelInfo> baseTunnelInfos = tunnelInfoService.findByTunnelType("Slave");
      senderDataPoints.sort(Comparator.comparing(ProtocolSenderDataPoint::getTunnelId).thenComparing(ProtocolSenderDataPoint::getProtocolPointNo));
      for (int i = 0; i < senderDataPoints.size(); i++) {
        HashMap map = new HashMap();
        List<String> row = CollUtil.newArrayList();
        String name = "";
        for(BaseTunnelInfo baseTunnelInfo : baseTunnelInfos){
          if(baseTunnelInfo.getId().equals(senderDataPoints.get(i).getTunnelId())){
            name = baseTunnelInfo.getTunnelName();
          }
        }
        if (senderDataPoints.get(i).getDataSource().toString().equals("GATHER")) {
          for (int j = 0; j < gatherDataPoints.size(); j++) {
            if (senderDataPoints.get(i).getGatherPoint().equals(gatherDataPoints.get(j).getId())) {
              List<AbstractEquipmentInfo> abstractEquipmentInfos = equipmentInfoService.findByEqType(gatherDataPoints.get(j).getEquipmentAttribute().getEquipmentType());
              String ename = "";
              for(AbstractEquipmentInfo abstractEquipmentInfo : abstractEquipmentInfos){
                if(abstractEquipmentInfo.getId().equals(gatherDataPoints.get(j).getEquipmentId())){
                  ename = abstractEquipmentInfo.getName();
                }
              }
              row.add(senderDataPoints.get(i).getId().toString());
              row.add(senderDataPoints.get(i).getDataSource().getMessage());
              row.add(senderDataPoints.get(i).getMagnification().toString());
              row.add(name);
              row.add(senderDataPoints.get(i).getProtocolPointNo().toString());
              row.add(senderDataPoints.get(i).getProtocolPointType().getDescribe());
              row.add(ename);
              row.add(gatherDataPoints.get(j).getEquipmentAttribute().getEquipmentType().getMessage());
              row.add(gatherDataPoints.get(j).getEquipmentAttribute().getExplanation());
              row.add("");
              row.add("");
              row.add("");
              rows1.add(row);
              row = null;
            }
          }
        }else {
          String forecastNode = "";
          if(senderDataPoints.get(i).getForecastForSendAttribute().getForecastType().toString().equals("ULTRA_SHORT_AVAILABLE") || senderDataPoints.get(i).getForecastForSendAttribute().getForecastType().toString().equals("ULTRA_SHORT_THEORETICAL")){
            switch (senderDataPoints.get(i).getForecastForSendAttribute().getForecastNode()){
              case 0: forecastNode = "第一小时";
                break;
              case 1: forecastNode = "第二小时";
                break;
              case 2: forecastNode = "第三小时";
                break;
              case 3: forecastNode = "第四小时";
                break;
            }
          } else {
            forecastNode = "第" + (senderDataPoints.get(i).getForecastForSendAttribute().getForecastNode()+1) + "天";
          }
          row.add(senderDataPoints.get(i).getId().toString());
          row.add(senderDataPoints.get(i).getDataSource().getMessage());
          row.add(senderDataPoints.get(i).getMagnification().toString());
          row.add(name);
          row.add(senderDataPoints.get(i).getProtocolPointNo().toString());
          row.add(senderDataPoints.get(i).getProtocolPointType().getDescribe());
          row.add("");
          row.add("");
          row.add("");
          row.add(senderDataPoints.get(i).getForecastForSendAttribute().getForecastType().getDescribe());
          //row.add(senderDataPoints.get(i).getForecastForSendAttribute().getForecastNode().toString());
          row.add(forecastNode);
          row.add("第" + senderDataPoints.get(i).getForecastForSendAttribute().getPointNumber().toString() + "节点");
          rows1.add(row);
          row = null;
        }
      }
      writer.setColumnWidth(0, 10);
        for(int i = 0 ; i<12;i++){
        writer.setColumnWidth(i+1, 15);
      }
      writer.write(rows1,true);
      String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
      String fileName = "转发点表" + now + ".xls";
      response.setContentType("application/x-msdownload;charset=utf-8");
      response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
      ServletOutputStream out= null;
      out = response.getOutputStream();
      writer.flush(out, true);
      // 关闭writer，释放内存
      writer.close();
      //此处记得关闭输出Servlet流
      IoUtil.close(out);
    }catch (IOException e) {
      e.printStackTrace();
    }
  }
}
