package com.ruoyi.jarvis.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.jarvis.domain.JDOrder;
import com.ruoyi.jarvis.domain.WeComShareLinkLogisticsJob;
import com.ruoyi.jarvis.mapper.WeComShareLinkLogisticsJobMapper;
import com.ruoyi.jarvis.service.IErpGoofishOrderService;
import com.ruoyi.jarvis.service.ILogisticsService;
import com.ruoyi.jarvis.service.IJDOrderService;
import com.ruoyi.jarvis.service.goofish.GoofishOrderPipeline;
import com.ruoyi.system.service.ISysConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Value;

import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.util.DigestUtils;

/**
 * 物流信息服务实现类
 */
@Service
public class LogisticsServiceImpl implements ILogisticsService {
    private static final Logger logger = LoggerFactory.getLogger(LogisticsServiceImpl.class);
    
    private static final String REDIS_WAYBILL_KEY_PREFIX = "logistics:waybill:order:";
    private static final String REDIS_LOCK_KEY_PREFIX = "logistics:lock:order:";
    private static final String REDIS_HEALTH_CHECK_ALERT_KEY = "logistics:health:alert:";
    private static final String REDIS_ADHOC_WAYBILL_PREFIX = "logistics:adhoc:waybill:";
    /** 企微分享链+备注入队，FIFO：RPUSH 入队、LPOP 出队 */
    private static final String REDIS_ADHOC_PENDING_QUEUE = "logistics:adhoc:pending:queue";
    /** 对账补入队限频：避免每轮定时任务对同一 jobKey 重复 RPUSH */
    private static final String REDIS_ADHOC_RECONCILE_ENQUEUE_PREFIX = "logistics:adhoc:reconcile:enqueue:";
    private static final int ADHOC_RECONCILE_ROW_LIMIT = 200;
    private static final long ADHOC_RECONCILE_ENQUEUE_LOCK_SECONDS = 8 * 60;
    /** 单次队列项最多重新入队次数（约对应多天 × 每 15 分钟一轮） */
    private static final int ADHOC_MAX_REQUEUE_ATTEMPTS = 500;
    private static final String PUSH_URL = "https://wxts.van333.cn/wx/send/pdd";
    private static final String PUSH_TOKEN = "super_token_b62190c26";
    private static final String CONFIG_KEY_PREFIX = "logistics.push.touser.";
    private static final long LOCK_EXPIRE_SECONDS = 300; // 锁过期时间5分钟，防止死锁
    private static final long HEALTH_CHECK_ALERT_INTERVAL_MINUTES = 30; // 健康检查失败提醒间隔30分钟，避免频繁推送
    
    @Value("${jarvis.server.logistics.base-url:http://127.0.0.1:5001}")
    private String logisticsBaseUrl;

    /** 逗号分隔的多个解析服务 base，非空时优先于此列表轮询；例如 http://10.0.0.1:5001,http://10.0.0.2:5001 */
    @Value("${jarvis.server.logistics.base-urls:}")
    private String logisticsBaseUrlsRaw;
    
    @Value("${jarvis.server.logistics.fetch-path:/fetch_logistics}")
    private String logisticsFetchPath;
    
    @Value("${jarvis.server.logistics.health-path:/health}")
    private String logisticsHealthPath;

    @Value("${jarvis.server.logistics.adhoc-pending-batch-size:50}")
    private int adhocPendingBatchSize;

    @Resource
    private WeComShareLinkLogisticsJobMapper weComShareLinkLogisticsJobMapper;
    
    /** 已规范化（无尾部斜杠）的物流解析服务 base 列表，至少一项 */
    private List<String> logisticsServiceBases = Collections.emptyList();
    private String logisticsServiceBasesSummary = "";
    private final AtomicInteger logisticsBaseRoundRobin = new AtomicInteger(0);
    
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    
    @Resource
    private ISysConfigService sysConfigService;
    
    @Resource
    private IJDOrderService jdOrderService;

    @Resource
    private IErpGoofishOrderService erpGoofishOrderService;

    @PostConstruct
    public void init() {
        List<String> list = new ArrayList<>();
        if (StringUtils.hasText(logisticsBaseUrlsRaw)) {
            for (String part : logisticsBaseUrlsRaw.split(",")) {
                String n = normalizeLogisticsBaseUrl(part);
                if (StringUtils.hasText(n)) {
                    list.add(n);
                }
            }
        }
        if (list.isEmpty()) {
            list.add(normalizeLogisticsBaseUrl(logisticsBaseUrl));
        }
        logisticsServiceBases = Collections.unmodifiableList(list);
        logisticsServiceBasesSummary = String.join(", ", logisticsServiceBases);
        logger.info("物流服务实例 {} 个（轮询）: {}", logisticsServiceBases.size(), logisticsServiceBasesSummary);
    }

    private static String normalizeLogisticsBaseUrl(String base) {
        if (!StringUtils.hasText(base)) {
            return "";
        }
        String t = base.trim();
        while (t.endsWith("/")) {
            t = t.substring(0, t.length() - 1);
        }
        return t;
    }

    private String pickLogisticsBaseUrl() {
        int n = logisticsServiceBases.size();
        if (n == 0) {
            return normalizeLogisticsBaseUrl(logisticsBaseUrl);
        }
        if (n == 1) {
            return logisticsServiceBases.get(0);
        }
        int idx = Math.floorMod(logisticsBaseRoundRobin.getAndIncrement(), n);
        return logisticsServiceBases.get(idx);
    }

    @Override
    public String buildFetchLogisticsRequestUrl(String logisticsLink) {
        String base = pickLogisticsBaseUrl();
        try {
            return base + logisticsFetchPath + "?tracking_url=" + URLEncoder.encode(logisticsLink, "UTF-8");
        } catch (java.io.UnsupportedEncodingException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * 与原先单 URL 健康检查语义一致：JSON 字段命中则通过；非 JSON 时仅当正文含 ok/healthy/success 子串则通过。
     */
    private boolean isHealthResponseBodyHealthy(String healthResult) {
        if (healthResult == null || healthResult.trim().isEmpty()) {
            return false;
        }
        try {
            JSONObject response = JSON.parseObject(healthResult);
            if (response != null) {
                String status = response.getString("status");
                Boolean healthy = response.getBoolean("healthy");
                Integer code = response.getInteger("code");
                if ("ok".equalsIgnoreCase(status) || "healthy".equalsIgnoreCase(status)
                    || Boolean.TRUE.equals(healthy) || (code != null && code == 200)) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            String lowerResult = healthResult.toLowerCase();
            return lowerResult.contains("ok") || lowerResult.contains("healthy") || lowerResult.contains("success");
        }
    }
    
    @Override
    public boolean isOrderProcessed(Long orderId) {
        if (orderId == null) {
            return false;
        }
        String redisKey = REDIS_WAYBILL_KEY_PREFIX + orderId;
        return stringRedisTemplate.hasKey(redisKey);
    }
    
    @Override
    public ILogisticsService.HealthCheckResult checkHealth() {
        List<String> errors = new ArrayList<>();
        for (String base : logisticsServiceBases) {
            String url = base + logisticsHealthPath;
            try {
                logger.debug("开始检查物流服务健康状态 - URL: {}", url);
                String healthResult = HttpUtils.sendGet(url);
                if (isHealthResponseBodyHealthy(healthResult)) {
                    logger.debug("物流服务健康检查通过 - {}", url);
                    return new ILogisticsService.HealthCheckResult(true, "正常", "服务运行正常: " + url,
                        logisticsServiceBasesSummary);
                }
                logger.warn("物流服务健康检查失败 - URL: {} 响应: {}", url, healthResult);
                errors.add(url + " -> " + (healthResult == null || healthResult.isEmpty() ? "空响应" : "状态异常"));
            } catch (Exception e) {
                logger.error("物流服务健康检查异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
                errors.add(url + " -> " + e.getMessage());
            }
        }
        String msg = errors.isEmpty() ? "未配置物流解析实例" : String.join("; ", errors);
        return new ILogisticsService.HealthCheckResult(false, "异常", msg, logisticsServiceBasesSummary);
    }
    
    /**
     * 检查物流服务健康状态（内部方法，用于业务逻辑）
     * @return 是否健康
     */
    @SuppressWarnings("unused")
    private boolean checkLogisticsServiceHealth() {
        ILogisticsService.HealthCheckResult result = checkHealth();
        if (result.isHealthy()) {
            // 清除健康检查失败标记
            stringRedisTemplate.delete(REDIS_HEALTH_CHECK_ALERT_KEY);
        } else {
            handleHealthCheckFailure(result.getMessage());
        }
        return result.isHealthy();
    }
    
    /**
     * 处理健康检查失败，推送提醒消息
     * @param reason 失败原因
     */
    @SuppressWarnings("null")
    private void handleHealthCheckFailure(String reason) {
        try {
            // 检查是否在提醒间隔内已经推送过
            String alertKey = REDIS_HEALTH_CHECK_ALERT_KEY;
            String lastAlertTime = stringRedisTemplate.opsForValue().get(alertKey);
            
            if (lastAlertTime != null) {
                // 如果30分钟内已经推送过，不再重复推送
                logger.debug("健康检查失败提醒已在30分钟内推送过，跳过本次推送");
                return;
            }
            
            // 构建推送消息
            StringBuilder pushContent = new StringBuilder();
            pushContent.append("【物流服务异常提醒】\n");
            pushContent.append("服务实例：").append(logisticsServiceBasesSummary).append("\n");
            pushContent.append("失败原因：").append(reason).append("\n");
            pushContent.append("时间：").append(new Date()).append("\n");
            pushContent.append("请及时检查服务状态！");
            
            JSONObject pushParam = new JSONObject();
            pushParam.put("title", "物流服务健康检查失败");
            pushParam.put("text", pushContent.toString());
            
            // 尝试获取系统管理员接收人配置，如果没有则使用默认接收人
            String adminTouser = sysConfigService.selectConfigByKey("logistics.push.touser.ADMIN");
            if (StringUtils.hasText(adminTouser)) {
                pushParam.put("touser", adminTouser.trim());
                logger.info("使用管理员接收人配置推送健康检查失败提醒");
            } else {
                logger.info("未配置管理员接收人，将使用远程接口默认接收人推送健康检查失败提醒");
            }
            
            String jsonBody = pushParam.toJSONString();
            String pushResult = sendPostWithHeaders(PUSH_URL, jsonBody, PUSH_TOKEN);
            
            if (pushResult != null && !pushResult.trim().isEmpty()) {
                logger.info("健康检查失败提醒已推送 - 响应: {}", pushResult);
                // 记录推送时间，30分钟内不再重复推送
                long currentTime = System.currentTimeMillis();
                stringRedisTemplate.opsForValue().set(alertKey, Long.toString(currentTime), 
                    HEALTH_CHECK_ALERT_INTERVAL_MINUTES, TimeUnit.MINUTES);
            } else {
                logger.warn("健康检查失败提醒推送失败 - 响应为空");
            }
            
        } catch (Exception e) {
            logger.error("推送健康检查失败提醒异常", e);
        }
    }
    
    /**
     * 京东单已写入 Redis 运单后，联动闲鱼单同步并发货（失败不影响物流主流程）。
     * 若存在关联闲鱼单，会先写入事件来源 JD_LOGISTICS_PUSH，便于与 REDIS_WAYBILL / AUTO_SHIP 对照。
     */
    private void safeNotifyGoofishShip(Long jdOrderId, String waybillNo, String traceSummary) {
        try {
            mirrorFxianyuGoofishSecondaryWaybillRedis(jdOrderId, waybillNo);
            erpGoofishOrderService.traceJdLogisticsPushForGoofish(jdOrderId, waybillNo, traceSummary);
            erpGoofishOrderService.notifyJdWaybillReady(jdOrderId);
        } catch (Exception e) {
            logger.warn("闲鱼发货联动异常 jdOrderId={} err={}", jdOrderId, e.toString());
        }
    }

    /**
     * F-闲鱼等：将运单镜像到 logistics:waybill:goofish:${第三方单号}，即使 erp_goofish_order.jd_order_id 尚未关联也能被同步。
     */
    private void mirrorFxianyuGoofishSecondaryWaybillRedis(Long jdOrderDbId, String waybillNo) {
        if (jdOrderDbId == null || !StringUtils.hasText(waybillNo)) {
            return;
        }
        JDOrder jd = jdOrderService.selectJDOrderById(jdOrderDbId);
        if (jd == null) {
            return;
        }
        if (!isFxianyuJdDistributionMark(jd.getDistributionMark())) {
            return;
        }
        String tp = jd.getThirdPartyOrderNo();
        if (!StringUtils.hasText(tp)) {
            return;
        }
        stringRedisTemplate.opsForValue().set(
            GoofishOrderPipeline.REDIS_WAYBILL_GOOFISH_ORDER_PREFIX + tp.trim(),
            waybillNo.trim(),
            30, TimeUnit.DAYS);
    }

    private static boolean isFxianyuJdDistributionMark(String distributionMark) {
        if (!StringUtils.hasText(distributionMark)) {
            return false;
        }
        String m = distributionMark.trim();
        return m.startsWith("F") || m.contains("\u95f2\u9c7c");
    }

    @Override
    public boolean fetchLogisticsAndPush(JDOrder order) {
        if (order == null || order.getId() == null) {
            logger.warn("订单信息为空，无法获取物流信息");
            return false;
        }
        
        Long orderId = order.getId();
        
        // 双重检查：先检查是否已处理过
        if (isOrderProcessed(orderId)) {
            logger.info("订单已处理过，跳过 - 订单ID: {}", orderId);
            return true; // 返回true表示已处理，避免重复处理
        }
        
        // 获取分布式锁，防止并发处理同一订单
        String lockKey = REDIS_LOCK_KEY_PREFIX + orderId;
        Boolean lockAcquired = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "locked", LOCK_EXPIRE_SECONDS, TimeUnit.SECONDS);
        
        if (Boolean.FALSE.equals(lockAcquired)) {
            logger.warn("订单正在被其他线程处理，跳过 - 订单ID: {}", orderId);
            return false; // 其他线程正在处理，返回false让调用方稍后重试
        }
        
        try {
            // 获取锁后再次检查是否已处理（双重检查锁定模式）
            if (isOrderProcessed(orderId)) {
                logger.info("订单在获取锁后检查发现已处理，跳过 - 订单ID: {}", orderId);
                return true;
            }
            
            // 检查物流链接
            String logisticsLink = order.getLogisticsLink();
            if (logisticsLink == null || logisticsLink.trim().isEmpty()) {
                logger.info("订单暂无物流链接，跳过处理 - 订单ID: {}", orderId);
                return false;
            }
            
            // 先进行健康检查
            ILogisticsService.HealthCheckResult healthResult = checkHealth();
            if (!healthResult.isHealthy()) {
                logger.error("物流服务健康检查失败，跳过处理订单 - 订单ID: {}, 原因: {}", orderId, healthResult.getMessage());
                return false;
            }
            
            String externalUrl = buildFetchLogisticsRequestUrl(logisticsLink);
            logger.info("调用外部接口获取物流信息 - 订单ID: {}, URL: {}", orderId, externalUrl);
            
            // 在服务端执行HTTP请求
            String result = HttpUtils.sendGet(externalUrl);
            
            if (result == null || result.trim().isEmpty()) {
                logger.warn("外部接口返回空结果 - 订单ID: {}", orderId);
                return false;
            }
            
            logger.info("外部接口调用成功 - 订单ID: {}, 返回数据长度: {}", orderId, result.length());
            
            // 解析返回结果
            JSONObject parsedData = null;
            try {
                Object parsed = JSON.parse(result);
                if (parsed instanceof JSONObject) {
                    parsedData = (JSONObject) parsed;
                } else {
                    logger.warn("返回数据不是JSON对象格式 - 订单ID: {}", orderId);
                    return false;
                }
            } catch (Exception e) {
                logger.warn("解析返回数据失败 - 订单ID: {}, 错误: {}", orderId, e.getMessage());
                return false;
            }
            
            // 检查waybill_no
            JSONObject dataObj = parsedData.getJSONObject("data");
            if (dataObj == null) {
                logger.info("返回数据中没有data字段 - 订单ID: {}", orderId);
                return false;
            }
            
            String waybillNo = dataObj.getString("waybill_no");
            if (waybillNo == null || waybillNo.trim().isEmpty()) {
                logger.info("waybill_no为空，无需处理 - 订单ID: {}", orderId);
                return false;
            }
            
            logger.info("检测到waybill_no: {} - 订单ID: {}", waybillNo, orderId);
            
            // 标记物流链接是否更新
            boolean logisticsLinkUpdated = false;
            String oldLogisticsLink = null;
            String newLogisticsLink = null;
            
            // 检查并更新物流链接（如果返回的数据中包含新的物流链接）
            // 尝试多种可能的字段名
            if (dataObj.containsKey("tracking_url")) {
                newLogisticsLink = dataObj.getString("tracking_url");
            } else if (dataObj.containsKey("logistics_link")) {
                newLogisticsLink = dataObj.getString("logistics_link");
            } else if (dataObj.containsKey("logisticsLink")) {
                newLogisticsLink = dataObj.getString("logisticsLink");
            } else if (dataObj.containsKey("trackingUrl")) {
                newLogisticsLink = dataObj.getString("trackingUrl");
            }
            
            // 如果获取到新的物流链接，与数据库中的进行比对
            if (newLogisticsLink != null && !newLogisticsLink.trim().isEmpty()) {
                String currentLogisticsLink = order.getLogisticsLink();
                String trimmedNewLink = newLogisticsLink.trim();
                String trimmedCurrentLink = (currentLogisticsLink != null) ? currentLogisticsLink.trim() : "";
                oldLogisticsLink = trimmedCurrentLink;
                
                // 比对物流链接，如果不一致则更新数据库
                if (!trimmedNewLink.equals(trimmedCurrentLink)) {
                    logger.info("========== 检测到物流链接发生变化 - 订单ID: {}, 订单号: {}, 旧链接: {}, 新链接: {}, 开始更新数据库 ==========", 
                        orderId, order.getOrderId(), trimmedCurrentLink, trimmedNewLink);
                    
                    try {
                        // 重新查询订单，确保获取最新数据
                        JDOrder updateOrder = jdOrderService.selectJDOrderById(orderId);
                        if (updateOrder != null) {
                            updateOrder.setLogisticsLink(trimmedNewLink);
                            int updateResult = jdOrderService.updateJDOrder(updateOrder);
                            if (updateResult > 0) {
                                logisticsLinkUpdated = true;
                                logger.info("========== 物流链接更新成功 - 订单ID: {}, 订单号: {}, 旧链接: {}, 新链接: {} ==========", 
                                    orderId, order.getOrderId(), trimmedCurrentLink, trimmedNewLink);
                                // 更新内存中的order对象，以便后续使用最新数据
                                order.setLogisticsLink(trimmedNewLink);
                            } else {
                                logger.warn("物流链接更新失败（影响行数为0） - 订单ID: {}, 订单号: {}, 新链接: {}", 
                                    orderId, order.getOrderId(), trimmedNewLink);
                            }
                        } else {
                            logger.warn("未找到订单，无法更新物流链接 - 订单ID: {}, 订单号: {}", orderId, order.getOrderId());
                        }
                    } catch (Exception e) {
                        logger.error("更新物流链接时发生异常 - 订单ID: {}, 订单号: {}, 新链接: {}, 错误: {}", 
                            orderId, order.getOrderId(), trimmedNewLink, e.getMessage(), e);
                        // 不中断主流程，继续处理
                    }
                } else {
                    logger.debug("物流链接未变化，无需更新 - 订单ID: {}, 订单号: {}, 链接: {}", 
                        orderId, order.getOrderId(), trimmedCurrentLink);
                }
            } else {
                logger.debug("返回数据中未包含物流链接字段 - 订单ID: {}, 订单号: {}", orderId, order.getOrderId());
            }
            
            // 兼容处理：检查Redis中是否已有该订单的运单号记录
            // 如果存在且运单号一致，说明之前已经推送过了（可能是之前没有配置接收人但推送成功的情况）
            String redisKey = REDIS_WAYBILL_KEY_PREFIX + orderId;
            String existingWaybillNo = stringRedisTemplate.opsForValue().get(redisKey);
            
            if (existingWaybillNo != null && existingWaybillNo.trim().equals(waybillNo.trim())) {
                // 运单号一致，说明之前已经推送过了，直接标记为已处理，跳过推送
                logger.info("订单运单号已存在且一致，说明之前已推送过，跳过重复推送 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
                // 更新过期时间，确保记录不会过期
                stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS);
                safeNotifyGoofishShip(orderId, waybillNo,
                    "Redis 运单与本次一致，跳过重复企微推送；已刷新 TTL；随后触发闲鱼同步");
                return true;
            }
            
            // 兼容处理：如果Redis中没有记录，但订单创建时间在30天之前，且获取到了运单号
            // 说明可能是之前推送过但没标记的情况（比如之前没有配置接收人但推送成功，响应解析失败）
            // 这种情况下，直接标记为已处理，跳过推送，避免重复推送旧订单
            if (existingWaybillNo == null && order.getCreateTime() != null) {
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.DAY_OF_MONTH, -30); // 30天前
                Date thresholdDate = calendar.getTime();
                
                if (order.getCreateTime().before(thresholdDate)) {
                    // 订单创建时间在30天之前，且Redis中没有记录，但获取到了运单号
                    // 视为之前已推送过但未标记，直接标记为已处理，跳过推送
                    logger.info("订单创建时间较早（{}），且Redis中无记录但已获取到运单号，视为之前已推送过，直接标记为已处理，跳过推送 - 订单ID: {}, waybill_no: {}", 
                        order.getCreateTime(), orderId, waybillNo);
                    stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS);
                    safeNotifyGoofishShip(orderId, waybillNo,
                        "老单兜底：直写 Redis，跳过企微；随后触发闲鱼同步");
                    return true;
                }
            }
            
            // 如果Redis中有记录但运单号不一致，记录警告
            if (existingWaybillNo != null && !existingWaybillNo.trim().equals(waybillNo.trim())) {
                logger.warn("订单运单号发生变化 - 订单ID: {}, 旧运单号: {}, 新运单号: {}, 将重新推送", 
                    orderId, existingWaybillNo, waybillNo);
            }
            
            // 调用企业应用推送，只有推送成功才记录状态
            boolean pushSuccess = sendEnterprisePushNotification(order, waybillNo, logisticsLinkUpdated, oldLogisticsLink, newLogisticsLink);
            if (!pushSuccess) {
                logger.warn("企业微信推送未确认成功，稍后将重试 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
                return false;
            }
            
            // 保存运单号到Redis（避免重复处理）- 使用原子操作确保只写入一次
            Boolean setSuccess = stringRedisTemplate.opsForValue().setIfAbsent(redisKey, waybillNo, 30, TimeUnit.DAYS);
            
            if (Boolean.FALSE.equals(setSuccess)) {
                // 如果Redis中已存在，说明可能被其他线程处理了，记录警告但不算失败
                logger.warn("订单运单号已存在（可能被并发处理），但推送已成功 - 订单ID: {}, waybill_no: {}", orderId, waybillNo);
                // 更新过期时间，确保记录不会过期
                stringRedisTemplate.opsForValue().set(redisKey, waybillNo, 30, TimeUnit.DAYS);
            }
            String mark = order.getDistributionMark();
            boolean skipGoofishJdWexin = erpGoofishOrderService.hasLinkedGoofishOrder(orderId)
                || (mark != null && mark.contains("\u95f2\u9c7c"));
            String traceTail = (logisticsLinkUpdated ? "物流链接已更新；" : "物流链接未变；") + "Redis 已写入；随后触发闲鱼同步";
            String traceSummary = (skipGoofishJdWexin
                ? "闲鱼单本环节未发京东物流企微，真发货见 SHIP 日志；"
                : "企微货主推送成功；") + traceTail;
            safeNotifyGoofishShip(orderId, waybillNo, traceSummary);

            // 记录最终处理结果
            if (logisticsLinkUpdated) {
                logger.info("========== 物流信息获取并推送成功（已更新物流链接） - 订单ID: {}, 订单号: {}, waybill_no: {}, 新链接: {} ==========", 
                    orderId, order.getOrderId(), waybillNo, newLogisticsLink);
            } else {
                logger.info("物流信息获取并推送成功 - 订单ID: {}, 订单号: {}, waybill_no: {}", 
                    orderId, order.getOrderId(), waybillNo);
            }
            return true;
            
        } catch (Exception e) {
            logger.error("获取物流信息失败 - 订单ID: {}, 错误: {}", orderId, e.getMessage(), e);
            return false;
        } finally {
            // 释放分布式锁
            try {
                stringRedisTemplate.delete(lockKey);
                logger.debug("释放订单处理锁 - 订单ID: {}", orderId);
            } catch (Exception e) {
                logger.warn("释放订单处理锁失败 - 订单ID: {}, 错误: {}", orderId, e.getMessage());
            }
        }
    }

    @Override
    public void enqueueShareLinkForScan(String trackingUrl, String remark, String touser, String fromWecomUserId) {
        if (!StringUtils.hasText(trackingUrl)) {
            logger.warn("adhoc 入队跳过：分享链接为空");
            return;
        }
        String jobKey = UUID.randomUUID().toString().replace("-", "");
        try {
            WeComShareLinkLogisticsJob row = new WeComShareLinkLogisticsJob();
            row.setJobKey(jobKey);
            row.setFromUserName(StringUtils.hasText(fromWecomUserId) ? fromWecomUserId.trim() : null);
            row.setTrackingUrl(trackingUrl.trim());
            row.setUserRemark(remark != null ? remark : "");
            row.setTouserPush(touser != null ? touser : "");
            row.setStatus("PENDING");
            row.setScanAttempts(0);
            weComShareLinkLogisticsJobMapper.insertWeComShareLinkLogisticsJob(row);
        } catch (Exception e) {
            logger.warn("adhoc 分享链任务落库失败仍将入队 jobKey={} err={}", jobKey, e.toString());
        }
        rightPushAdhocQueueJson(jobKey, 0, trackingUrl.trim(), remark, touser, fromWecomUserId);
    }

    @Override
    public void pushShareLinkJobToRedis(WeComShareLinkLogisticsJob job) {
        if (job == null || !StringUtils.hasText(job.getJobKey()) || !StringUtils.hasText(job.getTrackingUrl())) {
            logger.warn("adhoc 入队跳过：jobKey 或 trackingUrl 为空");
            return;
        }
        WeComShareLinkLogisticsJob row = weComShareLinkLogisticsJobMapper.selectByJobKey(job.getJobKey().trim());
        if (row != null && "CANCELLED".equalsIgnoreCase(row.getStatus())) {
            logger.info("adhoc 入队跳过：任务已取消 jobKey={}", job.getJobKey());
            return;
        }
        int attempts = job.getScanAttempts() != null ? job.getScanAttempts() : 0;
        rightPushAdhocQueueJson(job.getJobKey().trim(), attempts, job.getTrackingUrl().trim(),
            job.getUserRemark(), job.getTouserPush(), job.getFromUserName());
    }

    @Override
    public int reconcileShareLinkJobsIntoPendingQueue() {
        int pushed = 0;
        try {
            List<WeComShareLinkLogisticsJob> rows = weComShareLinkLogisticsJobMapper.selectJobsNeedingQueueReconcile(
                ADHOC_RECONCILE_ROW_LIMIT);
            if (rows == null || rows.isEmpty()) {
                return 0;
            }
            for (WeComShareLinkLogisticsJob job : rows) {
                if (job == null || !StringUtils.hasText(job.getJobKey())) {
                    continue;
                }
                String lockKey = REDIS_ADHOC_RECONCILE_ENQUEUE_PREFIX + job.getJobKey().trim();
                Boolean gotLock = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "1",
                    ADHOC_RECONCILE_ENQUEUE_LOCK_SECONDS, TimeUnit.SECONDS);
                if (!Boolean.TRUE.equals(gotLock)) {
                    continue;
                }
                try {
                    WeComShareLinkLogisticsJob toEnqueue = job;
                    if ("ABANDONED".equalsIgnoreCase(job.getStatus())) {
                        String prev = StringUtils.hasText(job.getLastNote()) ? job.getLastNote() : "";
                        if (prev.length() > 400) {
                            prev = prev.substring(0, 400) + "…";
                        }
                        String note = "requeue_after_abandon|" + prev;
                        weComShareLinkLogisticsJobMapper.updateByJobKey(job.getJobKey().trim(), "WAITING", note, 0, null);
                        toEnqueue = weComShareLinkLogisticsJobMapper.selectByJobKey(job.getJobKey().trim());
                        if (toEnqueue == null) {
                            stringRedisTemplate.delete(lockKey);
                            continue;
                        }
                    }
                    pushShareLinkJobToRedis(toEnqueue);
                    pushed++;
                } catch (Exception e) {
                    try {
                        stringRedisTemplate.delete(lockKey);
                    } catch (Exception ignored) {
                    }
                    logger.warn("adhoc 对账入队失败 jobKey={} err={}", job.getJobKey(), e.toString());
                }
            }
        } catch (Exception e) {
            logger.error("adhoc 分享链对账入队异常", e);
        }
        return pushed;
    }

    /** 与 drain 解析字段一致：jobKey、attempts、trackingUrl、remark、touser、fromWecom */
    private void rightPushAdhocQueueJson(String jobKey, int attempts, String trackingUrl, String remark,
        String touser, String fromWecom) {
        JSONObject o = new JSONObject();
        o.put("jobKey", jobKey);
        o.put("attempts", attempts);
        o.put("trackingUrl", trackingUrl);
        o.put("remark", remark != null ? remark : "");
        o.put("touser", touser != null ? touser : "");
        o.put("fromWecom", fromWecom != null ? fromWecom : "");
        stringRedisTemplate.opsForList().rightPush(REDIS_ADHOC_PENDING_QUEUE, o.toJSONString());
        logger.info("adhoc 分享链接已入队 jobKey={} trackingUrl={} queueKey={}", jobKey, trackingUrl, REDIS_ADHOC_PENDING_QUEUE);
    }

    @Override
    public int drainPendingShareLinkQueue() {
        int processed = 0;
        int n = Math.max(1, adhocPendingBatchSize);
        for (int i = 0; i < n; i++) {
            String json = stringRedisTemplate.opsForList().leftPop(REDIS_ADHOC_PENDING_QUEUE);
            if (json == null || !StringUtils.hasText(json)) {
                break;
            }
            processed++;
            try {
                JSONObject o = JSON.parseObject(json);
                if (o == null) {
                    continue;
                }
                String url = o.getString("trackingUrl");
                String remark = o.getString("remark");
                String touser = o.getString("touser");
                String jobKey = o.getString("jobKey");
                int attempts = o.getIntValue("attempts");
                if (StringUtils.hasText(jobKey)) {
                    WeComShareLinkLogisticsJob row = weComShareLinkLogisticsJobMapper.selectByJobKey(jobKey.trim());
                    if (row == null || "CANCELLED".equalsIgnoreCase(row.getStatus())) {
                        logger.info("adhoc 队列项跳过（任务已删除或已取消扫描） jobKey={} rowNull={}", jobKey, row == null);
                        continue;
                    }
                }
                AdhocTryResult tr = tryAdhocShareLinkOnce(url, remark, touser, null);
                if (tr.needsRequeue) {
                    int nextAttempts = attempts + 1;
                    if (nextAttempts > ADHOC_MAX_REQUEUE_ATTEMPTS) {
                        logger.warn("adhoc 已达最大重试次数 {}，放弃 jobKey={} url={} note={}",
                            ADHOC_MAX_REQUEUE_ATTEMPTS, jobKey, url, tr.note);
                        touchShareLinkJobRow(jobKey, "ABANDONED", tr.note, nextAttempts, null);
                        continue;
                    }
                    o.put("attempts", nextAttempts);
                    stringRedisTemplate.opsForList().rightPush(REDIS_ADHOC_PENDING_QUEUE, o.toJSONString());
                    touchShareLinkJobRow(jobKey, "WAITING", tr.note, nextAttempts, null);
                } else {
                    int doneAttempts = attempts + 1;
                    touchShareLinkJobRow(jobKey, "PUSHED",
                        tr.note, doneAttempts, StringUtils.hasText(tr.waybillNo) ? tr.waybillNo : null);
                }
            } catch (Exception e) {
                logger.error("adhoc 队列项处理失败 raw={}", json.length() > 200 ? json.substring(0, 200) + "..." : json, e);
            }
        }
        return processed;
    }

    @Override
    public void clearAdhocPendingQueue() {
        Boolean deleted = stringRedisTemplate.delete(REDIS_ADHOC_PENDING_QUEUE);
        logger.info("adhoc 待扫描队列已清理 key={} existed={}", REDIS_ADHOC_PENDING_QUEUE, Boolean.TRUE.equals(deleted));
    }

    @Override
    public boolean fetchLogisticsByShareLinkAndPush(String trackingUrl, String remark, String touser) {
        if (!StringUtils.hasText(trackingUrl)) {
            logger.warn("分享物流链接为空");
            return false;
        }
        AdhocTryResult tr = tryAdhocShareLinkOnce(trackingUrl, remark, touser, null);
        return !tr.needsRequeue;
    }

    @Override
    public Map<String, Object> adminFetchShareLinkLogisticsDebug(String trackingUrl, String remark, String touser) {
        Map<String, Object> debug = new LinkedHashMap<>();
        AdhocTryResult tr = tryAdhocShareLinkOnce(trackingUrl, remark, touser, debug);
        debug.put("terminalSuccess", !tr.needsRequeue);
        debug.put("adhocNote", tr.note);
        if (StringUtils.hasText(tr.waybillNo)) {
            debug.put("waybillNo", tr.waybillNo);
        }
        return debug;
    }

    private void touchShareLinkJobRow(String jobKey, String status, String lastNote, int scanAttempts, String waybillNo) {
        if (!StringUtils.hasText(jobKey)) {
            return;
        }
        try {
            weComShareLinkLogisticsJobMapper.updateByJobKey(jobKey.trim(), status, lastNote, scanAttempts, waybillNo);
        } catch (Exception e) {
            logger.warn("adhoc 任务状态更新失败 jobKey={} err={}", jobKey, e.toString());
        }
    }

    /**
     * 处理一条分享链：需要重新入队时 {@link #needsRequeue} 为 true（未发货、接口异常、推送失败等）。
     *
     * @param debug 非空时写入与订单手动接口相近的调试字段（requestUrl、responseRaw、responseData、pushSent 等）
     */
    private AdhocTryResult tryAdhocShareLinkOnce(String trackingUrl, String remark, String touser, Map<String, Object> debug) {
        if (debug != null) {
            debug.put("pushSent", false);
        }
        if (!StringUtils.hasText(trackingUrl)) {
            if (debug != null) {
                debug.put("error", "分享物流链接为空");
            }
            return AdhocTryResult.requeue("empty_url");
        }
        String url = trackingUrl.trim();
        if (debug != null) {
            debug.put("trackingUrl", url);
            debug.put("logisticsLink", url);
            debug.put("userRemark", remark != null ? remark : "");
        }
        String dedupeKey = REDIS_ADHOC_WAYBILL_PREFIX + DigestUtils.md5DigestAsHex(url.getBytes(StandardCharsets.UTF_8));
        try {
            ILogisticsService.HealthCheckResult healthResult = checkHealth();
            if (!healthResult.isHealthy()) {
                logger.error("物流服务不可用，adhoc 将重试: {}", healthResult.getMessage());
                if (debug != null) {
                    debug.put("healthOk", false);
                    debug.put("healthMessage", healthResult.getMessage());
                }
                return AdhocTryResult.requeue("health:" + healthResult.getMessage());
            }
            if (debug != null) {
                debug.put("healthOk", true);
            }
            String externalUrl = buildFetchLogisticsRequestUrl(url);
            if (debug != null) {
                debug.put("requestUrl", externalUrl);
            }
            String result = HttpUtils.sendGet(externalUrl);
            if (!StringUtils.hasText(result)) {
                logger.warn("物流接口空响应 adhoc，将重试");
                if (debug != null) {
                    debug.put("responseRaw", result);
                }
                return AdhocTryResult.requeue("empty_http_body");
            }
            if (debug != null) {
                debug.put("responseRaw", result);
            }
            JSONObject parsedData;
            try {
                Object parsed = JSON.parse(result);
                if (!(parsed instanceof JSONObject)) {
                    if (debug != null) {
                        debug.put("responseData", parsed);
                    }
                    return AdhocTryResult.requeue("not_json_object");
                }
                parsedData = (JSONObject) parsed;
            } catch (Exception e) {
                logger.warn("物流响应非JSON adhoc: {}", e.getMessage());
                if (debug != null) {
                    debug.put("jsonParseError", e.getMessage());
                }
                return AdhocTryResult.requeue("json_parse:" + e.getMessage());
            }
            if (debug != null) {
                debug.put("responseData", parsedData);
            }
            JSONObject dataObj = parsedData.getJSONObject("data");
            if (dataObj == null) {
                return AdhocTryResult.requeue("no_data_field");
            }
            String waybillNo = dataObj.getString("waybill_no");
            if (!StringUtils.hasText(waybillNo)) {
                logger.info("adhoc 暂未返回运单号（可能未发货），将重新入队");
                return AdhocTryResult.requeue("no_waybill_yet");
            }
            waybillNo = waybillNo.trim();
            String existing = stringRedisTemplate.opsForValue().get(dedupeKey);
            if (existing != null && existing.equals(waybillNo)) {
                logger.info("adhoc 该链接已推送过运单 {}", waybillNo);
                if (debug != null) {
                    debug.put("pushSent", false);
                    debug.put("skipPushReason", "already_pushed_same_waybill");
                }
                return AdhocTryResult.done("already_pushed", waybillNo);
            }
            StringBuilder pushContent = new StringBuilder();
            pushContent.append("【分享链接物流】\n");
            pushContent.append("备注：").append(remark != null ? remark : "").append("\n");
            pushContent.append("原链接：").append(url).append("\n");
            pushContent.append("运单号：\n\n\n\n").append(waybillNo).append("\n");
            JSONObject pushParam = new JSONObject();
            pushParam.put("title", "JD物流(分享链接)");
            pushParam.put("text", pushContent.toString());
            if (StringUtils.hasText(touser)) {
                pushParam.put("touser", touser.trim());
            } else {
                logger.info("adhoc 推送未设置接收人 touser，将使用远程接口默认接收人（与订单未配分销接收人时一致）");
            }
            String pushResult = sendPostWithHeaders(PUSH_URL, pushParam.toJSONString(), PUSH_TOKEN);
            boolean success = isPushResponseSuccess(pushResult);
            if (debug != null) {
                debug.put("pushSent", success);
                if (!success && pushResult != null) {
                    debug.put("pushError", pushResult.length() > 500 ? pushResult.substring(0, 500) + "..." : pushResult);
                }
            }
            if (success) {
                stringRedisTemplate.opsForValue().set(dedupeKey, waybillNo, 30, TimeUnit.DAYS);
                logger.info("adhoc 物流推送成功 waybill={}", waybillNo);
                return AdhocTryResult.done("pushed", waybillNo);
            }
            logger.warn("adhoc 推送接口未成功，将重新入队 waybill={} respSnippet={}",
                waybillNo, pushResult != null && pushResult.length() > 120 ? pushResult.substring(0, 120) : pushResult);
            return AdhocTryResult.requeue("push_failed");
        } catch (Exception e) {
            logger.error("adhoc 物流推送异常，将重新入队", e);
            if (debug != null) {
                debug.put("exception", e.getMessage());
            }
            return AdhocTryResult.requeue("exception:" + e.getMessage());
        }
    }

    private static final class AdhocTryResult {
        final boolean needsRequeue;
        final String note;
        final String waybillNo;

        private AdhocTryResult(boolean needsRequeue, String note, String waybillNo) {
            this.needsRequeue = needsRequeue;
            this.note = note;
            this.waybillNo = waybillNo;
        }

        static AdhocTryResult requeue(String note) {
            return new AdhocTryResult(true, note, null);
        }

        static AdhocTryResult done(String note, String waybillNo) {
            return new AdhocTryResult(false, note, waybillNo);
        }
    }
    
    /**
     * 调用企业应用推送逻辑
     * @param order 订单信息
     * @param waybillNo 运单号
     * @param logisticsLinkUpdated 物流链接是否已更新
     * @param oldLogisticsLink 旧的物流链接（如果更新了）
     * @param newLogisticsLink 新的物流链接（如果更新了）
     */
    private boolean sendEnterprisePushNotification(JDOrder order, String waybillNo, boolean logisticsLinkUpdated, String oldLogisticsLink, String newLogisticsLink) {
        try {
            String distributionMark = order.getDistributionMark() != null ? order.getDistributionMark() : "\u672a\u77e5";
            String thirdPartyOrderNo = order.getThirdPartyOrderNo();
            String modelStr = order.getModelNumber() != null ? order.getModelNumber() : "\u65e0";
            String addressStr = order.getAddress() != null ? order.getAddress() : "\u65e0";

            boolean goofishLinked = erpGoofishOrderService.hasLinkedGoofishOrder(order.getId())
                || (distributionMark != null && distributionMark.contains("\u95f2\u9c7c"));

            if (goofishLinked) {
                // 闲鱼单：不在京东扫到运单环节发企微；仅写 Redis 并 notifyJdWaybillReady / tryAutoShip。
                // 真发货成功后由 GoofishOrderChangeLogger SHIP 事件发 wx。
                logger.info("闲鱼关联/分销：跳过本环节企微直推 - 订单ID: {}, 订单号: {}, waybill_no: {}",
                    order.getId(), order.getOrderId(), waybillNo);
                return true;
            }

            // 非闲鱼：PDD 企微，完整 JD 物流版式
            StringBuilder std = new StringBuilder();
            std.append("JD物流信息推送").append("\n");
            std.append(distributionMark).append("\n");
            if (thirdPartyOrderNo != null && !thirdPartyOrderNo.trim().isEmpty()) {
                std.append("第三方单号：").append(thirdPartyOrderNo.trim()).append("\n");
            }
            std.append("型号：").append(modelStr).append("\n");
            std.append("收货地址：").append(addressStr).append("\n");
            if (logisticsLinkUpdated && newLogisticsLink != null && !newLogisticsLink.trim().isEmpty()) {
                std.append("【物流链接已更新】").append("\n");
                std.append("新物流链接：").append(newLogisticsLink.trim()).append("\n");
                if (oldLogisticsLink != null && !oldLogisticsLink.trim().isEmpty()) {
                    std.append("旧物流链接：").append(oldLogisticsLink.trim()).append("\n");
                }
                std.append("\n");
            }
            std.append("运单号：").append("\n").append("\n").append("\n").append("\n").append(waybillNo).append("\n");
            String fullText = std.toString();

            // 调用企业微信推送接口（PDD 自建应用）
            JSONObject pushParam = new JSONObject();
            pushParam.put("title", "");
            pushParam.put("text", fullText);
            
            // 根据分销标识获取接收人列表
            String touser = getTouserByDistributionMark(distributionMark);
            if (StringUtils.hasText(touser)) {
                pushParam.put("touser", touser);
                logger.info("企业微信推送设置接收人 - 订单ID: {}, 分销标识: {}, 接收人: {}", 
                    order.getId(), distributionMark, touser);
            } else {
                // 未配置接收人时，使用远程接口的默认接收人，这是正常情况
                logger.info("未找到分销标识对应的接收人配置，将使用远程接口默认接收人 - 订单ID: {}, 分销标识: {}", 
                    order.getId(), distributionMark);
            }
            
            // 记录完整的推送参数（用于调试）
            String jsonBody = pushParam.toJSONString();
            if (logisticsLinkUpdated) {
                logger.info("企业微信推送完整参数（已更新物流链接） - 订单ID: {}, 订单号: {}, 旧链接: {}, 新链接: {}, JSON: {}", 
                    order.getId(), order.getOrderId(), oldLogisticsLink, newLogisticsLink, jsonBody);
            } else {
                logger.info("企业微信推送完整参数 - 订单ID: {}, 订单号: {}, JSON: {}", 
                    order.getId(), order.getOrderId(), jsonBody);
            }
            
            // 使用支持自定义header的HTTP请求
            String pushResult = sendPostWithHeaders(PUSH_URL, jsonBody, PUSH_TOKEN);
            if (pushResult == null || pushResult.trim().isEmpty()) {
                logger.warn("企业应用推送响应为空 - 订单ID: {}, waybill_no: {}", order.getId(), waybillNo);
                return false;
            }
            
            boolean success = isPushResponseSuccess(pushResult);
            if (success) {
                if (logisticsLinkUpdated) {
                    logger.info("企业应用推送成功（已更新物流链接） - 订单ID: {}, 订单号: {}, waybill_no: {}, 新链接: {}, 推送结果: {}", 
                        order.getId(), order.getOrderId(), waybillNo, newLogisticsLink, pushResult);
                } else {
                    logger.info("企业应用推送成功 - 订单ID: {}, 订单号: {}, waybill_no: {}, 推送结果: {}", 
                        order.getId(), order.getOrderId(), waybillNo, pushResult);
                }
            } else {
                logger.warn("企业应用推送响应未确认成功 - 订单ID: {}, 订单号: {}, waybill_no: {}, 响应: {}", 
                    order.getId(), order.getOrderId(), waybillNo, pushResult);
            }
            return success;
            
        } catch (Exception e) {
            logger.error("调用企业应用推送失败 - 订单ID: {}, waybill_no: {}, 错误: {}", 
                order.getId(), waybillNo, e.getMessage(), e);
            // 不抛出异常，主流程根据返回值决定是否重试
            return false;
        }
    }
    
    /**
     * 根据分销标识获取接收人列表
     * 从系统配置中读取，配置键名格式：logistics.push.touser.{分销标识}
     * 配置值格式：接收人1,接收人2,接收人3（逗号分隔）
     * 
     * @param distributionMark 分销标识
     * @return 接收人列表（逗号分隔），如果未配置则返回null
     */
    private String getTouserByDistributionMark(String distributionMark) {
        if (!StringUtils.hasText(distributionMark)) {
            logger.warn("分销标识为空，无法获取接收人配置");
            return null;
        }
        
        try {
            String trimmed = distributionMark.trim();
            // 构建配置键名（可与订单中的标识完全一致，如 F-王杰）
            String configKey = CONFIG_KEY_PREFIX + trimmed;
            String configValue = sysConfigService.selectConfigByKey(configKey);
            
            if (StringUtils.hasText(configValue)) {
                String touser = configValue.trim().replaceAll(",\\s+", ",");
                logger.info("从配置获取接收人列表 - 分销标识: {}, 配置键: {}, 接收人: {}", 
                    distributionMark, configKey, touser);
                return touser;
            }
            // F、F-中文 等未单独配置时，共用 logistics.push.touser.F
            if (trimmed.startsWith("F-") || "F".equals(trimmed)) {
                if (!trimmed.equals("F")) {
                    String fallbackKey = CONFIG_KEY_PREFIX + "F";
                    String fallbackVal = sysConfigService.selectConfigByKey(fallbackKey);
                    if (StringUtils.hasText(fallbackVal)) {
                        String touser = fallbackVal.trim().replaceAll(",\\s+", ",");
                        logger.info("从配置获取接收人列表（F 系回退） - 分销标识: {}, 配置键: {}, 接收人: {}",
                            distributionMark, fallbackKey, touser);
                        return touser;
                    }
                }
            }
            logger.debug("未找到接收人配置 - 分销标识: {}, 配置键: {}", distributionMark, configKey);
            return null;
        } catch (Exception e) {
            logger.error("获取接收人配置失败 - 分销标识: {}, 错误: {}", distributionMark, e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 判断推送返回值是否为成功状态
     * @param pushResult 推送接口返回结果
     * @return 是否成功
     */
    private boolean isPushResponseSuccess(String pushResult) {
        if (pushResult == null || pushResult.trim().isEmpty()) {
            logger.warn("推送响应为空，视为失败");
            return false;
        }
        
        try {
            JSONObject response = JSON.parseObject(pushResult);
            if (response == null) {
                logger.warn("推送响应解析为null，视为失败。原始响应: {}", pushResult);
                return false;
            }
            
            Integer code = response.getInteger("code");
            Boolean successFlag = response.getBoolean("success");
            String status = response.getString("status");
            String message = response.getString("msg");
            String errcode = response.getString("errcode");
            
            // 记录完整的响应信息用于调试
            logger.debug("推送响应解析 - code: {}, success: {}, status: {}, msg: {}, errcode: {}", 
                code, successFlag, status, message, errcode);
            
            // 检查错误码（errcode为0表示成功）
            if (errcode != null && "0".equals(errcode)) {
                logger.info("推送成功（通过errcode=0判断）");
                return true;
            }
            
            // 检查code字段（0或200表示成功）
            if (code != null && (code == 0 || code == 200)) {
                logger.info("推送成功（通过code={}判断）", code);
                return true;
            }
            
            // 检查success字段
            if (Boolean.TRUE.equals(successFlag)) {
                logger.info("推送成功（通过success=true判断）");
                return true;
            }
            
            // 检查status字段
            if (status != null && ("success".equalsIgnoreCase(status) || "ok".equalsIgnoreCase(status))) {
                logger.info("推送成功（通过status={}判断）", status);
                return true;
            }
            
            // 检查message字段（某些接口可能用message表示成功）
            if (message != null && ("success".equalsIgnoreCase(message) || "ok".equalsIgnoreCase(message))) {
                logger.info("推送成功（通过message={}判断）", message);
                return true;
            }
            
            // 检查是否包含明确的错误标识
            String responseStr = pushResult.toLowerCase();
            boolean hasErrorKeyword = responseStr.contains("\"error\"") || responseStr.contains("\"fail\"") || 
                responseStr.contains("\"failed\"") || responseStr.contains("\"errmsg\"");
            
            // 如果包含错误标识，检查是否有明确的错误码
            if (hasErrorKeyword) {
                if (code != null && code < 0) {
                    logger.warn("推送失败（检测到错误标识和负错误码） - code: {}, 完整响应: {}", code, pushResult);
                    return false;
                }
                if (errcode != null && !"0".equals(errcode) && !errcode.isEmpty()) {
                    logger.warn("推送失败（检测到错误标识和非零错误码） - errcode: {}, 完整响应: {}", errcode, pushResult);
                    return false;
                }
            }
            
            // 如果响应是有效的JSON，且没有明确的错误标识，视为成功
            // 因为远程接口有默认接收人，即使没有配置接收人，推送也应该成功
            // 如果响应格式特殊（不是标准格式），只要没有错误，也视为成功
            if (!hasErrorKeyword) {
                logger.info("推送成功（响应格式有效且无错误标识，使用默认接收人） - 完整响应: {}", pushResult);
                return true;
            }
            
            // 如果所有判断都失败，记录详细信息
            logger.warn("推送响应未确认成功 - code: {}, success: {}, status: {}, msg: {}, errcode: {}, 完整响应: {}", 
                code, successFlag, status, message, errcode, pushResult);
            return false;
        } catch (Exception e) {
            logger.error("解析企业应用推送响应失败，将视为未成功。原始响应: {}, 错误: {}", pushResult, e.getMessage(), e);
            return false;
        }
    }
    
    /**
     * 发送POST请求，支持自定义header（用于企业微信推送）
     * @param url 请求URL
     * @param jsonBody JSON请求体
     * @param token 认证token
     * @return 响应结果
     */
    private String sendPostWithHeaders(String url, String jsonBody, String token) {
        java.io.BufferedReader in = null;
        java.io.PrintWriter out = null;
        StringBuilder result = new StringBuilder();
        try {
            java.net.URL realUrl = new java.net.URL(url);
            java.net.URLConnection conn = realUrl.openConnection();
            
            // 设置请求头
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("vanToken", token);
            conn.setRequestProperty("source", "XZJ_UBUNTU");
            
            conn.setDoOutput(true);
            conn.setDoInput(true);
            
            // 发送请求体
            out = new java.io.PrintWriter(conn.getOutputStream());
            out.print(jsonBody);
            out.flush();
            
            // 读取响应
            in = new java.io.BufferedReader(new java.io.InputStreamReader(conn.getInputStream(), java.nio.charset.StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            
            logger.info("企业微信推送请求成功 - URL: {}, 响应: {}", url, result.toString());
        } catch (java.net.ConnectException e) {
            logger.error("企业微信推送连接失败 - URL: {}", url, e);
            throw new RuntimeException("推送连接失败: " + e.getMessage(), e);
        } catch (java.net.SocketTimeoutException e) {
            logger.error("企业微信推送超时 - URL: {}", url, e);
            throw new RuntimeException("推送请求超时: " + e.getMessage(), e);
        } catch (java.io.IOException e) {
            logger.error("企业微信推送IO异常 - URL: {}", url, e);
            throw new RuntimeException("推送IO异常: " + e.getMessage(), e);
        } catch (Exception e) {
            logger.error("企业微信推送异常 - URL: {}", url, e);
            throw new RuntimeException("推送异常: " + e.getMessage(), e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (java.io.IOException ex) {
                logger.error("关闭流异常", ex);
            }
        }
        return result.toString();
    }
}

