package com.jjt.utils;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.jjt.biz.domain.TwinDevice;
import com.jjt.biz.domain.TwinDeviceYhj;
import com.jjt.calc.domain.TwinCalcHourYhj;
import com.jjt.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

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

/**
 * 多线程执行任务
 *
 * @author wukai
 * @date 2024/5/4 20:35
 */
@Service
@Slf4j
public class AsyncYhjService {
    @Resource
    private IotService iotService;
    /**
     * 字段列表，方便看下标
     */
    private final String[] fields = {"Capacity_data_2", "Capacity_data_37", "Capacity_data_38", "Capacity_data_39", "Capacity_data_42",
            "Capacity_data_43", "Capacity_data_44", "Capacity_data_48", "Formula_data_3", "Formula_data_13",
            "Capacity_data_36", "Capacity_data_41", "Alarm_unit_1", "Alarm_unit_2", "Alarm_unit_3",
            "Alarm_unit_4", "Alarm_unit_5", "Alarm_unit_6", "Alarm_unit_7", "Alarm_unit_8",
            "Alarm_unit_9", "Alarm_unit_10", "Alarm_unit_11", "Alarm_unit_12", "Alarm_unit_13",
            "Alarm_unit_14", "Alarm_unit_15", "Alarm_unit_16", "Alarm_unit_17", "Alarm_unit_18",
            "Alarm_unit_19", "Alarm_unit_20", "Alarm_unit_21", "Alarm_unit_22", "Alarm_unit_23",
            "Alarm_unit_24", "Alarm_unit_25", "Alarm_unit_26", "Alarm_unit_27", "Capacity_data_33",
            "Capacity_data_15", "Capacity_data_16", "Capacity_data_17", "Capacity_data_18", "Capacity_data_19",
            "Capacity_data_34", "Formula_data_24", "Formula_data_15", "Capacity_data_1"
    };


    /**
     * 字段列表，方便查找位置
     */
    private final List<String> fieldList = Arrays.stream(fields).collect(Collectors.toList());

    @Async("threadPoolTaskExecutor")
    public Future<Map<String, Object>> currData(TwinDevice twinDevice) {
        String table = twinDevice.getDevicePath();
        String sql = "select last * from " + table;
        JSONObject jsonObject = iotService.query(sql);
        JSONObject data = jsonObject.getJSONObject("data");
        JSONArray values = data.getJSONArray("values");
        JSONArray timestamps = data.getJSONArray("timestamps");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("device", twinDevice);
        if (timestamps.size() > 0 && (System.currentTimeMillis() - new Date(timestamps.getLong(0)).getTime()) > 5 * 60 * 100) {
            //如果最后一条记录 超过5分钟，则视为无效记录
            dataMap.put("total", 0);
        } else {
            dataMap.put("total", values.size());
            dataMap.putAll(Tools.json2Map(values, table));
        }
        return new AsyncResult<>(dataMap);
    }

    /**
     * 根据设备获取指定时段数据
     *
     * @param yhj   印花机设备
     * @param start 开始时间
     * @param end   结束时间
     * @return
     */
    @Async("threadPoolTaskExecutor")
    public Future<TwinCalcHourYhj> process(TwinDeviceYhj yhj, LocalDateTime start, LocalDateTime end) {
        Long startTime = start.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        Long endTime = end.toInstant(ZoneOffset.of("+8")).toEpochMilli();
        TwinCalcHourYhj calcYhj = new TwinCalcHourYhj();
        String[] fields = {"Formula_data_set_1", "Formula_data_act_5"};

        String sql = "select %s from " + yhj.getDevicePath() + " where time>%s and time <=%s";

        sql = String.format(sql, String.join(",", fields), startTime, endTime);
            JSONObject jsonObject = iotService.query(sql);
        JSONObject data = jsonObject.getJSONObject("data");
        JSONArray columnNames = data.getJSONArray("columnNames");
        JSONArray values = data.getJSONArray("values");
        JSONArray timestamps = data.getJSONArray("timestamps");
        //记录上一次记录的值
        Integer[] last = new Integer[columnNames.size()];
        //记录最后一次的值，防中间有数，后面没数
        Integer[] over = new Integer[columnNames.size()];
        //当前记录值
        Integer[] curr = new Integer[columnNames.size()];
        //记录第一次记录的值，如果清0，则记录清零时刻的值
        Integer[] first = new Integer[columnNames.size()];
        //记录统计值
        Integer[] total = new Integer[columnNames.size()];
        for (int i = 0; i < values.size(); i++) {
            JSONArray da = values.getJSONArray(i);
            da.toList(Integer.class).toArray(curr);
            if (i == 0) {
                cloneArray(curr, last);
                cloneArray(curr, first);
                cloneArray(curr, over);
                continue;
            }
            for (int j = 0; j < columnNames.size(); j++) {
                String name = columnNames.getStr(j);
                if (name.contains("Formula_data_set_1")) {
                    //如果是版距，则需要记录变化
                    if (curr[j] != null && last[j] != null && curr[j].intValue() != last[j].intValue()) {
                        //这里要用j+1才行
                        calcLength(j + 1, last, first, total);
                        combo(calcYhj, start, yhj, last[j], total[j + 1]);
                        total[j + 1] = 0;
                    }
                }
                if (name.contains("Formula_data_act_5")) {
                    //如果是米长，则需要记录是否清0
                    //如果当前值为小于上一个，且上一个值不为0，则计算
                    //因为会出现数据波动，停机再启动之后的第一个点不为0，为0.00几几几的
                    if (curr[j] != null && last[j] != null && curr[j] < last[j] && last[j] != 0) {
                        calcLength(j, last, first, total);
                        cloneArray(curr, first);
                    }
                }
            }
            //将本次的值，设为上一条记录了
            cloneArray(curr, last);
            cloneArray(curr, over);
            cloneArrayFirst(curr, first);
        }
        for (int j = 0; j < columnNames.size(); j++) {
            String name = columnNames.getStr(j);
            if (name.contains("Formula_data_set_1")) {
                calcLength(j + 1, over, first, total);
                combo(calcYhj, start, yhj, over[j], total[j + 1]);
            }
        }

        return new AsyncResult<>(calcYhj);
    }


    /**
     * 初始值，如果当前值不为空，并且原来值为空
     */
    void cloneArrayFirst(Integer[] arr, Integer[] target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] != null && target[i] == null) {
                target[i] = arr[i];
            }
        }
    }

    /**
     * 复制数组，如果当前值不为空
     */
    void cloneArray(Integer[] arr, Integer[] target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] != null) {
                target[i] = arr[i];
            }
        }
    }

    /**
     * 组合入库数据
     */
    void combo(TwinCalcHourYhj calcYhj, LocalDateTime start, TwinDeviceYhj yhj, Integer distance, Integer length) {
        if (distance != null && length != null) {
            calcYhj.setDeviceId(yhj.getDeviceId());
            calcYhj.setDataDate(DateUtils.toDate(start.toLocalDate()));
            calcYhj.setHour(start.getHour());
            calcYhj.setDistance(distance);
            calcYhj.setLength(length);
        }
    }

    /**
     * 计算米长
     */
    void calcLength(int j, Integer[] last, Integer[] first, Integer[] total) {
        if (last[j] != null && first[j] != null) {
            if (total[j] == null) {
                total[j] = 0;
            }
            total[j] += (last[j] - first[j]);
        }
    }
}
