package com.malk.tonglibo.utils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.aliwork.YDSearch;
import com.malk.service.aliwork.YDClient;
import com.malk.tonglibo.Mapper.MachineDataMapper;
import com.malk.tonglibo.Mapper.MachineDetailMapper;
import com.malk.tonglibo.Service.IMachineDataService;
import com.malk.tonglibo.entity.MachineDetail;
import com.malk.tonglibo.entity.RawDeviceData;
import com.malk.tonglibo.entity.MachineData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能：
 * 作者：hanxue
 * 日期：2025/10/18 1:00
 */
@Slf4j
@Component
public class DeviceDataPersistTask {
    @Autowired
    private MachineDataMapper machineDataMapper;
    @Autowired
    private IMachineDataService machineDataService;
    @Autowired
    private MachineDetailMapper machineDetailMapper;

    @Autowired
    private DataBuffer dataBuffer;

    @Autowired
    private ChangeDetector changeDetector;
    @Autowired
    private YDClient ydClient;


    @Scheduled(fixedDelay = 1000) // 每秒执行一次
    public void persist() {
        List<RawDeviceData> dataList = dataBuffer.drain(500);
        if (dataList.isEmpty()) return;

        // "machineNo + 分钟"
        Map<String, MachineData> latestPerMinute = new HashMap<>();

        for (RawDeviceData item : dataList) {
            MachineData data = convertToMachineData(item);
            if (data == null) {
                log.warn("设备数据转换失败，跳过: {}", item);
                continue;
            }

            //生成 key：machineNo + 时间分钟
            String minuteKey = data.getMachineNo() + "_" +
                    data.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
            // 保留最新的数据
            MachineData existing = latestPerMinute.get(minuteKey);
            if (existing == null || data.getTime().isAfter(existing.getTime())) {
                latestPerMinute.put(minuteKey, data);
            }
        }

        //对每分钟最新数据进行 MD5 变化检测
        List<MachineData> toInsert = new ArrayList<>();
        int unchangedCount = 0;

        for (MachineData data : latestPerMinute.values()) {
            if (changeDetector.isChanged(data)) {
                String fingerprint = MD5Util.md5(changeDetector.concatFields(data));
                data.setDataFingerprint(fingerprint);
                toInsert.add(data);
                changeDetector.recordAsCurrent(data.getMachineNo(), fingerprint); // 更新为当前指纹
            } else {
                unchangedCount++;
            }
        }

        // 批量入库
        if (!toInsert.isEmpty()) {
            machineDataService.saveBatch(toInsert, 100);
            log.info("入库 {} 条（每设备每分钟最新且变化数据），跳过 {} 条未变数据，原始上报 {} 条",
                    toInsert.size(), unchangedCount, dataList.size());
        } else if (unchangedCount > 0) {
            log.debug("跳过 {} 条未变化数据（已按分钟合并）", unchangedCount);
        }
    }



    private MachineData convertToMachineData(RawDeviceData item) {
        try {
            String deviceId = item.getDeviceId();
            String key = item.getKey();
            List<String> data = item.getData();

            MachineData machineData = new MachineData();
            machineData.setParamId(deviceId); // 唯一设备标识
            machineData.setMachineNo(key);
            machineData.setTime(item.getTime());
            machineData.setTimestr(item.getTimeStr());

            // 填充字段（根据索引取值）
            machineData.setJqyxsh(safeGet(data, 0));
            machineData.setZcn(safeGet(data, 1));
            machineData.setDn(safeGet(data, 2));
            machineData.setZqsj(safeGet(data, 3));
            machineData.setSgdyl(safeGet(data, 4));
            machineData.setXgdyl(safeGet(data, 5));
            machineData.setYskqyl1(safeGet(data, 6));
            machineData.setYskqyl2(safeGet(data, 7));
            machineData.setZymwd1(safeGet(data, 8));
            machineData.setZymwd2(safeGet(data, 9));
            machineData.setZymwd3(safeGet(data, 10));
            machineData.setZymwd4(safeGet(data, 11));
            machineData.setSmwd1(safeGet(data, 12));
            machineData.setSmwd2(safeGet(data, 13));
            machineData.setSmwd3(safeGet(data, 14));
            machineData.setSmwd4(safeGet(data, 15));
            machineData.setXmwd1(safeGet(data, 16));
            machineData.setXmwd2(safeGet(data, 17));
            machineData.setXmwd3(safeGet(data, 18));
            machineData.setXmwd4(safeGet(data, 19));
            machineData.setXjsj(safeGet(data, 20));
            machineData.setTssj(safeGet(data, 21));
            machineData.setZysj(safeGet(data, 22));
            List<MachineDetail> machineList = machineDetailMapper.selectList(new QueryWrapper<MachineDetail>().eq("machine_no", key));
            if (machineList != null && !machineList.isEmpty()){
                MachineDetail yidaParam = machineList.get(0);
                String machineName = yidaParam.getMachineName();
                String machineCode = yidaParam.getMachineCode();
                String machineFlag = yidaParam.getMachineFlag();
                if (machineName != null) {
                    machineData.setMachineName(machineName);
                    machineData.setMachineCode(machineCode);
                    machineData.setMachineFlag(machineFlag);
                } else {
                    log.warn("未在宜搭中找到设备编号 {} 对应的名称，使用默认值", key);
                }
            }

            return machineData;
        } catch (Exception e) {
            log.error("转换数据失败: {}", item, e);
            return null;
        }
    }

    // 安全获取索引值
    private String safeGet(List<String> list, int index) {
        if (index >= 0 && index < list.size()) {
            String value = list.get(index);
            // 切割掉 . 后面的数据
            if (value != null) {
                String[] parts = value.split("\\.");
                return parts[0]; // 返回点号前面的部分
            }
        }
        return "";
    }
}
