package com.jjt.calc.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jjt.calc.domain.TwinCalcHourEnergy;
import com.jjt.calc.mapper.TwinCalcHourEnergyMapper;
import com.jjt.calc.service.ITwinCalcHourEnergyService;
import com.jjt.common.utils.DateUtils;
import com.jjt.common.utils.StringUtils;
import com.jjt.inventory.domain.TwinCalcHourBpOut;
import com.jjt.utils.IotService;
import com.jjt.utils.Tools;
import com.jjt.ws.domain.TwinWorkshopEnergy;
import com.jjt.ws.service.ITwinWorkshopCalcService;
import com.jjt.ws.service.ITwinWorkshopEnergyService;
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.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 能源1小时统计数据Service业务层处理
 *
 * @author wukai
 * @date 2025-01-18
 */
@Service
@Slf4j
public class TwinCalcHourEnergyServiceImpl implements ITwinCalcHourEnergyService {
    @Resource
    private TwinCalcHourEnergyMapper twinCalcHourEnergyMapper;
    @Resource
    private IotService iotService;
    @Resource
    private SqlSessionFactory factory;
    @Resource
    private ITwinWorkshopEnergyService energyService;
    @Resource
    private ITwinWorkshopCalcService calcService;

    /**
     * 查询能源1小时统计数据
     *
     * @param autoId 能源1小时统计数据主键
     * @return 能源1小时统计数据
     */
    @Override
    public TwinCalcHourEnergy selectTwinCalcHourEnergyByAutoId(Long autoId) {
        return twinCalcHourEnergyMapper.selectTwinCalcHourEnergyByAutoId(autoId);
    }

    /**
     * 查询能源1小时统计数据列表
     *
     * @param twinCalcHourEnergy 能源1小时统计数据
     * @return 能源1小时统计数据
     */
    @Override
    public List<TwinCalcHourEnergy> selectTwinCalcHourEnergyList(TwinCalcHourEnergy twinCalcHourEnergy) {
        return twinCalcHourEnergyMapper.selectTwinCalcHourEnergyList(twinCalcHourEnergy);
    }

    /**
     * 新增能源1小时统计数据
     *
     * @param twinCalcHourEnergy 能源1小时统计数据
     * @return 结果
     */
    @Override
    public int insertTwinCalcHourEnergy(TwinCalcHourEnergy twinCalcHourEnergy) {
        return twinCalcHourEnergyMapper.insertTwinCalcHourEnergy(twinCalcHourEnergy);
    }

    /**
     * 修改能源1小时统计数据
     *
     * @param twinCalcHourEnergy 能源1小时统计数据
     * @return 结果
     */
    @Override
    public int updateTwinCalcHourEnergy(TwinCalcHourEnergy twinCalcHourEnergy) {
        return twinCalcHourEnergyMapper.updateTwinCalcHourEnergy(twinCalcHourEnergy);
    }

    /**
     * 批量删除能源1小时统计数据
     *
     * @param autoIds 需要删除的能源1小时统计数据主键
     * @return 结果
     */
    @Override
    public int deleteTwinCalcHourEnergyByAutoIds(Long[] autoIds) {
        return twinCalcHourEnergyMapper.deleteTwinCalcHourEnergyByAutoIds(autoIds);
    }

    /**
     * 删除能源1小时统计数据信息
     *
     * @param autoId 能源1小时统计数据主键
     * @return 结果
     */
    @Override
    public int deleteTwinCalcHourEnergyByAutoId(Long autoId) {
        return twinCalcHourEnergyMapper.deleteTwinCalcHourEnergyByAutoId(autoId);
    }

    /**
     * 统计指定日期指定时段能耗数据
     *
     * @param start 开始时间戳
     * @param end   结束时间戳
     */
    @Override
    public void calcEnergy(LocalDateTime start, LocalDateTime end) {
        Date date = Date.from(start.toLocalDate().atStartOfDay(ZoneOffset.of("+8")).toInstant());
        int period = start.getHour();
        //先删除数据
        deleteTwinCalcHourEnergy(start.toLocalDate(), period);
        Long startTime = start.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        Long endTime = end.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        List<TwinWorkshopEnergy> energyList = energyService.selectTwinWorkshopEnergyList(new TwinWorkshopEnergy());
        // 转换为 Map<String, TwinWorkshopEnergy>，使用 能源ID 属性作为键
        Map<Long, TwinWorkshopEnergy> energyMap = energyList.stream().collect(Collectors.toMap(TwinWorkshopEnergy::getEnergyId, obj -> obj));
        List<String> fieldList = new ArrayList<>();
        energyList.forEach(energy -> {
            String field = energy.getEnergyPath() + " AS " + energy.getEnergyId();
            fieldList.add(field);
        });

        String sql = "select %s from root.tl.suxi where time>%s and time <=%s";
        sql = String.format(sql, String.join(",", fieldList), startTime, endTime);
        iotService.query(sql);
        JSONObject jsonObject = iotService.query(sql);
        JSONObject data = jsonObject.getJSONObject("data");
        JSONArray values = data.getJSONArray("values");
        JSONArray columnNames = data.getJSONArray("columnNames");

//        JSONArray timestamps = data.getJSONArray("timestamps");

        List<TwinCalcHourEnergy> calcHourEnergyList = new ArrayList<>();
        if (values.size() == 1) {
            JSONArray da = values.getJSONArray(0);
            for (int i = 0; i < da.size(); i++) {
                Long id = columnNames.getLong(i);
                String v = da.getStr(i);
                if (StringUtils.isNotEmpty(v)) {
                    BigDecimal value = new BigDecimal(v);
                    TwinCalcHourEnergy calc = new TwinCalcHourEnergy();
                    TwinWorkshopEnergy energy = energyMap.get(id);
                    value = value.multiply(energy.getCoefficient());
                    calc.setEnergyId(id);
                    calc.setDataDate(date);
                    calc.setHour(period);
                    calc.setDataValue(value);
                    calcHourEnergyList.add(calc);
                }
            }
        }
        try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
            if (calcHourEnergyList.size() > 0) {
                TwinCalcHourEnergyMapper mapper = sqlSession.getMapper(TwinCalcHourEnergyMapper.class);
                calcHourEnergyList.forEach(mapper::insertTwinCalcHourEnergy);
                sqlSession.commit();
            }
        }
    }

    private void deleteTwinCalcHourEnergy(LocalDate date, int hour) {
        QueryWrapper<TwinCalcHourEnergy> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("data_date", date);
        queryWrapper.eq("hour", hour);
        twinCalcHourEnergyMapper.delete(queryWrapper);
    }

    /**
     * 统计上一个时段的能源
     */
    @Override
    public void calcLastEnergy() {
        LocalDateTime curr = Tools.currWholeTime();
        //上一个小时
        LocalDateTime start = curr.minusHours(1);
        calcEnergy(start, curr);
    }

    /**
     * 按时间查询
     *
     * @param date 时间
     * @return 结果
     */
    @Override
    public List<TwinCalcHourEnergy> selectTwinEmpCalcListByDate(Date date) {
        LocalDate localDate = DateUtils.toLocalDate(date);
        //计算统计时间
        Pair<Date, Date> pair = Tools.calcDay(localDate);
        Date sTime = pair.getKey();
        Date eTime = pair.getValue();
        TwinCalcHourEnergy hour = new TwinCalcHourEnergy();
        Map<String, Object> params = new HashMap<>(16);
        params.put("sTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, sTime));
        params.put("eTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, eTime));
        hour.setParams(params);
        return selectTwinCalcHourEnergyList(hour);
    }

    /**
     * 从数据库最后一个时间段统计至上一个时段
     */
    @Override
    public void calc2Curr() {
        TwinCalcHourEnergy lastHour = lastRecord();
        LocalDate localDate = DateUtils.toLocalDate(lastHour.getDataDate());
        LocalDateTime start = LocalDateTime.of(localDate, LocalTime.MIN).plusHours(lastHour.getHour() + 1);
        LocalDateTime end = start.plusHours(1);

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

    /**
     * 获取最后一条记录
     *
     * @return 结果
     */
    private TwinCalcHourEnergy lastRecord() {
        return twinCalcHourEnergyMapper.lastRecord();
    }
}
