package com.jjt.calc.service.impl;

import com.jjt.biz.domain.TwinDevice;
import com.jjt.calc.domain.TwinCalcAlarms;
import com.jjt.calc.domain.TwinRecordAlarms;
import com.jjt.calc.mapper.TwinCalcAlarmsMapper;
import com.jjt.calc.service.ITwinCalcAlarmsService;
import com.jjt.calc.service.ITwinRecordAlarmsService;
import com.jjt.common.utils.StringUtils;
import com.jjt.common.utils.bean.BeanUtils;
import com.jjt.system.service.ISysConfigService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 告警数据统计Service业务层处理
 *
 * @author wukai
 * @date 2025-01-18
 */
@Service
public class TwinCalcAlarmsServiceImpl implements ITwinCalcAlarmsService {
    @Resource
    private TwinCalcAlarmsMapper twinCalcAlarmsMapper;
    @Resource
    private ISysConfigService configService;
    @Resource
    private ITwinRecordAlarmsService alarmsService;
    @Resource
    private SqlSessionFactory factory;

    /**
     * 查询告警数据统计
     *
     * @param id 告警数据统计主键
     * @return 告警数据统计
     */
    @Override
    public TwinCalcAlarms selectTwinCalcAlarmsById(Long id) {
        return twinCalcAlarmsMapper.selectTwinCalcAlarmsById(id);
    }

    /**
     * 查询告警数据统计列表
     *
     * @param twinCalcAlarms 告警数据统计
     * @return 告警数据统计
     */
    @Override
    public List<TwinCalcAlarms> selectTwinCalcAlarmsList(TwinCalcAlarms twinCalcAlarms) {
        return twinCalcAlarmsMapper.selectTwinCalcAlarmsList(twinCalcAlarms);
    }

    /**
     * 新增告警数据统计
     *
     * @param twinCalcAlarms 告警数据统计
     * @return 结果
     */
    @Override
    public int insertTwinCalcAlarms(TwinCalcAlarms twinCalcAlarms) {
        return twinCalcAlarmsMapper.insertTwinCalcAlarms(twinCalcAlarms);
    }

    /**
     * 修改告警数据统计
     *
     * @param twinCalcAlarms 告警数据统计
     * @return 结果
     */
    @Override
    public int updateTwinCalcAlarms(TwinCalcAlarms twinCalcAlarms) {
        return twinCalcAlarmsMapper.updateTwinCalcAlarms(twinCalcAlarms);
    }

    /**
     * 批量删除告警数据统计
     *
     * @param ids 需要删除的告警数据统计主键
     * @return 结果
     */
    @Override
    public int deleteTwinCalcAlarmsByIds(Long[] ids) {
        return twinCalcAlarmsMapper.deleteTwinCalcAlarmsByIds(ids);
    }

    /**
     * 删除告警数据统计信息
     *
     * @param id 告警数据统计主键
     * @return 结果
     */
    @Override
    public int deleteTwinCalcAlarmsById(Long id) {
        return twinCalcAlarmsMapper.deleteTwinCalcAlarmsById(id);
    }

    /**
     * 告警数据治理，从告警记录表到告警统计表中
     *
     * @param startTime  开始时间
     * @param deviceList 设备列表
     */
    @Override
    public void process(LocalDateTime startTime, List<TwinDevice> deviceList) {
        String config = configService.selectConfigByKey("data.legal.time");
        int legalTime = Integer.parseInt(config) * 1000;
        Date date = Date.from(startTime.toLocalDate().atStartOfDay(ZoneOffset.of("+8")).toInstant());
        //先处理上次未统计完整的数据
        TwinCalcAlarms calcSearch = new TwinCalcAlarms();
        calcSearch.setCalcStatus("1");
        List<TwinCalcAlarms> oldList = selectTwinCalcAlarmsList(calcSearch);
        Map<Long, List<TwinCalcAlarms>> oldMap = oldList.stream().collect(Collectors.groupingBy(TwinCalcAlarms::getDeviceId, LinkedHashMap::new, Collectors.toList()));
        //再处理本次数据，2次结合
        TwinRecordAlarms recordSearch = new TwinRecordAlarms();
        recordSearch.setDataDate(date);
        recordSearch.setHour(startTime.getHour());
        List<TwinRecordAlarms> newList = alarmsService.selectTwinRecordAlarmsList(recordSearch);
        Map<Long, List<TwinRecordAlarms>> newMap = newList.stream().collect(Collectors.groupingBy(TwinRecordAlarms::getDeviceId, LinkedHashMap::new, Collectors.toList()));

        List<TwinCalcAlarms> insertList = new ArrayList<>();
        List<TwinCalcAlarms> updateList = new ArrayList<>();
        List<TwinRecordAlarms> recordList = new ArrayList<>();
        for (TwinDevice device : deviceList) {
            List<TwinRecordAlarms> list = new ArrayList<>();
            if (oldMap.get(device.getDeviceId()) != null) {
                oldMap.get(device.getDeviceId()).forEach(old -> {
                    TwinRecordAlarms alarms = new TwinRecordAlarms();
                    BeanUtils.copyProperties(old, alarms);
                    //这里存ID，方便后面需要删除，判断是否之前的记录，则直接判断remark是否为空即可
                    alarms.setRemark(old.getId() + "");
                    list.add(alarms);
                });
            }
            //再处理本次数据，2次结合
            if (newMap.get(device.getDeviceId()) != null) {
                list.addAll(newMap.get(device.getDeviceId()));
            }

            //1.先循环一轮，处理记录合并
            List<TwinRecordAlarms> list1 = mergeList(list, legalTime);
            List<TwinRecordAlarms> list2 = new ArrayList<>();
            //2.再循环合并后的记录，删除无效数据
            for (TwinRecordAlarms alarm : list1) {
                if ((alarm.getEndTime().getTime() - alarm.getStartTime().getTime()) > legalTime) {
                    list2.add(alarm);

                }
            }
            //3.还要循环一轮，进行记录合并
            recordList.addAll(mergeList(list2, legalTime));
        }
        for (TwinRecordAlarms alarm : recordList) {
            TwinCalcAlarms v = new TwinCalcAlarms();
            BeanUtils.copyProperties(alarm, v);
            if (StringUtils.isNotEmpty(alarm.getRemark())) {
                v.setCalcStatus("0");
                v.setRemark("");
                updateList.add(v);
            } else {
                v.setId(null);
                insertList.add(v);
            }
        }

        try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
            TwinCalcAlarmsMapper mapper = sqlSession.getMapper(TwinCalcAlarmsMapper.class);
            insertList.forEach(mapper::insertTwinCalcAlarms);
            updateList.forEach(mapper::updateTwinCalcAlarms);
            sqlSession.commit();
        }

        //统计完成删除记录数据，避免记录超长
        alarmsService.deleteTwinRecordAlarms(date, startTime.getHour());
    }

    /**
     * 合并数据记录
     */
    private List<TwinRecordAlarms> mergeList(List<TwinRecordAlarms> list, int legalTime) {
        List<TwinRecordAlarms> result = new ArrayList<>();
        TwinRecordAlarms lastAlarm = null;

        for (TwinRecordAlarms alarm : list) {
            if (lastAlarm != null && alarm.getAlarmType().equals(lastAlarm.getAlarmType()) && (alarm.getStartTime().getTime() - lastAlarm.getEndTime().getTime()) < legalTime) {
                //判断同一个类型，并且下一条记录的开始时间-上一条记录的结束时间 小于数据合法时间
                lastAlarm.setEndTime(alarm.getEndTime());
                //需要设置统计未完成状态 为当前记录的
                lastAlarm.setCalcStatus(alarm.getCalcStatus());
            } else {
                result.add(alarm);
                lastAlarm = alarm;
            }
        }
        return result;
    }


    /**
     * 按开始和结束时间查询数据
     *
     * @param sTime 开始时间
     * @param eTime 结束时间
     * @return 查询列表
     */
    @Override
    public List<TwinCalcAlarms> selectTwinCalcAlarmsListByDate(Date sTime, Date eTime) {
        TwinCalcAlarms alarms = new TwinCalcAlarms();
        Map<String, Object> params = new HashMap<>(16);
        params.put("sTime", sTime);
        params.put("eTime", eTime);
        alarms.setParams(params);
        return selectTwinCalcAlarmsList(alarms);
    }
}
