package com.jjt.calc.service.impl;

import com.jjt.biz.domain.TwinDeviceYhj;
import com.jjt.biz.service.ITwinDeviceYhjService;
import com.jjt.calc.domain.TwinCalcHourYhj;
import com.jjt.calc.mapper.TwinCalcHourYhjMapper;
import com.jjt.calc.service.ITwinCalcDayYhjService;
import com.jjt.calc.service.ITwinCalcHourYhjService;
import com.jjt.common.constant.CacheConstants;
import com.jjt.common.core.redis.RedisCache;
import com.jjt.common.utils.DateUtils;
import com.jjt.inventory.service.ITwinCalcHourBpOutService;
import com.jjt.utils.AsyncYhjService;
import com.jjt.utils.IotService;
import com.jjt.utils.Tools;
import javafx.util.Pair;
import lombok.extern.slf4j.Slf4j;
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.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * 印花机1小时统计数据Service业务层处理
 *
 * @author wukai
 * @date 2025-03-06
 */
@Service
@Slf4j
public class TwinCalcHourYhjServiceImpl implements ITwinCalcHourYhjService {
    @Resource
    private TwinCalcHourYhjMapper twinCalcHourYhjMapper;
    @Resource
    private IotService iotService;
    @Resource
    private SqlSessionFactory factory;
    @Resource
    private ITwinDeviceYhjService yhjService;
    @Resource
    private ITwinCalcDayYhjService dayYhjService;
    @Resource
    private AsyncYhjService asyncYhjService;
    @Resource
    private RedisCache redisCache;
    @Resource
    private ITwinCalcHourBpOutService bpOutService;

    /**
     * 查询印花机1小时统计数据
     *
     * @param id 印花机1小时统计数据主键
     * @return 印花机1小时统计数据
     */
    @Override
    public TwinCalcHourYhj selectTwinCalcHourYhjById(Long id) {
        return twinCalcHourYhjMapper.selectTwinCalcHourYhjById(id);
    }

    /**
     * 查询印花机1小时统计数据列表
     *
     * @param twinCalcHourYhj 印花机1小时统计数据
     * @return 印花机1小时统计数据
     */
    @Override
    public List<TwinCalcHourYhj> selectTwinCalcHourYhjList(TwinCalcHourYhj twinCalcHourYhj) {
        return twinCalcHourYhjMapper.selectTwinCalcHourYhjList(twinCalcHourYhj);
    }

    /**
     * 新增印花机1小时统计数据
     *
     * @param twinCalcHourYhj 印花机1小时统计数据
     * @return 结果
     */
    @Override
    public int insertTwinCalcHourYhj(TwinCalcHourYhj twinCalcHourYhj) {
        return twinCalcHourYhjMapper.insertTwinCalcHourYhj(twinCalcHourYhj);
    }

    /**
     * 修改印花机1小时统计数据
     *
     * @param twinCalcHourYhj 印花机1小时统计数据
     * @return 结果
     */
    @Override
    public int updateTwinCalcHourYhj(TwinCalcHourYhj twinCalcHourYhj) {
        return twinCalcHourYhjMapper.updateTwinCalcHourYhj(twinCalcHourYhj);
    }

    /**
     * 批量删除印花机1小时统计数据
     *
     * @param ids 需要删除的印花机1小时统计数据主键
     * @return 结果
     */
    @Override
    public int deleteTwinCalcHourYhjByIds(Long[] ids) {
        return twinCalcHourYhjMapper.deleteTwinCalcHourYhjByIds(ids);
    }

    /**
     * 删除印花机1小时统计数据信息
     *
     * @param id 印花机1小时统计数据主键
     * @return 结果
     */
    @Override
    public int deleteTwinCalcHourYhjById(Long id) {
        return twinCalcHourYhjMapper.deleteTwinCalcHourYhjById(id);
    }

    /**
     * 统计指定日期指定时段数据
     *
     * @param date   指定日期 yyyy-mm-dd
     * @param period 时段
     */
    @Override
    public void calc(String date, int period) {
        LocalDate localDate = LocalDate.parse(date);
        LocalDateTime ldt = LocalDateTime.of(localDate, LocalTime.MIN);
        LocalDateTime start = ldt.plusHours(period);
        LocalDateTime end = start.plusHours(1);
        calc(start, end);
    }

    /**
     * 统计上一时段数据
     */
    @Override
    public void last() {
        LocalDateTime ldt = Tools.currWholeTime();
        //上一个小时
        ldt = ldt.minusHours(1);
        LocalDateTime start = ldt;
        LocalDateTime end = ldt.plusHours(1);
        calc(start, end);
    }

    /**
     * 统计当日数据
     */
    @Override
    public void today() {
        //计算统计时间
        Pair<Date, Date> pair = Tools.calcToday();
        Date sTime = pair.getKey();
        Date eTime = pair.getValue();
        TwinCalcHourYhj search = new TwinCalcHourYhj();
        Map<String, Object> params = new HashMap<>(16);
        params.put("sTime", sTime);
        params.put("eTime", eTime);
        search.setParams(params);
        List<TwinCalcHourYhj> hourList = selectTwinCalcHourYhjList(search);
        TwinCalcHourYhj lastRecord = lastRecord();
        LocalDate localDate = DateUtils.toLocalDate(lastRecord.getDataDate());
        LocalDateTime start = LocalDateTime.of(localDate, LocalTime.MIN).plusHours(lastRecord.getHour() + 1);
        List<TwinCalcHourYhj> calcList = process(start, LocalDateTime.now());
        hourList.addAll(calcList);
        hourList.forEach(TwinCalcHourYhj::setTeam);
        redisCache.setCacheObject(CacheConstants.YHJ_TODAY, hourList);
    }

    /**
     * 按指定时间统计
     *
     * @param start 开始时间
     * @param end   结束时间
     */
    @Override
    public void calc(LocalDateTime start, LocalDateTime end) {
        //先删除当前时段的统计数据
        deleteTwinCalcHourYhj(DateUtils.toDate(start.toLocalDate()), start.getHour());

        List<TwinCalcHourYhj> calcList = process(start, end);

        try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
            if (calcList.size() > 0) {
                TwinCalcHourYhjMapper mapper = sqlSession.getMapper(TwinCalcHourYhjMapper.class);
                calcList.forEach(mapper::insertTwinCalcHourYhj);
                sqlSession.commit();
            }
        }
    }

    private List<TwinCalcHourYhj> process(LocalDateTime start, LocalDateTime end) {
        List<TwinDeviceYhj> list = yhjService.selectTwinDeviceYhjList(new TwinDeviceYhj());
        List<Future<TwinCalcHourYhj>> futureList = new ArrayList<>();
        List<TwinCalcHourYhj> calcList = new ArrayList<>();
        for (TwinDeviceYhj yhj : list) {
            futureList.add(asyncYhjService.process(yhj, start, end));
        }

        try {
            for (Future<TwinCalcHourYhj> future : futureList) {
                // 任务完成后获取结果
                try {
                    TwinCalcHourYhj calcYhj = future.get(10L, TimeUnit.SECONDS);
                    if (calcYhj.getDeviceId() != null) {
                        calcList.add(calcYhj);
                    }
                } catch (TimeoutException e) {
                    log.error("有超时的哟{}", e.getMessage());
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
        return calcList;
    }

    /**
     * 查询数据库最后一条记录
     *
     * @return 结果
     */
    @Override
    public TwinCalcHourYhj lastRecord() {
        return twinCalcHourYhjMapper.lastRecord();
    }

    /**
     * 补录数据至当前时间
     */
    @Override
    public void calc2Curr() {
        TwinCalcHourYhj last = lastRecord();
        LocalDate localDate = DateUtils.toLocalDate(last.getDataDate());
        LocalDateTime start = LocalDateTime.of(localDate, LocalTime.MIN).plusHours(last.getHour() + 1);
        LocalDateTime end = start.plusHours(1);

        LocalDateTime stop = Tools.currWholeTime();
        while (!end.isAfter(stop)) {
            calc(start, end);
            bpOutService.calc(start, end);
            log.info("补录数据===========start:{},end:{},stop:{}", start, end, stop);
            if (end.getHour() == 7) {
                //跨天,统计前一天的总数据
                log.info("----------------{},{}", start, end);
                dayYhjService.day(start.toLocalDate().minusDays(1));
            }
            start = end;
            end = end.plusHours(1);
        }
    }

    /**
     * 按时间和小时删除数据
     *
     * @param date 时间
     * @param hour 小时
     */
    public void deleteTwinCalcHourYhj(Date date, int hour) {
        twinCalcHourYhjMapper.deleteTwinCalcHourYhj(date, hour);
    }
}
