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是传过来的
        List<PalletDeviceBinding> palletDeviceBindings = initAdAndStatus(message);

        // 2 解析数据上传MES 返回如果失败则记录失败，等下次有时间再上传
        initMesDataAndUpload(palletDeviceBindings);
    }

    /**
     * 初始化MES数据并上传
     */
    private void initMesDataAndUpload(List<PalletDeviceBinding> palletDeviceBindings) {
        if(palletDeviceBindings.isEmpty()) {
            log.info("initMesDataAndUpload:没有数据需要处理");
            return;
        }

        List<MesDeviceDomain> mesDeviceDomains = new ArrayList<>();

        for (PalletDeviceBinding palletDeviceBinding : palletDeviceBindings) {
            MesDeviceDomain mesDeviceDomain = new MesDeviceDomain();
            // 主板码
            mesDeviceDomain.setMotherboardCode(palletDeviceBinding.getDeviceCode());
            // 标定浓度值
            mesDeviceDomain.setCalibrationConcentration(palletDeviceBinding.getCalibrationConcentration());
            // 标定状态
            mesDeviceDomain.setCalibrationConcentrationStatus(palletDeviceBinding.getCalibrationConcentrationStatus());
            // 浓度
            mesDeviceDomain.setConcentration(palletDeviceBinding.getConcentration());
            // 实时AD
            mesDeviceDomain.setRealTimeAd(palletDeviceBinding.getRealTimeAd());
            // 实时状态
            mesDeviceDomain.setRealTimeStatus(palletDeviceBinding.getRealTimeStatus());
            mesDeviceDomains.add(mesDeviceDomain);
        }

        String mesUploadAddress = sysConfigService.directSelectConfigByKey(RoboticArmConstans.UPLOAD_MES_ADDRESS);
        if(StringUtils.isNotBlank(mesUploadAddress)) {
            try{
                String result = HttpUtils.sendPost(mesUploadAddress, JSON.toJSONString(mesDeviceDomains));
                UploadMesResultHistory uploadMesResultHistory = new UploadMesResultHistory();
                uploadMesResultHistory.setMessage(result);
                uploadMesResultHistoryService.insertUploadMesResultHistory(uploadMesResultHistory);
                if(StringUtils.isNotBlank(result)) {
                    JSONObject jsonObject = JSON.parseObject(result);
                    if(jsonObject.getInteger("code") != 200) {
                        String data = jsonObject.getString("data");
                        if(StringUtils.isNotBlank(data)) {
                            processPalletDeviceUploadHistory(palletDeviceBindings,data);
                        } else {
                            directProcessPaalletDeviceUploadHistory(palletDeviceBindings);
                        }
                    }
                } else {
                    directProcessPaalletDeviceUploadHistory(palletDeviceBindings);
                }
            }catch (Exception e){
                directProcessPaalletDeviceUploadHistory(palletDeviceBindings);
            }
        } else {
            directProcessPaalletDeviceUploadHistory(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);

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

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

        return palletDeviceBindings;
    }


    /**
     * 阶段一：解析托盘号
     * 消息格式: @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 void processPalletDeviceUploadHistory(List<PalletDeviceBinding> palletDeviceBindings,String data){
        JSONObject jsonObject = JSON.parseObject(data);

        if (!jsonObject.containsKey("failedCodes")) {
            return;
        } else {
            log.info("上传失败；没有返回正确数据");
        }

        JSONArray failedCodes = jsonObject.getJSONArray("failedCodes");
        if (failedCodes == null || failedCodes.isEmpty()) {
            return;
        }

        // 使用Set提高查找效率
        Set<String> failedCodeSet = failedCodes.stream()
                .map(Object::toString)
                .collect(Collectors.toSet());

        List<PalletDeviceUploadHistory> palletDeviceUploadHistories = palletDeviceBindings.stream()
                .filter(binding -> failedCodeSet.contains(binding.getDeviceCode()))
                .map(this::convertToUploadHistory)
                .collect(Collectors.toList());

        if (!palletDeviceUploadHistories.isEmpty()) {
            palletDeviceUploadHistoryService.batchInsert(palletDeviceUploadHistories);
        }
    }

    /**
     * 直接处理托盘设备上传历史数据
     */
    private void directProcessPaalletDeviceUploadHistory(List<PalletDeviceBinding> palletDeviceBindings) {
        List<PalletDeviceUploadHistory> collect = palletDeviceBindings.stream().map(this::convertToUploadHistory).collect(Collectors.toList());
        palletDeviceUploadHistoryService.batchInsert(collect);
    }
    /**
     * 转换对象
     */
    private PalletDeviceUploadHistory convertToUploadHistory(PalletDeviceBinding binding) {
        PalletDeviceUploadHistory history = new PalletDeviceUploadHistory();
        // 基础信息字段
        history.setTrayId(binding.getTrayId());
        history.setDeviceCode(binding.getDeviceCode());
        history.setRow(binding.getRow());
        history.setCol(binding.getCol());
        history.setIndex(binding.getIndex());
        history.setNumber(binding.getNumber());
        history.setBindingTime(binding.getBindingTime());
        history.setUnbindingTime(binding.getUnbindingTime());

        // 状态字段
        history.setStatus(binding.getStatus());

        // 时间记录字段
        history.setRecordYear(binding.getRecordYear());
        history.setRecordMonth(binding.getRecordMonth());
        history.setRecordDate(binding.getRecordDate());
        history.setRecordHour(binding.getRecordHour());
        history.setRecordMinute(binding.getRecordMinute());

        // 写入状态字段
        history.setWriteTimeStatus(binding.getWriteTimeStatus());
        history.setRunTimeStatus(binding.getRunTimeStatus());

        // 调零相关字段
        history.setAdjustmentZeroAd(binding.getAdjustmentZeroAd());
        history.setZeroStatus(binding.getZeroStatus());

        // 标定相关字段 - 注意字段名称不同
        history.setCalibrationAd(binding.getCalibrationAd());
        history.setCalibrationStatus(binding.getCalibrationAdStatus()); // 注意：这里字段名不同

        // 浓度字段
        history.setConcentration(binding.getConcentration());

        // 实时AD相关字段
        history.setRealTimeAd(binding.getRealTimeAd());
        history.setRealTimeAdStatus(binding.getRealTimeStatus()); // 注意：这里字段名不同

        // 托盘编号字段 - 注意字段名称不同
        history.setTrayCode(binding.getfTrayCode()); // 注意：这里字段名不同

        // 创建时间和更新时间（如果需要）
        history.setCreateTime(binding.getCreateTime());
        history.setUpdateTime(binding.getUpdateTime());

        // 标定浓度字段 - 注意字段名称不同
        history.setCalibrationConcentration(binding.getCalibrationConcentration());
        history.setCalibrationConcentrationStatus(binding.getCalibrationConcentrationStatus());

        return history;
    }

    /**
     * 设备数据内部类（如果需要存储设备类型，可以扩展此类）
     */
    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;
        }
    }
}