package com.zehong.system.netty.event;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zehong.common.constant.RoboticArmConstans;
import com.zehong.common.utils.StringUtils;
import com.zehong.common.utils.http.HttpUtils;
import com.zehong.system.domain.*;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.service.*;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author lenovo
 * @date 2025/12/1
 * @description 处理标定结果event
 */

@Component
public class CalibrationResultEventHandler {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CalibrationResultEventHandler.class);

    @Resource
    private IPalletDeviceUploadHistoryService palletDeviceUploadHistoryService;

    // 格式: /@A1_1/0/0.0/ 或 /@B2_1/0/0.0/ 或 /@C3_1/0/0.0/
    // 支持任意大写字母后跟数字的设备标识符，如 A1, B2, C3, D4 等
    private static final Pattern DEVICE_PATTERN = Pattern.compile("/@([A-Z]\\d+)_(\\d+)/([^/]+)/([^/]+)");

    // 如果您需要支持多位字母的设备标识符（如 AB1, ABC2 等），可以使用以下正则表达式：
    // private static final Pattern DEVICE_PATTERN = Pattern.compile("/@([A-Z]+\\d+)_(\\d+)/([^/]+)/([^/]+)");

    @Resource
    private IPalletDeviceBindingService palletDeviceBindingService;

    @Resource
    private ISysConfigService sysConfigService;

    @Resource
    private IProcessCalibrationResultHistoryService processCalibrationResultHistoryService;

    @Resource
    private TTrayInfoMapper tTrayInfoMapper;

    @Resource
    private IUploadMesResultHistoryService uploadMesResultHistoryService;

    /**
     * check是否启动 ，没启动就启动下 开始老化
     *
     * @param event event
     */
    @Async("threadPoolTaskExecutor")
    @EventListener(ProcessCalibrationResultsEvent.class)
    public void handleProcessCalibrationResultsEventCommand(ProcessCalibrationResultsEvent event) {

        String message = event.getMessage();

        log.info("处理标定结果: {}", message);
        // 先存历史记录
        ProcessCalibrationResultHistory processCalibrationResultHistory = new ProcessCalibrationResultHistory();
        processCalibrationResultHistory.setMessage(message);
        processCalibrationResultHistoryService.insertProcessCalibrationResultHistory(processCalibrationResultHistory);
        // 例如：更新校准状态、保存校准数据、通知前端等
        // 1 根据信息拿到点位信息 假如说1L是传过来的
        initAdAndStatus(message);

        // 2 解析数据上传MES 返回如果失败则记录失败，等下次有时间再上传
        // 20260116 调整 接收标定结果后 不存历史，解绑的时候才去处理。
        //initMesDataAndUpload(palletDeviceBindings);
    }

    /**
     * 根据托盘码查询托盘绑定的设备列
     */
    private List<PalletDeviceBinding> initAdAndStatus(String message) {

        String trayCode = parseTrayCode(message);
        if (StringUtils.isBlank(trayCode)) {
            log.info("无法从消息中解析出托盘号: {}", message);
            return new ArrayList<>();
        }

        List<PalletDeviceBinding> palletDeviceBindings = palletDeviceBindingService.listByTrayCode(trayCode);

        if (palletDeviceBindings.isEmpty()) {
            log.info("未找到托盘号 {} 绑定的设备", trayCode);
            return new ArrayList<>();
        }

        // 根据message 处理 标定浓度值   标定状态
        List<DeviceData> deviceDataList = parseDeviceData(message);
        if (deviceDataList.isEmpty()) {
            log.info("消息中未包含有效的设备数据: {}", message);
            return palletDeviceBindings;
        }

        // 阶段四：根据顺序号更新设备
        updateDevicesBySequence(palletDeviceBindings, deviceDataList);

        // 阶段五：处理设备的 最终标定状态 根据所有结果 获取最终标定状态
        updateFinalStatus(palletDeviceBindings);

        // 批量更新
        palletDeviceBindingService.batchUpdateAdAndStatus(palletDeviceBindings);

        // 更新托盘为标检完成状态3
        TTrayInfo tTrayInfo = new TTrayInfo();
        tTrayInfo.setfStatus("3");
        tTrayInfo.setfTrayCode(trayCode);
        tTrayInfoMapper.updateStatusByTrayCode(tTrayInfo);

        return palletDeviceBindings;
    }

    private void updateFinalStatus(List<PalletDeviceBinding> palletDeviceBindings) {

        // deviceStatus = 1,3,4; 设备状态
        // writeTimeStatus 写时间状态
        // runTimeStatus 时间运行状态
        // realTimeStatus 实时AD状态
        // calibrationConcentrationStatus 标定浓度状态
        // writeSelfCheckStatus 写自检状态
        // relayStatus 继电器状态
        // pulseStatus 脉冲状态
        // moduleStatus 模块状态
        // simCardStatus 串口状态
        for (PalletDeviceBinding palletDeviceBinding : palletDeviceBindings) {
            if(StringUtils.isBlank(palletDeviceBinding.getMotherboardCode())) continue;
            if(("1".equals(palletDeviceBinding.getDeviceStatus())
            || "3".equals(palletDeviceBinding.getDeviceStatus())
            || "4".equals(palletDeviceBinding.getDeviceStatus()))
            && "1".equals(palletDeviceBinding.getWriteTimeStatus())
            && "1".equals(palletDeviceBinding.getRunTimeStatus())
            && "1".equals(palletDeviceBinding.getRealTimeStatus())
            && "4".equals(palletDeviceBinding.getCalibrationConcentrationStatus())
            && palletDeviceBinding.getWriteSelfCheckStatus() == 1
            && palletDeviceBinding.getModuleStatus() == 1
            && palletDeviceBinding.getSimCardStatus() == 1
            && palletDeviceBinding.getNetworkStatus() == 1) {
                palletDeviceBinding.setStandardInspectResult("1");
            }

            if(!"2".equals(palletDeviceBinding.getReadingMode())) {
                if(palletDeviceBinding.getRelayStatus() == 1) {
                    palletDeviceBinding.setStandardInspectResult("1");
                } else {
                    palletDeviceBinding.setStandardInspectResult("0");
                }
            }

            if(!"1".equals(palletDeviceBinding.getReadingMode())) {
                if(palletDeviceBinding.getPulseStatus() == 1) {
                    palletDeviceBinding.setStandardInspectResult("1");
                } else {
                    palletDeviceBinding.setStandardInspectResult("0");
                }
            }
        }
    }

    /**
     * 阶段一：解析托盘号
     * 消息格式: @00012346/@A1_1/0/0.0/@B2_2/0/0.0/@C3_3/0/0.0/
     */
    private String parseTrayCode(String message) {
        if (StringUtils.isBlank(message) || !message.startsWith("@")) {
            return null;
        }

        try {
            // 提取 @ 后面的内容，直到第一个 /
            int endIndex = message.indexOf("/");
            if (endIndex == -1) {
                // 如果没有斜杠，整个消息就是托盘号（去掉@）
                return message.substring(1);
            }

            // 提取托盘号（去掉开头的@）
            return message.substring(1, endIndex);
        } catch (Exception e) {
            log.info("解析托盘号失败: {}", message, e);
            return null;
        }
    }


    /**
     * 阶段二和阶段三：解析设备数据
     */
    private List<DeviceData> parseDeviceData(String message) {
        List<DeviceData> deviceDataList = new ArrayList<>();

        if (StringUtils.isBlank(message)) {
            return deviceDataList;
        }

        try {
            // 使用正则表达式匹配所有设备数据
            Matcher deviceMatcher = DEVICE_PATTERN.matcher(message);

            while (deviceMatcher.find()) {
                try {
                    // 修改后：group(1) 是设备标识符（如A1, B2, C3等），group(2) 是顺序号
                    String deviceType = deviceMatcher.group(1);   // 设备类型，如A1, B2, C3等
                    String sequenceStr = deviceMatcher.group(2);  // 顺序号
                    String statusStr = deviceMatcher.group(3);    // 标定状态
                    String valueStr = deviceMatcher.group(4);     // 标定值

                    // 解析数据
                    Integer sequenceNumber = parseInt(sequenceStr);
                    BigDecimal calibrationValue = parseBigDecimal(valueStr);

                    if (sequenceNumber != null) {
                        DeviceData deviceData = new DeviceData();
                        deviceData.setDeviceType(deviceType);      // 存储设备类型（如果需要）
                        deviceData.setSequenceNumber(sequenceNumber);
                        deviceData.setCalibrationStatus(statusStr);
                        deviceData.setCalibrationValue(calibrationValue);

                        deviceDataList.add(deviceData);

                        log.info("解析到设备数据: 设备类型={}, 顺序号={}, 状态={}, 值={}",
                                deviceType, sequenceNumber, statusStr, calibrationValue);
                    }
                } catch (Exception e) {
                    log.info("解析设备数据失败，跳过此设备: {}", deviceMatcher.group(), e);
                }
            }
        } catch (Exception e) {
            log.info("解析设备数据列表失败: {}", message, e);
        }

        return deviceDataList;
    }


    /**
     * 工具方法：解析整数
     */
    private Integer parseInt(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return Integer.parseInt(str.trim());
        } catch (NumberFormatException e) {
            log.info("解析整数失败: {}", str, e);
            return null;
        }
    }

    /**
     * 工具方法：解析BigDecimal
     */
    private BigDecimal parseBigDecimal(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        try {
            return new BigDecimal(str.trim());
        } catch (NumberFormatException e) {
            log.info("解析BigDecimal失败: {}", str, e);
            return null;
        }
    }

    /**
     * 阶段四：根据顺序号更新设备
     */
    private void updateDevicesBySequence(List<PalletDeviceBinding> bindings, List<DeviceData> deviceDataList) {
        if (bindings == null || deviceDataList == null || deviceDataList.isEmpty()) {
            return;
        }

        // 将设备数据转为以顺序号为key的Map
        Map<Integer, DeviceData> deviceDataMap = new HashMap<>();
        for (DeviceData data : deviceDataList) {
            if (data.getSequenceNumber() != null) {
                deviceDataMap.put(data.getSequenceNumber(), data);
            }
        }

        // 更新设备绑定列表
        for (PalletDeviceBinding binding : bindings) {
            Integer sequenceNumber = binding.getNumber(); // 假设顺序号字段为number

            if (sequenceNumber != null && deviceDataMap.containsKey(sequenceNumber)) {
                DeviceData deviceData = deviceDataMap.get(sequenceNumber);

                // 更新标定浓度值
                if (deviceData.getCalibrationValue() != null) {
                    binding.setCalibrationConcentration(deviceData.getCalibrationValue());
                }

                // 更新标定状态
                if (deviceData.getCalibrationStatus() != null) {
                    binding.setCalibrationConcentrationStatus(deviceData.getCalibrationStatus());
                }

                // 可以添加其他字段的更新，比如更新时间等
                binding.setUpdateTime(new Date());

                log.info("更新设备绑定: 顺序号={}, 托盘号={}, 状态={}, 值={}",
                        sequenceNumber, binding.getfTrayCode(),
                        deviceData.getCalibrationStatus(),
                        deviceData.getCalibrationValue());
            } else {
                log.debug("未找到顺序号 {} 对应的设备数据", sequenceNumber);
            }
        }
    }

    /**
     * 设备数据内部类（如果需要存储设备类型，可以扩展此类）
     */
    private static class DeviceData {
        private String deviceType;          // 设备类型，如A1, B2, C3等
        private Integer sequenceNumber;     // 顺序号
        private String calibrationStatus;   // 标定状态
        private BigDecimal calibrationValue;// 标定值

        // getter 和 setter 方法
        public String getDeviceType() {
            return deviceType;
        }

        public void setDeviceType(String deviceType) {
            this.deviceType = deviceType;
        }

        public Integer getSequenceNumber() {
            return sequenceNumber;
        }

        public void setSequenceNumber(Integer sequenceNumber) {
            this.sequenceNumber = sequenceNumber;
        }

        public String getCalibrationStatus() {
            return calibrationStatus;
        }

        public void setCalibrationStatus(String calibrationStatus) {
            this.calibrationStatus = calibrationStatus;
        }

        public BigDecimal getCalibrationValue() {
            return calibrationValue;
        }

        public void setCalibrationValue(BigDecimal calibrationValue) {
            this.calibrationValue = calibrationValue;
        }
    }
}
