package com.tofly.spire.service.impl;


import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haiqiu.tools.excel.utils.ExcelUtils;
import com.tofly.common.core.util.StringUtil;
import com.tofly.pojo.User;
import com.tofly.scada.entity.Allocation;
import com.tofly.scada.entity.Scada;
import com.tofly.scada.entity.ScadaMonitor;
import com.tofly.scada.service.ScadaMonitorService;
import com.tofly.scada.service.ScadaService;
import com.tofly.scada.service.SpireBigBaseService;
import com.tofly.spire.common.Constants;
import com.tofly.spire.entity.*;
import com.tofly.spire.entity.dto.SpireBigGridDto;
import com.tofly.spire.mapper.SpireBigGridMapper;
import com.tofly.spire.service.*;
import com.tofly.spire.utils.ResultScada;
import com.tofly.spire.utils.SpireUtils;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.swing.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 大表（管网）(SpireBigGrid)表服务实现类
 *
 * @author HaiQiu
 * @since 2022-11-11 09:16:07
 */
@Slf4j
@Service("spireBigGridService")
public class SpireBigGridServiceImpl extends ServiceImpl<SpireBigGridMapper, SpireBigGrid> implements SpireBigGridService {

    @Autowired
    private SpireUtils spireUtils;

    @Autowired
    private DeviceArchiveManageService deviceArchiveManageService;

    @Autowired
    private IndexAllocationService allocationService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ScadaService scadaService;

    @Autowired
    private ScadaMonitoringRealtimeService scadaMonitoringRealtimeService;

    @Autowired
    private SpireBigBaseService spireBigBaseService;

    /**
     * 定时获取-此接口用户获取主网表具数据信息以及日志信息。
     *
     * @param params
     * @return
     */
    @XxlJob("getBulkMeterData")
//    @Scheduled(cron = "0 0/1 * * * ?")
    public ReturnT getBulkMeterData(String params) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        String format = DateUtil.format(calendar.getTime(), "yyyy-MM-dd");
        getBulkMeterData(format, false, null);
        return ReturnT.SUCCESS;
    }

    /**
     * 定时任务--同步管网数据分发到其它表里面，5分钟1次
     * @param params
     * @return
     */
    @XxlJob("getBulkMSynData")
    @Async
    public ReturnT getBulkMSynData(String params) {
        synData();
        return ReturnT.SUCCESS;
    }

    /**
     * 同步管网数据
     *
     * @param date  日期 yyyy-mm-dd
     * @param clean 是否清空原始旧数据
     * @param sn    设备sn
     * @return 同步成功条数
     */
    @Override
    @Async
    public long getBulkMeterData(String date, Boolean clean, String sn) {

        //新增或者修改实时数据
        ResultScada bulkMeterBaseData = spireUtils.getBulkMeterData(null, null);
        List<SpireBigBase> dataBase = JSONObject.parseArray(bulkMeterBaseData.getData().toString(), SpireBigBase.class);
        if(dataBase.size()>0){
            dataBase.forEach(a->{
                SpireBigBase spireBigBase= spireBigBaseService.list(Wrappers.<SpireBigBase>lambdaQuery()
                        .eq(SpireBigBase::getSn,a.getSn())).stream().findFirst().orElse(null);
                if(spireBigBase!=null){
                    a.setId(spireBigBase.getId());

                }

            });
            spireBigBaseService.saveOrUpdateBatch(dataBase);
        }

        ResultScada bulkMeterData = spireUtils.getBulkMeterData(sn, date);
        List<SpireBigGrid> data = JSONObject.parseArray(bulkMeterData.getData().toString(), SpireBigGrid.class);
        log.info("获取到接口数据：{}条", data.size());

        Date getReadTime=null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            getReadTime = sdf.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        //查找库里面大于查询时间的所有数据
        List<SpireBigGrid>  list_old=super.list(Wrappers.<SpireBigGrid>lambdaQuery()
                .ge(SpireBigGrid::getReadTime,getReadTime));

        if(list_old.size()>0){
            //取不同的差集，用于新增数据
            List<SpireBigGrid> list_diff=data.stream().filter(x->list_old.stream().noneMatch(e->e.getSn().equals(x.getSn()) && e.getReadTime().equals(x.getReadTime()))).collect(Collectors.toList());
             if(list_diff.size()>0){
                 //添加
                 saveBatch(list_diff);
             }

        }else{
            saveBatch(data);
        }

        return data.size();
    }

public  String str(String str){
        if(StringUtils.isEmpty(str)){
            return "";
        }
        return str;
}
    /**
     * 分发数据同步数据
     */
    @Override
    @Async
   public long synData(){
        Page page=new Page();
        page.setCurrent(1);
        page.setSize(300); //每次取1000条数据进行同步
        long total=0L;
       Page<SpireBigGrid> listPage=super.page(page,Wrappers.<SpireBigGrid>lambdaQuery()
                .eq(SpireBigGrid::getStatus,"0").orderByAsc(SpireBigGrid::getReadTime));

        List<SpireBigBase> ListSpireBigBase=spireBigBaseService.list();
       if(listPage.getTotal()>0){
         List<SpireBigGrid> spireBigGrids=listPage.getRecords();
            total=spireBigGrids.stream().count();
           for (SpireBigGrid spireBigGrid : spireBigGrids) {
               //新增设备
                 SpireBigBase spireBigBase=ListSpireBigBase.stream().filter(a->a.getSn().equals(spireBigGrid.getSn())).findFirst().orElse(null);
                 if(spireBigBase!=null){
                       spireBigGrid.setMeterName(spireBigBase.getMeterName());
                       spireBigGrid.setLatitude(spireBigBase.getLatitude());
                       spireBigGrid.setLongitude(spireBigBase.getLongitude());
                       spireBigGrid.setMeterType(spireBigBase.getMeterType());
                       spireBigGrid.setMeterStatus(spireBigBase.getMeterStatus());

               }


               int count = deviceArchiveManageService.count(Wrappers.<TfDeviceArchiveManage>lambdaQuery()
                       .eq(TfDeviceArchiveManage::getCode, spireBigGrid.getSn()));
               if (count == 0) {
                   log.info("正在添加设备添加");
                   TfDeviceArchiveManage manage = new TfDeviceArchiveManage();

                   manage.setName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()));
                   manage.setStatus("1");
                   manage.setType("2");
                   if(StringUtil.isNotEmpty(spireBigGrid.getLongitude())){
                       manage.setLongitude(new BigDecimal(spireBigGrid.getLongitude()));

                   }
                   if(StringUtil.isNotEmpty(spireBigGrid.getLatitude())){
                       manage.setLatitude(new BigDecimal(spireBigGrid.getLatitude()));

                   }
                   manage.setCode(spireBigGrid.getSn());
                   deviceArchiveManageService.save(manage);
                   //新增指标
                   log.info("正在添加新增指标");
                   saveAllocations(spireBigGrid, manage);
               } else {
                   //新增指标
                   List<TfDeviceArchiveManage> list = deviceArchiveManageService.list(Wrappers.<TfDeviceArchiveManage>lambdaQuery()
                           .eq(TfDeviceArchiveManage::getCode, spireBigGrid.getSn()));
                   if (!CollectionUtils.isEmpty(list)) {
                       log.info("正在添加新增指标");
                       saveAllocations(spireBigGrid, list.get(0));
                   }
               }
               //新增历史表数据
               log.info("正在添加新增历史表数据");
             boolean flag= saveScadas(spireBigGrid);
               spireBigGrid.setStatus(flag?"1":"2");
               this.updateById(spireBigGrid);

           }
       }
      return total;
    }


    /**
     * 自动新增指标
     *
     * @param spireBigGrid
     * @param manage
     */
    private void saveAllocations(SpireBigGrid spireBigGrid, TfDeviceArchiveManage manage) {
        //新增指标累计量(m³)
        if (allocationService.count(Wrappers.<IndexAllocation>lambdaQuery()
                .eq(IndexAllocation::getVariableCode, spireBigGrid.getSn() + "." + Constants.accFlow)) == 0) {
            IndexAllocation allocation = new IndexAllocation();
            allocation.setDeviceId(manage.getId());
            allocation.setCreateTime(new Date());
            allocation.setDisplayName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "#累计量#" + Constants.accFlow);
            allocation.setVariableName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "." + Constants.accFlow);
            allocation.setVariableCode(spireBigGrid.getSn() + "." + Constants.accFlow);
            allocationService.save(allocation);
        }
        //新增指标反向累积量 (m³)
        if (allocationService.count(Wrappers.<IndexAllocation>lambdaQuery()
                .eq(IndexAllocation::getVariableCode, spireBigGrid.getSn() + "." + Constants.decAccFlow)) == 0) {
            IndexAllocation allocation = new IndexAllocation();
            allocation.setDeviceId(manage.getId());
            allocation.setCreateTime(new Date());
            allocation.setDisplayName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "#反向累积量#" + Constants.decAccFlow);
            allocation.setVariableName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "." + Constants.decAccFlow);
            allocation.setVariableCode(spireBigGrid.getSn() + "." + Constants.decAccFlow);
            allocationService.save(allocation);
        }
        //新增指标瞬时量 (m³/h)
        if (allocationService.count(Wrappers.<IndexAllocation>lambdaQuery()
                .eq(IndexAllocation::getVariableCode, spireBigGrid.getSn() + "." + Constants.flow)) == 0) {
            IndexAllocation allocation = new IndexAllocation();
            allocation.setDeviceId(manage.getId());
            allocation.setCreateTime(new Date());
            allocation.setDisplayName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "#瞬时量#" + Constants.flow);
            allocation.setVariableName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "." + Constants.flow);
            allocation.setVariableCode(spireBigGrid.getSn() + "." + Constants.flow);
            allocationService.save(allocation);
        }
        //新增指标进水温度 (℃)
        if (allocationService.count(Wrappers.<IndexAllocation>lambdaQuery()
                .eq(IndexAllocation::getVariableCode, spireBigGrid.getSn() + "." + Constants.inTemp)) == 0) {
            IndexAllocation allocation = new IndexAllocation();
            allocation.setDeviceId(manage.getId());
            allocation.setCreateTime(new Date());
            allocation.setDisplayName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "#进水温度#" + Constants.inTemp);
            allocation.setVariableName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "." + Constants.inTemp);
            allocation.setVariableCode(spireBigGrid.getSn() + "." + Constants.inTemp);
            allocationService.save(allocation);
        }
        //新增压力值 (kPa
        if (allocationService.count(Wrappers.<IndexAllocation>lambdaQuery()
                .eq(IndexAllocation::getVariableCode, spireBigGrid.getSn() + "." + Constants.pressure)) == 0) {
            IndexAllocation allocation = new IndexAllocation();
            allocation.setDeviceId(manage.getId());
            allocation.setCreateTime(new Date());
            allocation.setDisplayName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "#压力值#" + Constants.pressure);
            allocation.setVariableName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "." + Constants.pressure);
            allocation.setVariableCode(spireBigGrid.getSn() + "." + Constants.pressure);
            allocationService.save(allocation);
        }
        //新增指标出水温度 (℃)
        if (allocationService.count(Wrappers.<IndexAllocation>lambdaQuery()
                .eq(IndexAllocation::getVariableCode, spireBigGrid.getSn() + "." + Constants.temp)) == 0) {
            IndexAllocation allocation = new IndexAllocation();
            allocation.setDeviceId(manage.getId());
            allocation.setCreateTime(new Date());
            allocation.setDisplayName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "#出水温度#" + Constants.temp);
            allocation.setVariableName(spireBigGrid.getSn() + str(spireBigGrid.getMeterName()) + "." + Constants.temp);
            allocation.setVariableCode(spireBigGrid.getSn()+ "." + Constants.temp);
            allocationService.save(allocation);
        }
        log.info("正在添加新增指标-------------------->完成");
    }


    /**
     * 保存实时数据，历史数据
     * @param scada
     */
    @Async
    public void saveScadaAndHistory(Scada scada){
        ScadaMonitoringRealtime scadaMonitoringRealtime = new ScadaMonitoringRealtime();
        BeanUtils.copyProperties(scada, scadaMonitoringRealtime);

        Integer count=scadaMonitoringRealtimeService.count(Wrappers.<ScadaMonitoringRealtime>lambdaQuery()
                .eq(ScadaMonitoringRealtime::getCode,scada.getCode())
                .eq(ScadaMonitoringRealtime::getScadaTime,scada.getScadaTime()));
        if(count==0){
            scadaMonitoringRealtimeService.saveOrUpdate(scadaMonitoringRealtime);

        }


       /* //历史数据保存
        Scada scadaHistory=scadaService.list(Wrappers.<Scada>lambdaQuery()
                .eq(Scada::getCode,scada.getCode())
                .eq(Scada::getScadaTime,scada.getScadaTime())).stream().findFirst().orElse(null);
       if(scadaHistory!=null && scadaHistory.getId()>0){

           scada.setId(scadaHistory.getId());
       }
        scadaService.saveOrUpdate(scada);
       boolean isOption=true;
       //查询实时表中是否存在数据 SCADA_MONITORING
        ScadaMonitor scadaMonitor=new ScadaMonitor();
        ScadaMonitor scadaMonitorHistory=scadaMonitorService.list(Wrappers.<ScadaMonitor>lambdaQuery()
                .eq(ScadaMonitor::getCode,scada.getCode())).stream().findFirst().orElse(null);
        if(scadaMonitorHistory!=null && scadaMonitorHistory.getId()>0){

            scadaMonitor.setId(scadaMonitorHistory.getId());
            //判断日期大小，只保存最新日期的数据
            if(!scadaMonitorHistory.getScadaTime().before(scada.getScadaTime())){
                isOption=false;
            }
        }
        if(isOption){
            scadaMonitor.setCode(scada.getCode());
            scadaMonitor.setScadaTime(scada.getScadaTime());
            scadaMonitor.setValue(scada.getValue());
            scadaMonitorService.saveOrUpdate(scadaMonitor);
        }*/

    }


    public boolean saveScadas(SpireBigGrid spireBigGrid) {
      try{
        //新增指标累计量(m³)
        if (StringUtils.hasText(spireBigGrid.getAccFlow())) {
            Scada scada = new Scada();
            scada.setCode(spireBigGrid.getSn() + "." + Constants.accFlow);
            scada.setScadaTime(spireBigGrid.getReadTime());
            scada.setUpdateTime(new Date());
            scada.setValue(spireBigGrid.getAccFlow());
            saveScadaAndHistory(scada);

        }
        //新增指标反向累积量 (m³)
        if (StringUtils.hasText(spireBigGrid.getDecAccFlow())) {
            Scada scada = new Scada();
            scada.setCode(spireBigGrid.getSn() + "." + Constants.decAccFlow);
            scada.setScadaTime(spireBigGrid.getReadTime());
            scada.setUpdateTime(new Date());
            scada.setValue(spireBigGrid.getDecAccFlow());
            saveScadaAndHistory(scada);
        }
        //新增指标瞬时量 (m³/h)
        if (StringUtils.hasText(spireBigGrid.getFlow())) {
            Scada scada = new Scada();
            scada.setCode(spireBigGrid.getSn() + "." + Constants.flow);
            scada.setScadaTime(spireBigGrid.getReadTime());
            scada.setUpdateTime(new Date());
            scada.setValue(spireBigGrid.getFlow());
            saveScadaAndHistory(scada);
        }
        //新增指标进水温度 (℃)
        if (StringUtils.hasText(spireBigGrid.getInTemp())) {
            Scada scada = new Scada();
            scada.setCode(spireBigGrid.getSn() + "." + Constants.inTemp);
            scada.setScadaTime(spireBigGrid.getReadTime());
            scada.setUpdateTime(new Date());
            scada.setValue(spireBigGrid.getInTemp());
            saveScadaAndHistory(scada);
        }
        //新增压力值 (kPa），转换成MPa
        if (StringUtils.hasText(spireBigGrid.getPressure())) {
            Scada scada = new Scada();
            scada.setCode(spireBigGrid.getSn() + "." + Constants.pressure);
            scada.setScadaTime(spireBigGrid.getReadTime());
            scada.setUpdateTime(new Date());
            Float Pressure=Float.valueOf(spireBigGrid.getPressure())/1000F;
            scada.setValue(Pressure.toString());
            saveScadaAndHistory(scada);
        }
        //新增指标出水温度 (℃)
        if (StringUtils.hasText(spireBigGrid.getTemp())) {
            Scada scada = new Scada();
            scada.setCode(spireBigGrid.getSn() + "." + Constants.temp);
            scada.setScadaTime(spireBigGrid.getReadTime());
            scada.setUpdateTime(new Date());
            scada.setValue(spireBigGrid.getTemp());
            saveScadaAndHistory(scada);
        }
      }catch (Exception ex){
          log.error(ex.getMessage());
          return false;
      }
      return true;
    }

    /**
     * 根据ID查询
     *
     * @param id id
     * @return 数据
     */
    @Override
    public SpireBigGrid get(Serializable id) {
        return getById(id);
    }

    /**
     * 新增
     *
     * @param spireBigGridDto 实体
     */
    @Override
    public void insert(SpireBigGridDto spireBigGridDto) {
        SpireBigGrid spireBigGrid = convert(spireBigGridDto);
        if (!save(spireBigGrid)) {
            throw new RuntimeException("新增失败");
        }
    }

    /**
     * 修改
     *
     * @param spireBigGridDto 实体
     */
    @Override
    public void edit(SpireBigGridDto spireBigGridDto) {
        SpireBigGrid spireBigGrid = convert(spireBigGridDto);
        if (!updateById(spireBigGrid)) {
            throw new RuntimeException("修改失败");
        }
    }

    /**
     * 实体转换
     *
     * @param spireBigGridDto dto实体
     */
    private SpireBigGrid convert(SpireBigGridDto spireBigGridDto) {
        SpireBigGrid spireBigGrid = new SpireBigGrid();
        BeanUtils.copyProperties(spireBigGridDto, spireBigGrid);
        return spireBigGrid;
    }

    /**
     * 批量删除
     *
     * @param idList 数据ID集合
     */
    @Override
    public void delete(List<Long> idList) {
        if (!removeByIds(idList)) {
            throw new RuntimeException("删除失败");
        }
    }

    /**
     * 生成模板下载
     */
    @Override
    public void template() {
        SpireBigGrid spireBigGrid = new SpireBigGrid();
        ExcelUtils.createTemplate("大表（管网）", "SpireBigGrid大表（管网）",
                "SpireBigGrid大表（管网）", SpireBigGrid.class, Collections.singletonList(spireBigGrid));
    }

    /**
     * 数据导入
     *
     * @param file 文件
     */
    @Override
    public void importData(MultipartFile file) {
        List<SpireBigGrid> datas = ExcelUtils.getExcelToList("大表（管网）", file, SpireBigGrid.class);
        if (!CollectionUtils.isEmpty(datas)) {
            saveBatch(datas);
        }
    }

    /**
     * 分页查询
     *
     * @param page         分页
     * @param spireBigGrid 查询wrapper
     * @return 数据集合
     */
    @Override
    public Page<SpireBigGrid> pageList(Page page, SpireBigGrid spireBigGrid) {
        return page(page, new QueryWrapper<>(spireBigGrid)).addOrder(page.getOrders());
    }

    /**
     * 数据导出
     *
     * @param page         分页
     * @param spireBigGrid 查询模型
     * @param isAll        是否导出全部数据，true是，false否
     */
    @Override
    public void export(Page page, SpireBigGrid spireBigGrid, Boolean isAll) {
        Page<SpireBigGrid> pageData = new Page<>();
        if (isAll == null || !isAll) {
            pageData = page(page, new QueryWrapper<>(spireBigGrid)).addOrder(page.getOrders());
        } else {
            pageData.setRecords(list(new QueryWrapper<>(spireBigGrid)));
        }
        //导出数据
        ExcelUtils.getListToExcel(SpireBigGrid.class, pageData.getRecords(), "大表（管网）");
    }

    /**
     * 查询所有数据
     *
     * @param spireBigGrid 查询条件
     * @return 查询所有数据
     */
    @Override
    public List<SpireBigGrid> allList(SpireBigGrid spireBigGrid) {
        return list(new QueryWrapper<>(spireBigGrid));
    }
}

