package cn.van.business.util;


import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.van.business.model.jd.OrderRow;
import cn.van.business.model.pl.Comment;
import cn.van.business.repository.CommentRepository;
import cn.van.business.repository.OrderRowRepository;
import cn.van.business.util.ds.DeepSeekClientUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jd.open.api.sdk.DefaultJdClient;
import com.jd.open.api.sdk.JdClient;
import com.jd.open.api.sdk.domain.kplunion.CouponService.request.get.CreateGiftCouponReq;
import com.jd.open.api.sdk.domain.kplunion.GoodsService.request.query.GoodsReq;
import com.jd.open.api.sdk.domain.kplunion.GoodsService.response.query.GoodsQueryResult;
import com.jd.open.api.sdk.domain.kplunion.GoodsService.response.query.UrlInfo;
import com.jd.open.api.sdk.domain.kplunion.promotionbysubunioni.PromotionService.request.get.PromotionCodeReq;
import com.jd.open.api.sdk.request.kplunion.UnionOpenCouponGiftGetRequest;
import com.jd.open.api.sdk.request.kplunion.UnionOpenGoodsQueryRequest;
import com.jd.open.api.sdk.request.kplunion.UnionOpenPromotionBysubunionidGetRequest;
import com.jd.open.api.sdk.response.kplunion.UnionOpenCouponGiftGetResponse;
import com.jd.open.api.sdk.response.kplunion.UnionOpenGoodsQueryResponse;
import com.jd.open.api.sdk.response.kplunion.UnionOpenPromotionBysubunionidGetResponse;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.van.business.util.JDUtil.UserInteractionState.GiftMoneyStep.*;
import static cn.van.business.util.JDUtil.UserInteractionState.ProcessState.INIT;
import static cn.van.business.util.WXUtil.*;

/**
 * @author Leo
 * @version 1.0
 * @create 2024/11/5 17:40
 * @description：
 */
@Component
public class JDUtil {
    static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    /**
     * 密钥配置
     */

    // van论坛
    private static final String LPF_APP_KEY_WZ = "98e21c89ae5610240ec3f5f575f86a59";
    private static final String LPF_SECRET_KEY_WZ = "3dcb6b23a1104639ac433fd07adb6dfb";
    private static final String LPF_WZ_ID = "4101253066";
    // 导购的
    private static final String LPF_APP_KEY_DG = "faf410cb9587dc80dc7b31e321d7d322";
    private static final String LPF_SECRET_KEY_DG = "a4fb15d7bedd4316b97b4e96e4effc1c";
    private static final String LL_APP_KEY_DG = "9c2011409f0fc906b73432dd3687599d";
    private static final String LL_SECRET_KEY_DG = "3ceddff403e544a8a2eacc727cf05dab";
    private static final String SERVER_URL = "https://api.jd.com/routerjson";
    //accessToken
    private static final String ACCESS_TOKEN = "";
    private static final Logger logger = LoggerFactory.getLogger(JDUtil.class);
    private static final String INTERACTION_STATE_PREFIX = "interaction_state:";
    private static final String PRODUCT_TYPE_MAP_PREFIX = "product_type_map";
    private static HashMap<String, String> productTypeMap = new HashMap<>();
    private static final String COMMENT_TEMPLATES_DS = "我需要为我的商品模拟一些商品评论。你协助我生成3条评价内容，京东商品评价的风格，每条评价100字即可，不需要太浮夸，也不要太像ai生成，尽量模拟真实客户评价，不要提到以旧换新和国家补贴。我会为你提供其他真实用户的评论：";
    private static final long TIMEOUT_MINUTES = 5;
    private static final String WENAN_FANAN_LQD = "提供方法自己下单\n" + "全程都是自己的账号下单\n" + "标价就是下单的到手价\n" + "本人有耐心，会一步一步提供教程\n" + "以后有什么质量问题都是用自己的账号走京东售后\n" + "\n" + "更新\n" + "\n" + "用你自己的账号下单\n" + "官方店铺 提供方法自己下单\n" + "——————————————————————————————————————————\n" + "同行可长久合作，可提供神级家电线报\n" + "\n" + "配合家电线报可以自己下单，不用找代购和代下，订单和利润都掌握在自己手中。\n" + "\n" + "一次入会永久使用，包含家电帮，雷神价，韭菜帮，河南&湖南帮，各种暗号帮后返等内部独家家电线报\n" + "\n" + "JD采销采购不定时发放独家优惠券\n" + "\n" + "基本上你能看到的京东家电低价都是从这些渠道里面出来。\n" + "\n" + "2025年家电项目新方向，配合家电线报下单，秒省1K+。";
    private static final String WENAN_FANAN_HG = "手把手教你实现超值下单，无需依赖他人！全程使用个人专属账号操作，所见即所得，页面标价即为最终到手价。别担心操作难题，我会全程贴心指导，每一步都细致讲解，助你轻松下单。后续若出现任何质量问题，凭借个人账号就能直接对接JD官方售后，售后无忧。\n" + "更新\n" + "采用自主账号下单模式，官方店铺商品随心购，专业方法全程提供！\n" + "——————————————————————————————————————————\n" + "诚邀同行建立长期合作关系，海量独家家电优惠线报倾囊相授！\n" + "借助这些优质家电线报，无需寻求代购代下服务，自己就能轻松下单，订单信息与收益牢牢掌握在手中。\n" + "一次加入，终身受益！涵盖家电帮、雷神价、韭菜帮、河南 & 湖南帮等众多渠道，还有各类暗号帮后返等内部专属家电优惠信息一网打尽。\n" + "JD采销团队会不定时发放独家隐藏优惠券，市面上那些令人心动的JD家电低价好物，大多都源自这些渠道！\n" + "2025 年家电选购新趋势，依托线报下单，轻松省下千元开支，开启超值购物之旅！";
    private static final String WENAN_ZCXS = "\n" + "购买后，两小时内出库，物流会电话联系您，同时生成京东官方安装单。送装一体，无需担心。\n" + "\n" + "\n" + "1:全新正品，原包装未拆封(京东商城代购，就近直发)\n" + "2:可提供下单运单号与电子发票（发票在收到货后找我要）。\n" + "3:收货时查看是否有质量或运损问题。可拍照让京东免费申请换新。\n" + "4:下单后非质量问题不支持退款退货，强制退扣100元。\n" + "5:价格有浮动，不支持补差价，谢谢理解。\n" + "6:全国联保，全国统一安装标准。支持官方 400，服务号查询，假一赔十。\n";
    private static final String FANAN_COMMON = "\n复制到薇，依次领券，到J东APP结算\n" + "换新选生活电器-除螨仪，可免回收\n";
    /**
     * 内部单号：
     * 分销标记（标记用，勿改）：
     * 型号：
     * <p>
     * 价格：
     * <p>
     * 后返：
     * <p>
     * 地址：
     * <p>
     * 物流单号：
     * <p>
     * 订单号：
     */
    private static final String WENAN_D = "单：{单的备注}\n" + "{单号} \n" + "分销标记：{分销标记}\n" + "型号：\n" + "{型号}" + "\n" + "链接：\n" + "{链接}" + "\n" + "下单付款：\n" + "\n" + "后返金额：\n" + "\n" + "地址：\n" + "{地址}" + "\n" + "物流链接：\n" + "\n" + "订单号：\n" + "\n" + "下单人：\n" + "\n";

    final WXUtil wxUtil;
    private final StringRedisTemplate redisTemplate;
    private final OrderRowRepository orderRowRepository;
    private final CommentRepository commentRepository;

    private final OrderUtil orderUtil;
    private final DeepSeekClientUtil deepSeekClientUtil;
    // 添加ObjectMapper来序列化和反序列化UserInteractionState
    private final ObjectMapper objectMapper = new ObjectMapper();
    private final ConcurrentHashMap<String, UserInteractionState> userInteractionStates = new ConcurrentHashMap<>();
    private HashMap<String, String> cacheMap = new HashMap<>();

    // 构造函数中注入StringRedisTemplate
    @Autowired
    public JDUtil(StringRedisTemplate redisTemplate, OrderRowRepository orderRowRepository, WXUtil wxUtil, OrderUtil orderUtil, DeepSeekClientUtil deepSeekClientUtil, CommentRepository commentRepository) {

        this.redisTemplate = redisTemplate;
        this.orderRowRepository = orderRowRepository;
        this.wxUtil = wxUtil;
        this.orderUtil = orderUtil;
        this.deepSeekClientUtil = deepSeekClientUtil;
        this.commentRepository = commentRepository;
    }

    private List<OrderRow> filterOrdersByDate(List<OrderRow> orderRows, int daysBack) {
        LocalDate now = LocalDate.now();

        return orderRows.stream().filter(order -> {
            // 将 Date 转换为 LocalDate
            LocalDate orderDate = order.getOrderTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

            // 计算是否在给定的天数内
            return !orderDate.isBefore(now.minusDays(daysBack)) && !orderDate.isAfter(now);
        }).collect(Collectors.toList());
    }

    private Stream<OrderRow> getStreamForWeiGui(List<OrderRow> todayOrders) {
        return todayOrders.stream().filter(orderRow -> orderRow.getValidCode() == 13 || orderRow.getValidCode() == 25 || orderRow.getValidCode() == 26 || orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28 || orderRow.getValidCode() == 29);
    }

    /**
     * 拼多多地址
     */
    public String convertAddress(String input) {
        try {
            // 正则表达式分解输入内容
            Pattern pattern = Pattern.compile("^(.+?)\\[(\\d+)\\]\\s+(\\d+)\\s+(.+)\\[\\d+]$");
            Matcher matcher = pattern.matcher(input);

            if (matcher.matches()) {
                // 提取各部分内容
                String name = matcher.group(1);
                String code = matcher.group(2);
                String phone = matcher.group(3);
                String address = matcher.group(4).trim();

                // 构造新地址格式
                return String.format("%s 13068923963 %s联系客户%s转%s", name, address, phone, code);
            }
        } catch (Exception ignored) {
            return "地址格式不匹配";
        }
        return "地址格式不匹配";
    }


    public void sendOrderToWxByOrderDefault(String order, String fromWxid) {
        logger.info("执行 sendOrderToWxByOrderDefault 方法，order: {}, fromWxid: {}", order, fromWxid);
        handleUserInteraction(fromWxid, order);
        // 具体逻辑
    }

    public void xb(String message, String fromWxid) {
        logger.info("执行 线报处理 方法，order: {}", message);
        if (message.contains("https://u.jd")) {
            String chatRoomRemark = chatRoom_xb.get(fromWxid);

            wxUtil.sendTextMessage(chatRoom_BY, "线报来源 \n " + chatRoomRemark + "\n\n " + message, 1, chatRoom_BY, true);

            // 2. 生成推广内容
            HashMap<String, List<String>> contentResult = generatePromotionContent(message, true);

            // 3. 发送文本内容
            for (String text : contentResult.get("text")) {
                wxUtil.sendTextMessage(chatRoom_BY, text, 1, chatRoom_BY, true);
            }

        }
        // 具体逻辑
    }

    private OrderStats calculateStats(List<OrderRow> orders) {
        long paid = orders.stream().filter(o -> o.getValidCode() == 16).count();
        long pending = orders.stream().filter(o -> o.getValidCode() == 15).count();
        long canceled = orders.stream().filter(o -> o.getValidCode() != 16 && o.getValidCode() != 17).count();
        long completed = orders.stream().filter(o -> o.getValidCode() == 17).count();

        return new OrderStats(orders.size(), orders.size() - canceled, paid, orders.stream().filter(o -> o.getValidCode() == 16).mapToDouble(OrderRow::getEstimateFee).sum(), pending, orders.stream().filter(o -> o.getValidCode() == 15).mapToDouble(OrderRow::getEstimateFee).sum(), canceled, completed, orders.stream().filter(o -> o.getValidCode() == 17).mapToDouble(OrderRow::getEstimateFee).sum(), getStreamForWeiGui(orders).count(), getStreamForWeiGui(orders).mapToDouble(o -> o.getEstimateCosPrice() * o.getCommissionRate() * 0.01).sum());
    }

    private StringBuilder buildStatsContent(String title, OrderStats stats) {
        StringBuilder content = new StringBuilder();
        content//[爱心][Wow][Packet][Party][Broken][心碎][亲亲][色]
                .append("* ").append(title).append(" *\n").append("━━━━━━━━━━━━\n").append("[爱心] 订单总数：").append(stats.getTotalOrders()).append("\n")  // [文件]
                .append("[Party] 有效订单：").append(stats.getValidOrders()).append("\n")  // [OK]
                .append("[心碎]已取消：").append(stats.getCanceledOrders()).append("\n")  // [禁止]

                .append("────────────\n").append("[爱心]已付款：").append(stats.getPaidOrders()).append("\n")  // [钱袋]
                .append("[Packet] 已付款佣金：").append(String.format("%.2f", stats.getPaidCommission())).append("\n")  // [钞票]
                .append("────────────\n").append("[Wow] 待付款：").append(stats.getPendingOrders()).append("\n")  // [时钟]
                .append("[Packet] 待付款佣金：").append(String.format("%.2f", stats.getPendingCommission())).append("\n")  // [钱]
                .append("────────────\n").append("[亲亲] 已完成：").append(stats.getCompletedOrders()).append("\n")  // [旗帜]
                .append("[Packet] 已完成佣金：").append(String.format("%.2f", stats.getCompletedCommission())).append("\n")  // [信用卡]
                .append("────────────\n").append("[Emm] 违规订单：").append(stats.getViolations()).append("\n")  // [警告]
                .append("[Broken] 违规佣金：").append(String.format("%.2f", stats.getViolationCommission())).append("\n")  // [炸弹]
                .append("━━━━━━━━━━━━");
        return content;
    }

    public void sendOrderToWxByOrderPDD(String order, String fromWxid) {
        String convertAddress = convertAddress(order);
        wxUtil.sendTextMessage(fromWxid, convertAddress, 0, fromWxid, false);
    }


    /**
     * 接收京粉指令指令
     */
    public void sendOrderToWxByOrderJD(String order, String fromWxid) {

        int[] param = {-1};
        List<WXUtil.SuperAdmin> superAdmins = getSuperAdmins(fromWxid);
        List<Long> unionIds = new ArrayList<>();
        for (WXUtil.SuperAdmin superAdmin : superAdmins) {
            String unionId = superAdmin.getUnionId();
            unionIds.add(Long.valueOf(unionId));
        }

        List<OrderRow> orderRows = orderRowRepository.findByValidCodeNotInAndUnionIdIn(param, unionIds);
        /**
         * 菜单：
         * 今日统计
         * 昨日统计
         * 最近七天统计
         * 最近一个月统计
         * 今天订单
         * 昨天订单
         * */
        List<StringBuilder> contents = new ArrayList<>();
        StringBuilder content = new StringBuilder();
        switch (order) {
            case "菜单":

                content.append("菜单：京+命令 \n 如： 京今日统计\r");
                content.append("今日统计\r");
                content.append("昨天统计\r");
                content.append("七日统计\r");
                content.append("一个月统计\r");
                content.append("两个月统计\r");
                content.append("三个月统计\r");
                content.append("总统计\r\n");
                content.append("这个月统计\r");
                content.append("上个月统计\r\n");


                content.append("今日订单\r");
                content.append("昨日订单\r");
                content.append("七日订单\r");
                content.append("刷新7天\r");

                contents.add(content);
                content = new StringBuilder();

                content.append("高级菜单：京+高级+命令 \n   如： 京高级违规30\r");
                content.append("京高级违规+整数(不传数字为365天)\r");
                content.append("京高级SKU+sku\r");
                content.append("京高级搜索+搜索标题(精准查询订单号+精准查询sku+模糊查询收件人+模糊查询地址)，只返回最近100条\r");

                contents.add(content);

                //content = new StringBuilder();
                //
                //content.append("礼金\r");
                //content.append("转链\r");
                //
                //contents.add(content);
                break;
            case "测试指令": {
                //test01();
                break;
            }
            case "今日统计": {
                // 订单总数，已付款，已取消，佣金总计
                List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
                OrderStats stats = calculateStats(todayOrders);
                contents.add(buildStatsContent("今日统计", stats));
                break;
            }
            case "昨日统计": {
                List<OrderRow> yesterdayOrders = filterOrdersByDate(orderRows, 1);
                OrderStats stats = calculateStats(yesterdayOrders);
                contents.add(buildStatsContent("昨日统计", stats));

                break;
            }
            case "三日统计": {
                List<OrderRow> last3DaysOrders = filterOrdersByDate(orderRows, 3);
                OrderStats stats = calculateStats(last3DaysOrders);
                contents.add(buildStatsContent("三日统计", stats));
                break;
            }
            case "七日统计": {
                List<OrderRow> last7DaysOrders = filterOrdersByDate(orderRows, 7);
                OrderStats stats = calculateStats(last7DaysOrders);
                contents.add(buildStatsContent("七日统计", stats));
                break;
            }
            case "一个月统计": {
                List<OrderRow> last30DaysOrders = filterOrdersByDate(orderRows, 30);
                OrderStats stats = calculateStats(last30DaysOrders);
                contents.add(buildStatsContent("一个月统计", stats));
                break;
            }
            case "两个月统计": {
                List<OrderRow> last60DaysOrders = filterOrdersByDate(orderRows, 60);
                OrderStats stats = calculateStats(last60DaysOrders);
                contents.add(buildStatsContent("两个月统计", stats));
                break;
            }
            case "三个月统计": {
                List<OrderRow> last90DaysOrders = filterOrdersByDate(orderRows, 90);
                OrderStats stats = calculateStats(last90DaysOrders);
                contents.add(buildStatsContent("三个月统计", stats));
                break;
            }
            case "这个月统计": {
                // 计算出距离1号有几天
                int days = LocalDate.now().getDayOfMonth();
                List<OrderRow> thisMonthOrders = filterOrdersByDate(orderRows, days);
                OrderStats stats = calculateStats(thisMonthOrders);
                contents.add(buildStatsContent("这个月统计", stats));
                break;
            }
            case "上个月统计": {
                LocalDate lastMonth = LocalDate.now().minusMonths(1);
                int days = LocalDate.now().getDayOfMonth();

                List<OrderRow> lastMonthOrders = filterOrdersByDate(orderRows, lastMonth.lengthOfMonth() + days);
                List<OrderRow> thisMonthOrders = filterOrdersByDate(orderRows, days);
                lastMonthOrders = lastMonthOrders.stream().filter(orderRow -> !thisMonthOrders.contains(orderRow)).collect(Collectors.toList());

                OrderStats stats = calculateStats(lastMonthOrders);
                contents.add(buildStatsContent("上个月统计", stats));
                break;

            }
            //总统计

            case "总统计": {
                OrderStats stats = calculateStats(orderRows);
                contents.add(buildStatsContent("总统计", stats));
                break;
            }


            case "今日订单": {

                List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
                // 订单总数，已付款，已取消，佣金总计
                OrderStats stats = calculateStats(todayOrders);
                contents.add(buildStatsContent("今日统计", stats));
                if (!todayOrders.isEmpty()) {
                    orderUtil.orderToWxBatch(todayOrders);
                }
                break;
            }
            case "昨日订单": {

                content = new StringBuilder();
                List<OrderRow> yesterdayOrders = filterOrdersByDate(orderRows, 1);
                List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
                logger.info("原始订单数量：{}", orderRows.size());
                logger.info("昨日过滤后数量：{}", yesterdayOrders.size());
                yesterdayOrders.removeAll(todayOrders);
                logger.info("今日过滤后数量：{}", todayOrders.size());
                logger.info("最终昨日订单数量：{}", yesterdayOrders.size());
                OrderStats stats = calculateStats(yesterdayOrders);
                contents.add(buildStatsContent("昨日统计", stats));
                if (!yesterdayOrders.isEmpty()) {
                    orderUtil.orderToWxBatch(yesterdayOrders);
                }
                break;
            }
            case "七日订单": {
                List<OrderRow> last7DaysOrders = filterOrdersByDate(orderRows, 1);
                List<OrderRow> todayOrders = filterOrdersByDate(orderRows, 0);
                last7DaysOrders.removeAll(todayOrders);
                OrderStats stats = calculateStats(last7DaysOrders);
                contents.add(buildStatsContent("七日统计", stats));

                if (!last7DaysOrders.isEmpty()) {
                    orderUtil.orderToWxBatch(last7DaysOrders);
                }
                break;
            }
            default:
                sendOrderToWxByOrderJDAdvanced(order, fromWxid);
        }
        if (!contents.isEmpty()) {
            for (StringBuilder stringBuilder : contents) {
                wxUtil.sendTextMessage(fromWxid, stringBuilder.toString(), 1, fromWxid, false);
            }
        }

    }

    /**
     * 接收京粉指令指令
     * 高级菜单
     */
    public void sendOrderToWxByOrderJDAdvanced(String order, String fromWxid) {
        int[] param = {-1};
        List<WXUtil.SuperAdmin> superAdmins = getSuperAdmins(fromWxid);
        List<Long> unionIds = new ArrayList<>();
        for (WXUtil.SuperAdmin superAdmin : superAdmins) {
            String unionId = superAdmin.getUnionId();
            unionIds.add(Long.valueOf(unionId));
        }
        List<OrderRow> orderRows = orderRowRepository.findByValidCodeNotInAndUnionIdIn(param, unionIds);

        List<StringBuilder> contents = new ArrayList<>();
        StringBuilder content = new StringBuilder();
        if (order.startsWith("高级")) {
            content = new StringBuilder();
            order = order.replace("高级", "");
            if (order.startsWith("违规")) {
                String days = order.replace("违规", "");
                Integer daysInt = 365;
                if (Util.isNotEmpty(days)) {
                    daysInt = Integer.parseInt(days);
                }
                List<OrderRow> filterOrdersByDays = filterOrdersByDate(orderRows, daysInt);

                content.append("违规排行：");
                content.append(daysInt).append("天").append("\r\n");


                Map<String, Long> skuIdViolationCountMap = filterOrdersByDays.stream().filter(orderRow -> orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28).filter(orderRow -> orderRow.getSkuName() != null).collect(Collectors.groupingBy(OrderRow::getSkuName, // ✅ 拼接SKU
                        Collectors.counting()));
                Map<String, List<OrderInfo>> orderInfoMap = filterOrdersByDays.stream().filter(orderRow -> orderRow.getValidCode() == 27 || orderRow.getValidCode() == 28).filter(orderRow -> orderRow.getSkuName() != null).map(orderRow -> {
                    OrderInfo info = new OrderInfo();
                    info.setSkuName(orderRow.getSkuName());
                    info.setOrderId(orderRow.getOrderId());
                    info.setOrderDate(orderRow.getOrderTime());
                    return info;
                }).collect(Collectors.groupingBy(OrderInfo::getSkuName));

                List<Map.Entry<String, Long>> sortedViolationCounts = skuIdViolationCountMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).toList();

                Integer num = 0;
                for (Map.Entry<String, Long> entry : sortedViolationCounts) {
                    num++;
                    String skuName = entry.getKey();
                    Long count = entry.getValue();
// 修改后直接使用已包含SKU信息的key
                    content.append("\n").append(num).append(",商品：").append(entry.getKey()) // 这里已包含SKU信息
                            .append("\r\r").append(" 违规次数：").append(count).append("\r");
                    List<OrderInfo> infos = orderInfoMap.get(skuName);
                    if (infos != null) {
                        for (OrderInfo info : infos) {
                            content.append("\n 订单：").append(info.getOrderId()).append("\r 下单：").append(info.getOrderDate()).append("\r");
                        }
                    }
                }
                contents.add(content);
            }
            // 订单查询
            if (order.startsWith("搜索")) {
                order = order.replace("搜索", "");

                content = new StringBuilder();
                // 精准查询订单号+精准查询sku+模糊查询收件人+模糊查询地址
                content.append("精准查询订单号:\r");
                List<OrderRow> orderRowList = orderRowRepository.findByOrderId(Long.parseLong(order));
                if (!orderRowList.isEmpty()) {
                    OrderRow orderRow = orderRowList.get(0);
                    if (unionIds.contains(orderRow.getUnionId())) {
                        content.append(orderUtil.getFormattedOrderInfo(orderRow, orderRow.getValidCode()));
                    } else {
                        content.append("订单不属于你，无法查询\r");
                    }
                } else {
                    content.append("订单不存在\r");
                }
                contents.add(content);

                content = new StringBuilder();
                // 不统计已取消的订单
                content.append("精准查询sku，不统计已取消的订单:\r");
                int[] validCodes = {-1, 3};

                List<OrderRow> bySkuIdAndUnionId = orderRowRepository.findBySkuIdAndUnionIdIn(validCodes, Long.parseLong(order), unionIds);
                int size = bySkuIdAndUnionId.size();
                content.append("查询到").append(size).append("条订单\r");
                // 切割成20条20条返回前100条
                for (int i = 0; i < size; i += 20) {
                    List<OrderRow> subList = bySkuIdAndUnionId.subList(i, Math.min(i + 20, size));
                    content.append("第").append(i / 20 + 1).append("页:\r");
                    for (OrderRow orderRow : subList) {
                        content.append(orderUtil.getFormattedOrderInfo(orderRow, orderRow.getValidCode()));
                        contents.add(content);
                        content = new StringBuilder();
                    }
                }
                content = new StringBuilder();
                content.append("模糊查询收件人+模糊查询地址:\r");
                //List<OrderRow> orderRowList = orderRowRepository
                content.append("暂不支持");
                contents.add(content);


            }
            if (order.startsWith("SKU")) {
                content = new StringBuilder();
                order = order.replace("SKU", "");
                String[] split = order.split("\r\n");
                content.append("电脑端").append("\r\n");
                for (String s : split) {
                    content.append("https://item.jd.com/").append(s.trim()).append(".html").append("\r\n");
                }
                wxUtil.sendTextMessage(fromWxid, content.toString(), 1, fromWxid, false);
                content = new StringBuilder();
                content.append("手机端").append("\r\n");
                for (String s : split) {
                    content.append("https://item.m.jd.com/product/").append(s.trim()).append(".html").append("\r\n");
                }
                wxUtil.sendTextMessage(fromWxid, content.toString(), 1, fromWxid, false);
                content = new StringBuilder();
                contents.add(content);

            }
            // 转链
            if (order.startsWith("转链")) {
                content = new StringBuilder();
                order = order.replace("转链", "");
                String jsonString;
                try {
                    GoodsQueryResult goodsQueryResult = queryProductInfoByUJDUrl(order);
                    jsonString = JSON.toJSONString(goodsQueryResult);
                    content.append(jsonString);

                } catch (Exception e) {
                    content.append(e);
                    throw new RuntimeException(e);
                }

                contents.add(content);
            }
        } else {
            try {
                sendOrderToWxByOrderJD("菜单", fromWxid);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        if (!contents.isEmpty()) {
            for (StringBuilder stringBuilder : contents) {
                wxUtil.sendTextMessage(fromWxid, stringBuilder.toString(), 1, fromWxid, false);
            }
        }
    }

    /**
     * 接口描述：通过商品链接、领券链接、活动链接获取普通推广链接或优惠券二合一推广链接
     * jd.union.open.promotion.bysubunionid.get
     */
    String transfer(String url, String giftCouponKey) {

        JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_WZ, LPF_SECRET_KEY_WZ);

        UnionOpenPromotionBysubunionidGetRequest request = new UnionOpenPromotionBysubunionidGetRequest();
        PromotionCodeReq promotionCodeReq = new PromotionCodeReq();
        promotionCodeReq.setSceneId(1);
        promotionCodeReq.setMaterialId(url);
        if (giftCouponKey != null) {
            promotionCodeReq.setGiftCouponKey(giftCouponKey);
        }

        request.setPromotionCodeReq(promotionCodeReq);

        request.setVersion("1.0");
        //logger.info("transfer - request {}", JSON.toJSONString(request));
        UnionOpenPromotionBysubunionidGetResponse response;
        try {
            response = client.execute(request);
            //logger.info("transfer - response {}", JSON.toJSONString(response));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        /**
         * {
         *       "jd_union_open_promotion_bysubunionid_get_responce": {
         *             "getResult": {
         *                   "code": "200",
         *                   "data": {
         *                         "clickURL": "https://union-click.jd.com/jdc?e=XXXXXX p=XXXXXXXXXXX",
         *                         "weChatShortLink": "#小程序://京小街/****",
         *                         "jShortCommand": "短口令",
         *                         "shortURL": "https://u.jd.com/XXXXX",
         *                         "jCommand": "6.0复制整段话 http://JhT7V5wlKygHDK京口令内容#J6UFE5iMn***"
         *                   },
         *                   "message": "success"
         *             }
         *       }
         * }
         * */
        String result = "";
        if (Util.isNotEmpty(response)) {
            if (response.getCode().equals("0") && response.getGetResult().getCode() == 200) {
                result = response.getGetResult().getData().getShortURL();
            }
        } else {
            result = null;
        }

        return result;
    }


    /**
     * 消毒柜部分的业务逻辑
     */
    @Scheduled(fixedRate = 1000) // 每10分钟执行一次
    public void cleanUpTimeoutStates() {
        LocalDateTime now = LocalDateTime.now();
        redisTemplate.keys(INTERACTION_STATE_PREFIX + "*").forEach(key -> {
            String stateJson = redisTemplate.opsForValue().get(key);
            try {
                UserInteractionState state = objectMapper.readValue(stateJson, UserInteractionState.class);
                LocalDateTime lastInteractionTime = LocalDateTime.parse(state.getLastInteractionTime(), DATE_TIME_FORMATTER);
                if (ChronoUnit.MINUTES.between(lastInteractionTime, now) > TIMEOUT_MINUTES) {
                    String wxid = key.replace(INTERACTION_STATE_PREFIX, "");
                    wxUtil.sendTextMessage(wxid, TIMEOUT_MINUTES + " 分钟未操作，已退出会话", 1, wxid, false);
                    redisTemplate.delete(key);
                    logger.debug("Deleted timeout state for key: {}", key);
                }
            } catch (Exception e) {
                logger.error("Error parsing interaction state: {}", e.getMessage());
            }
        });
    }

    private void handleUserInteraction(String fromWxid, String message) {
        String key = INTERACTION_STATE_PREFIX + fromWxid;
        UserInteractionState state = loadOrCreateState(key);

        try {
            switch (state.getCurrentState()) {
                case INIT:
                    handleInitState(fromWxid, message, state);
                    break;

                case PRODUCT_PROMOTION:
                    handlePromotionState(fromWxid, message, state);
                    break;

                case GIFT_MONEY_FLOW:
                    handleGiftMoneyFlow(fromWxid, message, state);
                    break;

                case COMMENT_GENERATION:
                    handleCommentInteraction(fromWxid, message, state);
                    break;
                default:
                    resetState(fromWxid, state);
                    wxUtil.sendTextMessage(fromWxid, "流程异常，请重新开始", 1, fromWxid, false);
            }
        } catch (Exception e) {
            logger.error("流程处理异常 - 用户: {}, 状态: {}", fromWxid, state, e);
            resetState(fromWxid, state);
            wxUtil.sendTextMessage(fromWxid, "处理异常，请重新开始", 1, fromWxid, false);
        } finally {
            saveState(key, state);
        }

        userInteractionStates.put(key, state);
        logger.debug("Updated interaction state for user {}: {}", fromWxid, JSON.toJSONString(state));
    }

    private UserInteractionState loadOrCreateState(String key) {
        UserInteractionState state = loadState(key);
        if (state == null) {
            state = new UserInteractionState();
            logger.debug("创建新交互状态: {}", key);
        } else if (isStateExpired(state)) {
            redisTemplate.delete(key);
            state = new UserInteractionState();
            logger.debug("状态已过期，重置: {}", key);
        }
        return state;
    }

    private boolean isStateExpired(UserInteractionState state) {
        LocalDateTime lastTime = LocalDateTime.parse(state.getLastInteractionTime(), DATE_TIME_FORMATTER);
        return ChronoUnit.MINUTES.between(lastTime, LocalDateTime.now()) > TIMEOUT_MINUTES;
    }

    private void handleInitState(String wxid, String message, UserInteractionState state) {
        if ("转".equals(message)) {
            state.setCurrentState(UserInteractionState.ProcessState.PRODUCT_PROMOTION);
            state.setCurrentField("content—withOutPic");
            wxUtil.sendTextMessage(wxid, "请输入推广方案 \n " + "（指令: 转 不返回图文 \n 文案 带图文 ）：", 1, wxid, false);
            logger.info("进入转链流程 - 用户: {}", wxid);
        } else if ("文案".equals(message)) {
            state.setCurrentState(UserInteractionState.ProcessState.PRODUCT_PROMOTION);
            state.setCurrentField("content—withPic");
            wxUtil.sendTextMessage(wxid, "请输入推广方案 \n " + "（指令: 转 不返回图文 \n 文案 带图文 ）：", 1, wxid, false);
            logger.info("进入转链流程 - 用户: {}", wxid);
        }
    }

    private void handlePromotionState(String wxid, String message, UserInteractionState state) {
        if ("content—withOutPic".equals(state.getCurrentField())) {
            processContentInput(wxid, message, state, false);
        } else if ("content—withPic".equals(state.getCurrentField())) {
            processContentInput(wxid, message, state, true);

        } else if ("confirm".equals(state.getCurrentField())) {
            handleGiftMoneyConfirmation(wxid, message, state);
        }
    }

    private void handleGiftMoneyFlow(String wxid, String message, UserInteractionState state) {
        if (!state.validateStep(state.getCurrentStep())) {
            wxUtil.sendTextMessage(wxid, "流程顺序异常，请重新开始", 1, wxid, false);
            return;
        }

        switch (state.getCurrentStep()) {
            case STEP_AMOUNT:
                processAmountInput(wxid, message, state);
                break;

            case STEP_QUANTITY:
                processQuantityInput(wxid, message, state);
                break;

            default:
                state.setCurrentStep(STEP_AMOUNT);
                wxUtil.sendTextMessage(wxid, "[Packet] 请输入金额（1-50元）：", 1, wxid, false);
        }
    }

    private void processAmountInput(String wxid, String message, UserInteractionState state) {
        if (!isValidAmount(message)) {
            wxUtil.sendTextMessage(wxid, "金额格式错误，请输入1-50元", 1, wxid, false);
            return;
        }

        state.getCollectedFields().put("amount", message);
        state.setCurrentStep(STEP_QUANTITY);
        wxUtil.sendTextMessage(wxid, "请输入数量（1-100）：", 1, wxid, false);
    }

    private void processQuantityInput(String wxid, String message, UserInteractionState state) {
        if (!isValidQuantity(message)) {
            wxUtil.sendTextMessage(wxid, "数量格式错误，请输入1-100的整数", 1, wxid, false);
            return;
        }

        // 从缓存获取商品数据

        String productDataJson = cacheMap.get("productData" + wxid);

        String finalWenAn = cacheMap.get("finalWenAn" + wxid);

        if (productDataJson == null || finalWenAn == null) {
            logger.error("数据丢失 - productData: {}, finalWenAn: {}", productDataJson != null, finalWenAn != null);
            wxUtil.sendTextMessage(wxid, "数据丢失，请重新开始流程", 1, wxid, false);
            resetState(wxid, state);
            return;
        }

        try {
            // 解析商品数据
            /**
             *                 // 取出来的每一个String都是JSONObject
             *                 List<String> data = contentResult.get("data");
             *                 JSONArray jsonObjectArr = new JSONArray(data);
             *
             *
             *                 cacheMap.put("productData" + wxid, jsonObjectArr.toJSONString());*/
            List<String> productList = JSON.parseArray(productDataJson, String.class);
            double amount = Double.parseDouble(state.getCollectedFields().get("amount"));
            int quantity = Integer.parseInt(message);

            StringBuilder result = new StringBuilder();
            String updatedContent = finalWenAn;

            for (String productJSONString : productList) {
                // 序列化好了的
                JSONObject product = JSON.parseObject(productJSONString);
                String skuId = product.getString("materialUrl");
                String owner = product.getString("owner");
                String skuName = product.getString("skuName");
                String originalUrl = product.getString("url");

                String giftKey = createGiftCoupon(skuId, amount, quantity, owner, skuName);
                if (giftKey == null) {
                    result.append(" ").append(skuName).append(" 礼金创建失败\n");
                    continue;
                }

                String transferUrl = transfer(skuId, giftKey);
                if (transferUrl != null) {
                    updatedContent = updatedContent.replace(originalUrl, transferUrl);
                    result.append(" ").append(skuName).append(" 礼金创建成功\n");
                } else {
                    result.append(" ").append(skuName).append(" 转链失败\n");
                }
            }

            wxUtil.sendTextMessage(wxid, result.toString(), 1, wxid, false);
            wxUtil.sendTextMessage(wxid, updatedContent, 1, wxid, true);

        } catch (Exception e) {
            logger.error("礼金处理异常", e);
            wxUtil.sendTextMessage(wxid, "处理异常：" + e.getMessage(), 1, wxid, false);
        } finally {
            resetState(wxid, state);
            cacheMap.remove("productData" + wxid);
            cacheMap.remove("finalWenAn" + wxid);
        }
    }

    /**
     * 处理用户输入的推广方案内容
     *
     * @param wxid    用户微信ID
     * @param message 用户输入的方案内容
     * @param state   当前交互状态
     * @param b
     */
    private void processContentInput(String wxid, String message, UserInteractionState state, boolean withPic) {
        try {
            // 1. 清除旧缓存
            cacheMap.remove("productData" + wxid);
            cacheMap.remove("finalWenAn" + wxid);

            // 2. 生成推广内容
            HashMap<String, List<String>> contentResult = generatePromotionContent(message, false);

            if (withPic) {
                // 3. 发送文本内容
                for (String text : contentResult.get("text")) {
                    wxUtil.sendTextMessage(wxid, text, 1, wxid, true);
                }
                // 4. 发送图片（如果有）
                List<String> images = contentResult.get("images");
                if (images != null) {
                    for (String imageUrl : images) {
                        if (imageUrl != null) {
                            wxUtil.sendImageMessage(wxid, imageUrl);
                        }
                    }
                }
            } else {

                // 3. 发送文本内容
                for (String text : contentResult.get("text")) {
                    if (text.contains("链接类型")) {
                        wxUtil.sendTextMessage(wxid, text, 1, wxid, true);
                    }
                }
            }

            // 5. 缓存商品数据
            if (!contentResult.get("data").isEmpty()) {
                // 取出来的每一个String都是JSONObject
                List<String> data = contentResult.get("data");
                JSONArray jsonObjectArr = new JSONArray(data);


                cacheMap.put("productData" + wxid, jsonObjectArr.toJSONString());
                cacheMap.put("finalWenAn" + wxid, contentResult.get("finalWenAn").get(0));

                state.setCurrentField("confirm");
                wxUtil.sendTextMessage(wxid, "检测到" + jsonObjectArr.size() + "个商品\n" + "是否需要开通礼金？\n回复 1 - 是\n回复 2 - 否", 1, wxid, false);
            } else {
                wxUtil.sendTextMessage(wxid, "未获取到商品数据，请检查链接格式", 1, wxid, false);
                state.reset();
            }
        } catch (Exception e) {
            logger.error("处理推广内容异常 - 用户: {}", wxid, e);
            wxUtil.sendTextMessage(wxid, "处理内容时发生异常，请重试", 1, wxid, false);
            state.reset();
        }
    }

    /**
     * 处理用户对礼金开通的确认
     *
     * @param wxid    用户微信ID
     * @param message 用户回复（1或2）
     * @param state   当前交互状态
     */
    private void handleGiftMoneyConfirmation(String wxid, String message, UserInteractionState state) {
        try {
            String cachedData = cacheMap.get("productData" + wxid);
            JSONArray jsonObjectArr = JSON.parseArray(cachedData);

            if ("1".equals(message)) {
                // 用户选择开通礼金
                state.setCurrentState(UserInteractionState.ProcessState.GIFT_MONEY_FLOW);
                state.setCurrentStep(STEP_AMOUNT);
                state.getCollectedFields().clear();
                wxUtil.sendTextMessage(wxid, "当前选择" + jsonObjectArr.size() + "个商品\n" + "请输入开通金额（1-50元，支持小数点后两位）：\n" + "示例：20.50", 1, wxid, false);
            } else if ("2".equals(message)) {
                // 用户选择不开通礼金
                if (cachedData != null) {
                    try {
                        JSONArray dataArray = JSON.parseArray(cachedData); // 支持多个商品
                        String finalWenAn = cacheMap.get("finalWenAn" + wxid);
                        if (finalWenAn == null) {
                            wxUtil.sendTextMessage(wxid, "文案内容为空，请检查缓存数据", 1, wxid, true);
                            return;
                        }

                        StringBuilder allTransferUrls = new StringBuilder();
                        for (Object obj : dataArray) {
                            JSONObject productInfo = (JSONObject) obj;
                            String skuUrl = productInfo.getString("materialUrl");
                            String originalUrl = productInfo.getString("url");

                            String transferUrl = transfer(skuUrl, null);
                            if (transferUrl != null) {
                                finalWenAn = finalWenAn.replace(originalUrl, transferUrl);
                                allTransferUrls.append(transferUrl).append("\n");
                            }
                        }

                        wxUtil.sendTextMessage(wxid, "不开礼金，只转链的方案：\n", 1, wxid, false);
                        wxUtil.sendTextMessage(wxid, finalWenAn, 1, wxid, true);

                        // 清理缓存和状态
                        resetState(wxid, state);
                        cacheMap.remove("productData" + wxid);
                        cacheMap.remove("finalWenAn" + wxid);
                        wxUtil.sendTextMessage(wxid, "已清除商品信息缓存，可输入新的文案", 1, wxid, false);

                    } catch (Exception e) {
                        logger.error("处理不开礼金转链失败 - 用户: {}", wxid, e);
                        wxUtil.sendTextMessage(wxid, "处理失败：" + e.getMessage(), 1, wxid, false);
                        resetState(wxid, state);
                    }
                }

            } else {
                wxUtil.sendTextMessage(wxid, "处理请求时发生异常，请重试", 1, wxid, false);
                state.reset();
            }
        } catch (Exception e) {
            logger.error("处理礼金确认异常 - 用户: {}", wxid, e);
            wxUtil.sendTextMessage(wxid, "处理请求时发生异常，请重试", 1, wxid, false);
            state.reset();
        }
    }

    private void resetState(String wxid, UserInteractionState state) {
        state.reset();
        saveState(INTERACTION_STATE_PREFIX + wxid, state);
    }

    public static List<String> extractPrices(String text) {
        List<String> prices = new ArrayList<>();
        if (text.contains("🔥")) {
            // 处理包含 🔥 的文本
            Pattern pattern = Pattern.compile("\\d+(\\.\\d+)?💰");
            Matcher matcher = pattern.matcher(text);
            while (matcher.find()) {
                String priceStr = matcher.group().replace("💰", "");
                prices.add(priceStr);
            }
        } else {
            // 处理不包含 🔥 的文本
            Pattern pattern = Pattern.compile("💰(\\d+)");
            Matcher matcher = pattern.matcher(text);
            while (matcher.find()) {
                prices.add(matcher.group(1));
            }
        }
        return prices;
    }

    /**
     * 生成转链和方案的方法
     *
     * @param message 方案内容，包含商品链接
     * @return 处理后的方案，附带商品信息
     */
    public synchronized HashMap<String, List<String>> generatePromotionContent(String message, Boolean isCj) {
        HashMap<String, List<String>> finallyMessage = new HashMap<>();
        List<String> textList = new ArrayList<>();
        List<String> imagesList = new ArrayList<>();
        List<String> dataList = new ArrayList<>();
        // 最终的方案
        List<String> finalWenAn = new ArrayList<>();
        // 提取方案中的所有 u.jd.com 链接
        List<String> urlList = new ArrayList<>();
        List<String> priceList = new ArrayList<>();

        // 提取方案中的所有 u.jd.com 链接
        List<String> urls = extractUJDUrls(message);
        if (urls.isEmpty()) {
            textList.add("方案中未找到有效的商品链接，请检查格式是否正确。");
            finallyMessage.put("text", textList);
            return finallyMessage;
        }

        /**
         * {
         *     "jd_union_open_goods_query_responce": {
         *         "code": "0",
         *         "queryResult": {
         *             "code": 200,
         *             "data": [
         *                 {
         *                     "brandCode": "16407",
         *                     "brandName": "松下（Panasonic）",
         *                     "categoryInfo": {
         *                         "cid1": 737,
         *                         "cid1Name": "家用电器",
         *                         "cid2": 794,
         *                         "cid2Name": "大 家 电",
         *                         "cid3": 880,
         *                         "cid3Name": "洗衣机"
         *                     },
         *                     "comments": 10000,
         *                     "commissionInfo": {
         *                         "commission": 599.95,
         *                         "commissionShare": 5,
         *                         "couponCommission": 592.95,
         *                         "endTime": 1743609599000,
         *                         "isLock": 1,
         *                         "plusCommissionShare": 5,
         *                         "startTime": 1742486400000
         *                     },
         *                     "couponInfo": {
         *                         "couponList": [
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 100,
         *                                 "getEndTime": 1746028799000,
         *                                 "getStartTime": 1743436800000,
         *                                 "isBest": 1,
         *                                 "isInputCoupon": 1,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoeVJzBK6Q6mfry4nz4ylRYHXsp_NnipDSrReNwGZGTxXhj94SGi9SkzR_7xaWEXLpO2boqow",
         *                                 "platformType": 0,
         *                                 "quota": 5000,
         *                                 "useEndTime": 1746028799000,
         *                                 "useStartTime": 1743436800000
         *                             },
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 50,
         *                                 "getEndTime": 1746028799000,
         *                                 "getStartTime": 1743436800000,
         *                                 "hotValue": 0,
         *                                 "isBest": 0,
         *                                 "isInputCoupon": 0,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoervD9YaNNXlsj6OBbZoWSFI1sZXw31PSjK04AH6tFP_Iu0YJlePWBT6sZfNvp14W0QK2K6A",
         *                                 "platformType": 0,
         *                                 "quota": 5000,
         *                                 "useEndTime": 1746028799000,
         *                                 "useStartTime": 1743436800000
         *                             },
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 40,
         *                                 "getEndTime": 1746028799000,
         *                                 "getStartTime": 1743436800000,
         *                                 "hotValue": 0,
         *                                 "isBest": 0,
         *                                 "isInputCoupon": 0,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoeqQdmhZbv1TiAn0QqI5gnT4g_zAgV5887llN8j6TatV-zpDfReipMr-hKkwQasE9NNUV2uQ",
         *                                 "platformType": 0,
         *                                 "quota": 500,
         *                                 "useEndTime": 1746028799000,
         *                                 "useStartTime": 1743436800000
         *                             },
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 20,
         *                                 "getEndTime": 1746028799000,
         *                                 "getStartTime": 1743436800000,
         *                                 "hotValue": 0,
         *                                 "isBest": 0,
         *                                 "isInputCoupon": 0,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoepukjRCuLpbwceODRbBw5HpNLRTVe5Olp99d34Izdo0s9lDtTIdyYZ-uJRCEXnc5N3OZ5LA",
         *                                 "platformType": 0,
         *                                 "quota": 2000,
         *                                 "useEndTime": 1746028799000,
         *                                 "useStartTime": 1743436800000
         *                             },
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 10,
         *                                 "getEndTime": 1746028799000,
         *                                 "getStartTime": 1743436800000,
         *                                 "hotValue": 0,
         *                                 "isBest": 0,
         *                                 "isInputCoupon": 0,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoeKIIbuvk-VsfJj_m1o3PRHqRaEBIbXHwooEMMt3z44T3cNQTkQsS8TjGnEeIz1obKp_t_mQ",
         *                                 "platformType": 0,
         *                                 "quota": 1000,
         *                                 "useEndTime": 1746028799000,
         *                                 "useStartTime": 1743436800000
         *                             }
         *                         ]
         *                     },
         *                     "deliveryType": 1,
         *                     "eliteType": [],
         *                     "forbidTypes": [
         *                         0
         *                     ],
         *                     "goodCommentsShare": 99,
         *                     "imageInfo": {
         *                         "imageList": [
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/273873/17/14072/113544/67ebd215Feef3f56b/fc5156bf59a25ba3.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/273802/16/14273/84419/67ebd224F72dbcc8d/8ffe6f99aeeeb8fd.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/278931/40/12819/81341/67ea0227F41ffc604/ab1c6727e5d4f224.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/276989/12/13440/79310/67ea0226F68c2ed40/8acdeda05aa3596b.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/284503/25/12384/59498/67ea0225F8be60c83/b29ea34abc64346e.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/284667/29/12481/56118/67ea0225F97d9c729/f4c81d77064957bd.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/270959/35/13852/50552/67ea0224F911b8f00/248f9a7751549db7.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/274981/3/13326/48019/67ea0224Fe64bca69/b062218fc8db9b29.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/283691/1/12478/82267/67ea0223Fd4ecb0f5/2c32de327d8aa440.jpg"
         *                             },
         *                             {
         *                                 "url": "https://img14.360buyimg.com/pop/jfs/t1/281457/31/12476/94335/67ea0222Fde76593a/cdddcd59b0b20c9a.jpg"
         *                             }
         *                         ]
         *                     },
         *                     "inOrderComm30Days": 633170.8,
         *                     "inOrderCount30Days": 3000,
         *                     "inOrderCount30DaysSku": 100,
         *                     "isHot": 1,
         *                     "isJdSale": 1,
         *                     "isOversea": 0,
         *                     "itemId": "BsrqLq5CfIziE7BSl3ItPp8q_3DFaNVYJqfkRRLc7HR",
         *                     "jxFlags": [],
         *                     "materialUrl": "jingfen.jd.com/detail/BsrqLq5CfIziE7BSl3ItPp8q_3DFaNVYJqfkRRLc7HR.html",
         *                     "oriItemId": "BMrqLq5CfIz9X04KC3ItPp8q_3DFaNVYJqfkRRLc7HR",
         *                     "owner": "g",
         *                     "pinGouInfo": {},
         *                     "pingGouInfo": {},
         *                     "priceInfo": {
         *                         "lowestCouponPrice": 11899,
         *                         "lowestPrice": 11999,
         *                         "lowestPriceType": 1,
         *                         "price": 11999
         *                     },
         *                     "purchasePriceInfo": {
         *                         "basisPriceType": 1,
         *                         "code": 200,
         *                         "couponList": [
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 100,
         *                                 "isBest": 0,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoeVJzBK6Q6mfry4nz4ylRYHXsp_NnipDSrReNwGZGTxXhj94SGi9SkzR_7xaWEXLpO2boqow",
         *                                 "platformType": 0,
         *                                 "quota": 5000
         *                             },
         *                             {
         *                                 "bindType": 1,
         *                                 "couponStatus": 0,
         *                                 "couponStyle": 0,
         *                                 "discount": 40,
         *                                 "isBest": 0,
         *                                 "link": "https://coupon.m.jd.com/coupons/show.action?linkKey=AAROH_xIpeffAs_-naABEFoeqQdmhZbv1TiAn0QqI5gnT4g_zAgV5887llN8j6TatV-zpDfReipMr-hKkwQasE9NNUV2uQ",
         *                                 "platformType": 0,
         *                                 "quota": 500
         *                             }
         *                         ],
         *                         "message": "success",
         *                         "purchaseNum": 1,
         *                         "purchasePrice": 11859,
         *                         "thresholdPrice": 11999
         *                     },
         *                     "shopInfo": {
         *                         "shopId": 1000001741,
         *                         "shopLabel": "0",
         *                         "shopLevel": 4.9,
         *                         "shopName": "松下洗衣机京东自营旗舰店"
         *                     },
         *                     "skuName": "松下（Panasonic）白月光4.0Ultra 洗烘套装 10kg滚筒洗衣机+变频热泵烘干机 除毛升级2.0 水氧SPA护理 8532N+8532NR",
         *                     "skuTagList": [
         *                         {
         *                             "index": 1,
         *                             "name": "自营",
         *                             "type": 11
         *                         },
         *                         {
         *                             "index": 1,
         *                             "name": "plus",
         *                             "type": 6
         *                         },
         *                         {
         *                             "index": 3,
         *                             "name": "7天无理由退货",
         *                             "type": 12
         *                         }
         *                     ],
         *                     "spuid": 100137629936,
         *                     "videoInfo": {}
         *                 }
         *             ],
         *             "message": "success",
         *             "requestId": "o_0b721560_m8yp5pqj_88394507",
         *             "totalCount": 1
         *         }
         *     }
         * }
         *
         * */

        // 如果需要图片和SKU名称，则代表要把图片下载发过去，还有对应的skuName
        StringBuilder couponInfo = null;
        ArrayList<HashMap<String, String>> resultList = new ArrayList<>();

        String format = null;
        DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
        if (!isCj) {
            try {
                priceList = extractPrices(message);
                finallyMessage.put("priceList", priceList);
            } catch (Exception ignored) {
            }
        }
        for (String url : urls) {
            try {
                // 重置。不然会一直追加文本内容
                couponInfo = new StringBuilder();
                // 新建格式好日期
                format = dateFormat.format(new Date());
                // 查询商品信息
                GoodsQueryResult productInfo = queryProductInfoByUJDUrl(url);
                if (productInfo == null || productInfo.getCode() != 200) {
                    couponInfo.append("链接查询失败：").append(url).append("\n");
                    continue;
                }
                long totalCount = productInfo.getTotalCount();

                couponInfo.append("  ").append(url).append("\n");
                if (totalCount == 0) {
                    couponInfo.append("链接类型：优惠券\n\n");
                } else {
                    urlList.add(url);
                    couponInfo.append("链接类型：商品\n\n");
                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(productInfo.getData()[0]));
                    jsonObject.put("url", url);
                    dataList.add(jsonObject.toString());

                    HashMap<String, String> itemMap = new HashMap<>();
                    itemMap.put("url", url);
                    itemMap.put("materialUrl", productInfo.getData()[0].getMaterialUrl());
                    itemMap.put("oriItemId", productInfo.getData()[0].getOriItemId());
                    itemMap.put("owner", productInfo.getData()[0].getOwner());
                    itemMap.put("shopId", String.valueOf(productInfo.getData()[0].getShopInfo().getShopId()));
                    itemMap.put("shopName", productInfo.getData()[0].getShopInfo().getShopName());
                    itemMap.put("skuName", productInfo.getData()[0].getSkuName());
                    String replaceAll = itemMap.get("skuName").replaceAll("以旧|政府|换新|领取|国家|补贴|15%|20%|国补|立减|【|】", "");
                    itemMap.put("spuid", String.valueOf(productInfo.getData()[0].getSpuid()));
                    itemMap.put("commission", String.valueOf(productInfo.getData()[0].getCommissionInfo().getCommission()));
                    itemMap.put("commissionShare", String.valueOf(productInfo.getData()[0].getCommissionInfo().getCommissionShare()));
                    //for (HashMap.Entry<String, String> entry : itemMap.entrySet()) {
                    //couponInfo.append("  ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
                    //}
                    couponInfo.append("店铺：  ").append(itemMap.get("shopName")).append("\n").append("标题：  ").append(replaceAll).append("\n").append("自营 POP： ").append(itemMap.get("owner").equals("g") ? " 自营 " : " POP ").append("\n").append("佣金比例：  ").append(itemMap.get("commissionShare")).append("\n").append("佣金：  ").append(itemMap.get("commission")).append("\n");


                    //StringBuilder images = new StringBuilder();
                    if (productInfo.getData()[0].getImageInfo() != null) {
                        //images.append("  ").append("图片信息：\n");
                        //int index = 1;
                        if (!isCj) {
                            for (UrlInfo image : productInfo.getData()[0].getImageInfo().getImageList()) {
                                //images.append("图片 ").append(index++).append("\n").append(image.getUrl()).append("\n");
                                imagesList.add(image.getUrl());
                            }
                        }
                    }
                    //textList.add(String.valueOf(images));
                    resultList.add(itemMap);
                    String title = "";

                    if (!isCj) {
                        try {
                            if (!message.equals(url)) {
                                String[] lines = message.split("\\r?\\n");
                                if (lines.length > 0) {
                                    title = lines[0];
                                    // 有的换行了
                                    if (lines[1].length() > 3 && !lines[1].contains("u.jd")) {
                                        title = title + lines[1];
                                    }
                                    logger.info("文案首行 {}", title);
                                    title = title.replaceAll("@|所有人", "");
                                }
                            }

                        } catch (Exception e) {
                            logger.error("文案首行异常", e);
                        }



                        /*直接生成闲鱼的商品文案*/
                        StringBuilder sb1 = new StringBuilder();

                        sb1.append("(教你买) ").append(title).append(replaceAll).append("\n").append(WENAN_FANAN_LQD.replaceAll("更新", format + "更新"));
                        //textList.add("闲鱼方案的文案：\n");
                        textList.add(String.valueOf(sb1));
                        StringBuilder sb2 = new StringBuilder();
                        sb2.append("(一键代下) ").append(title).append(replaceAll).append("\n").append(WENAN_ZCXS);
                        //textList.add("闲鱼正常销售：\n");
                        textList.add(String.valueOf(sb2));
                        StringBuilder sb3 = new StringBuilder();
                        sb3.append("(教你买) ").append(title).append(replaceAll).append("\n").append(WENAN_FANAN_HG.replaceAll("更新", format + "更新"));
                        textList.add(String.valueOf(sb3));
                    }

                }
                textList.add(String.valueOf(couponInfo));
                finallyMessage.put("data", dataList);
                finallyMessage.put("urlList", urlList);


            } catch (Exception e) {
                logger.error("处理商品链接时发生异常：{}", url, e);
                couponInfo.append(" 处理商品链接时发生异常：").append(url).append("\n");
                textList.add(String.valueOf(couponInfo));
                finallyMessage.put("text", textList);
            }
        }
        /**
         * 因为在这里转链返回，没有什么意义，后面走转链不转链，会重新发方案
         * */
        StringBuilder wenan;

        wenan = new StringBuilder().append(format).append(FANAN_COMMON).append(message);
        finalWenAn.add(String.valueOf(wenan));


        finallyMessage.put("text", textList);
        finallyMessage.put("images", imagesList);
        finallyMessage.put("finalWenAn", finalWenAn);
        return finallyMessage;

    }


    /**
     * 提取方案中的所有 u.jd.com 链接
     *
     * @param message 方案内容
     * @return 包含所有 u.jd.com 链接的列表
     */
    private List<String> extractUJDUrls(String message) {
        List<String> urls = new ArrayList<>();
        Pattern pattern = Pattern.compile("https://u\\.jd\\.com/\\S+");
        Matcher matcher = pattern.matcher(message);

        while (matcher.find()) {
            urls.add(matcher.group());
        }

        return urls;
    }

    /**
     * 通过这个可以将u.jd.*** 查询到对应的商品信息 和 商品图片，甚至可以查询到是不是自营的商品
     */
    public UnionOpenGoodsQueryResponse getUnionOpenGoodsQueryRequest(String uJDUrl) throws Exception {
        JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_WZ, LPF_SECRET_KEY_WZ);

        UnionOpenGoodsQueryRequest request = new UnionOpenGoodsQueryRequest();
        GoodsReq goodsReq = new GoodsReq();
        //goodsReq.setSkuIds(List.of(Long.parseLong(skuId)).toArray(new Long[0])); // 传入skuId集合
        /**
         * 查询域集合，不填写则查询全部，目目前支持：categoryInfo（类目信息）,imageInfo（图片信息）,
         * baseBigFieldInfo（基础大字段信息）,bookBigFieldInfo（图书大字段信息）,
         * videoBigFieldInfo（影音大字段信息）,detailImages（商详图）
         * */
        //goodsReq.setFields(new String[]{"categoryInfo", "imageInfo", "baseBigFieldInfo"}); // 设置需要查询的字段
        goodsReq.setKeyword(uJDUrl);
        goodsReq.setSceneId(1);
        request.setGoodsReqDTO(goodsReq);
        request.setVersion("1.0");
        request.setSignmethod("md5");
        // 时间戳，格式为yyyy-MM-dd HH:mm:ss，时区为GMT+8。API服务端允许客户端请求最大时间误差为10分钟
        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        request.setTimestamp(simpleDateFormat.format(date));
        //logger.debug("getUnionOpenGoodsQueryRequest 查询商品信息请求：{}", JSON.toJSONString(request));

        UnionOpenGoodsQueryResponse execute = client.execute(request);
        //logger.debug("getUnionOpenGoodsQueryRequest 查询商品信息响应：{}", JSON.toJSONString(execute));
        return execute;
    }

    public GoodsQueryResult queryProductInfoByUJDUrl(String uJDUrl) throws Exception {
        UnionOpenGoodsQueryResponse response = getUnionOpenGoodsQueryRequest(uJDUrl);
        if (response == null || response.getQueryResult() == null) {
            return null;
        }
        GoodsQueryResult queryResult = response.getQueryResult();
        if (queryResult.getCode() != 200) {
            return null;
        }
        return queryResult;
    }


    // 新增礼金创建方法
    public String createGiftCoupon(String skuId, double amount, int quantity, String owner, String skuName) throws Exception {
        logger.debug("准备创建礼金：SKU={}, 金额={}元，数量={}, Owner={}", skuId, amount, quantity, owner);

        // 参数校验
        if (skuId == null || amount <= 0 || quantity <= 0) {
            logger.error("礼金创建失败：参数错误，SKU={}, 金额={}元，数量={}", skuId, amount, quantity);
            return null;
        }

        // 设置默认值
        owner = (owner != null) ? owner : "g";

        JdClient client = new DefaultJdClient(SERVER_URL, ACCESS_TOKEN, LPF_APP_KEY_WZ, LPF_SECRET_KEY_WZ);

        UnionOpenCouponGiftGetRequest request = new UnionOpenCouponGiftGetRequest();
        CreateGiftCouponReq couponReq = new CreateGiftCouponReq();
        couponReq.setSkuMaterialId(skuId); // 使用SKU或链接
        couponReq.setDiscount(amount);
        couponReq.setAmount(quantity);

        // 自营的只能设置一天，pop的只能设置7天，默认为自营
        String startTime;
        String endTime;
        if ("pop".equals(owner)) {
            startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
            endTime = LocalDateTime.now().plusDays(6).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
            couponReq.setEffectiveDays(7);

        } else {
            startTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
            endTime = LocalDateTime.now().plusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH"));
            couponReq.setEffectiveDays(1);

        }

        couponReq.setReceiveStartTime(startTime);
        couponReq.setReceiveEndTime(endTime);
        couponReq.setIsSpu(1);
        couponReq.setExpireType(1);
        couponReq.setShare(-1);
        if (skuName.length() >= 25) {
            skuName = skuName.substring(0, 25);
        }
        // 新建格式日期
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        skuName = skuName + " " + dateFormat.format(new Date());

        couponReq.setCouponTitle(skuName);
        couponReq.setContentMatch(1);

        request.setCouponReq(couponReq);
        request.setVersion("1.0");

        logger.debug("请求参数：{}", JSON.toJSONString(request));

        UnionOpenCouponGiftGetResponse response = client.execute(request);
        logger.debug("API响应：{}", JSON.toJSONString(response));

        if ("0".equals(response.getCode()) && response.getGetResult().getCode() == 200) {
            String giftKey = response.getGetResult().getData().getGiftCouponKey();
            logger.debug("礼金创建成功：批次ID={}, 返回数据：{}", giftKey, response.getGetResult().getData());
            return giftKey;
        } else {
            logger.error("礼金创建失败：错误码={}, 错误信息={}", response.getCode(), response.getMsg());
        }
        return null;
    }


    boolean isValidAmount(String input) {
        // 新增：直接处理 null 或空字符串
        if (input == null || input.trim().isEmpty()) {
            return false;
        }
        try {
            double amount = Double.parseDouble(input);
            return amount >= 1 && amount <= 50;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    private boolean isValidQuantity(String input) {
        if (input == null || input.trim().isEmpty()) {
            logger.error("数量为空或无效: {}", input);
            return false;
        }
        try {
            int quantity = Integer.parseInt(input);
            if (quantity < 1 || quantity > 100) {
                logger.error("数量超出范围: {}", quantity);
                return false;
            }
            return true;
        } catch (NumberFormatException e) {
            logger.error("数量格式错误: {}", input, e);
            return false;
        }
    }

    // 将状态存储迁移到Redis
    public void saveState(String wxid, UserInteractionState state) {
        String key = INTERACTION_STATE_PREFIX + wxid;
        redisTemplate.opsForValue().set(key, JSON.toJSONString(state), 10, TimeUnit.MINUTES);
    }

    public UserInteractionState loadState(String wxid) {
        String json = redisTemplate.opsForValue().get(INTERACTION_STATE_PREFIX + wxid);
        return JSON.parseObject(json, UserInteractionState.class);
    }

    public void sendOrderToWxByOrderD(String order, String fromWxid) {

        if (order == null || order.trim().isEmpty()) {
            wxUtil.sendTextMessage(fromWxid, "输入格式为：\n 单\n分销标记\n型号\n转链链接\n数量\n地址", 1, fromWxid, false);
            return;
        }
        String[] split = order.split("\n");
        if (split.length != 6) {
            wxUtil.sendTextMessage(fromWxid, "输入格式为：\n 单\n分销标记\n型号\n转链链接\n数量\n地址", 1, fromWxid, false);
            return;
        }
        String remark = "";
        if (!split[0].trim().replace("单", "").isEmpty()) {
            remark = split[0].trim().replace("{单}", "").replace("\n", "");
        }
        // 今天的日期
        String today = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd "));
        String redisKey = "order_count:" + today;
        Integer count;

        try {
            // 从 Redis 获取当前日期的订单计数器
            String s = redisTemplate.opsForValue().get(redisKey);
            count = s != null ? Integer.parseInt(s) : 0; // 初始为 0，后面再 ++

            logger.info("sendOrderToWxByOrderD.count beforeFor {}", count);

            Integer num = 1;
            try {
                num = Integer.valueOf(split[4].trim());
            } catch (NumberFormatException e) {
                logger.error("sendOrderToWxByOrderD 订单数量格式错误，请输入正确的数字", e);
                wxUtil.sendTextMessage(fromWxid, "订单数量格式错误，请输入正确的数字", 1, fromWxid, false);
                return;
            }

            // 先一次性增加计数器，并设置到 Redis（原子性操作）
            int startCount = count + 1;
            int endCount = count + num;

            // 更新 Redis 的计数器为最终值
            redisTemplate.opsForValue().set(redisKey, String.valueOf(endCount), 1, TimeUnit.DAYS);

            // 批量生成订单号并发送
            for (int i = 0; i < num; i++) {
                int currentCount = startCount + i;
                String orderID = today + String.format("%03d", currentCount); // 格式化为三位数
                // 每次使用原始模板进行替换，避免污染
                String currentTemp = WENAN_D.replace("{单的备注}", remark).replace("{单号}", orderID).replace("{分销标记}", split[1]).replace("{链接}", split[3]).replace("{地址}", split[5]).replace("{型号}", split[2]).replaceAll("[|]", "");
                // 发送订单信息到微信
                wxUtil.sendTextMessage(fromWxid, currentTemp, 1, fromWxid, true);
            }

        } catch (Exception e) {
            logger.error("生成订单号时发生异常 - 用户: {}, 日期: {}", fromWxid, today, e);
            wxUtil.sendTextMessage(fromWxid, "生成订单号时发生异常，请重试", 1, fromWxid, false);
        }

    }

    public void sendOrderToWxByOrderP(String order, String fromWxid) {
        logger.info("sendOrderToWxByOrderP.order {}", order);
        // 检查是否命中“评”指令
        UserInteractionState state = null;
        if ("".equals(order)) {
            // 初始化用户交互状态
            String key = INTERACTION_STATE_PREFIX + fromWxid;
            state = loadOrCreateState(key);
            logger.info("loadOrCreateState - 用户: {}, 状态: {}", fromWxid, state);

            try {
                // 设置当前状态为生成评论流程
                state.setCurrentState(UserInteractionState.ProcessState.COMMENT_GENERATION);
                state.setCurrentField("commentTypeSelection");
                // 提示用户选择评论类型
                getProductTypeMap();
                if (productTypeMap == null) {
                    wxUtil.sendTextMessage(fromWxid, "productTypeMap 为空 ", 1, fromWxid, false);
                    return;
                }
                StringBuilder productTypeStr = new StringBuilder();
                for (Map.Entry<String, String> entry : productTypeMap.entrySet()) {
                    String k = entry.getKey();
                    //String value = entry.getValue();
                    productTypeStr.append("  ").append(k) .append("\n");
                }
                wxUtil.sendTextMessage(fromWxid, "请选择要生成的评论类型：\n " + productTypeStr, 1, fromWxid, false);
                logger.info("进入生成评论流程 - 用户: {}", fromWxid);

            } catch (Exception e) {
                logger.error("生成评论流程初始化异常 - 用户: {}, 状态: {}", fromWxid, state, e);
                wxUtil.sendTextMessage(fromWxid, "处理异常，请重新开始", 1, fromWxid, false);
                resetState(fromWxid, state);
            } finally {
                saveState(key, state);
            }
        } else {
            // 如果未命中“评”指令，检查是否在生成评论流程中
            handleCommentInteraction(fromWxid, order, state);
        }
    }

    //getProductTypeMap 从redis中获取PRODUCT_TYPE_MAP_PREFIX
    public void getProductTypeMap() {
        Map<Object, Object> rawMap = redisTemplate.opsForHash().entries(PRODUCT_TYPE_MAP_PREFIX);

        if (rawMap != null && !rawMap.isEmpty()) {
            productTypeMap.clear();
            for (Map.Entry<Object, Object> entry : rawMap.entrySet()) {
                productTypeMap.put(entry.getKey().toString(), entry.getValue().toString());
            }
        } else {
            logger.warn("Redis 中未找到键为 {} 的 Hash 数据", PRODUCT_TYPE_MAP_PREFIX);
        }
    }


    /**
     * 处理生成评论流程中的用户交互
     */
    private void handleCommentInteraction(String fromWxid, String message, UserInteractionState state) {
        String key = INTERACTION_STATE_PREFIX + fromWxid;
        logger.info("handleCommentInteraction 处理生成评论流程中的用户交互 - 用户: {}, 状态: {},message: {}", fromWxid, state, message);
        try {
            // 检查当前状态是否为生成评论流程
            if (!"commentTypeSelection".equals(state.getCurrentField())) {
                return;
            }
            getProductTypeMap();
            if (productTypeMap == null) {
                wxUtil.sendTextMessage(fromWxid, "productTypeMap 为空 ", 1, fromWxid, false);
                return;
            }
            if (productTypeMap.containsKey(message)) {
                generateComment(fromWxid, message);
            } else {
                wxUtil.sendTextMessage(fromWxid, "无效的选择", 1, fromWxid, false);
            }

        } catch (Exception e) {
            logger.error("生成评论流程处理异常 - 用户: {}, 状态: {}", fromWxid, state, e);
            wxUtil.sendTextMessage(fromWxid, "处理异常，请重新开始", 1, fromWxid, false);
            resetState(fromWxid, state);
        } finally {
            saveState(key, state);
        }
    }


    /**
     * 生成评论内容
     */
    private void generateComment(String fromWxid, String productType) {
        wxUtil.sendTextMessage(fromWxid, "已接收到评论生成指令，等候过程请勿重复输入", 1, fromWxid, false);

        // 获取产品ID
        getProductTypeMap();
        if (productTypeMap == null) {
            wxUtil.sendTextMessage(fromWxid, "productTypeMap 为空 ", 1, fromWxid, false);
            return;
        }
        String product_id = productTypeMap.get(productType);
        if (product_id == null || product_id.isEmpty()) {
            wxUtil.sendTextMessage(fromWxid, "缺失对应的SKUID", 1, fromWxid, false);
            return;
        }

        // 从数据库获取可用评论
        List<Comment> availableComments = commentRepository.findByProductIdAndIsUseNotAndPictureUrlsIsNotNull(product_id, 1);

        Comment commentToUse = null;

        if (!availableComments.isEmpty()) {
            // 随机选取一个未使用的评论
            Collections.shuffle(availableComments);
            commentToUse = availableComments.get(0);
        } else {
            wxUtil.sendTextMessage(fromWxid, "没有本地评论，调用外部接口抓取", 1, fromWxid, false);
            // 没有本地评论，调用外部接口抓取
            try {
                String fetchUrl = "http://192.168.8.6:5000/fetch_comments?product_id=" + product_id;
                // 用hutool发起post请求
                HttpResponse response = HttpRequest.post(fetchUrl).timeout(60000).execute();

                logger.info("fetchUrl: {}", fetchUrl);
// code = 200 表示成功，-200 表示失败
                if (response.getStatus() == 200) {
                    wxUtil.sendTextMessage(fromWxid, "已获取新的评论，请稍等", 1, fromWxid, false);
                    // ✅ 关键修改：重新从数据库中查询，而不是使用内存中的 fetchedComments
                    availableComments = commentRepository.findByProductIdAndIsUseNotAndPictureUrlsIsNotNull(product_id, 1);
                    if (!availableComments.isEmpty()) {
                        Collections.shuffle(availableComments);
                        commentToUse = availableComments.get(0);
                    }
                } else if (response.getStatus() == -200) {
                    wxUtil.sendTextMessage(fromWxid, "暂时无法获取新的评论，请稍后再试", 1, fromWxid, false);
                    return;
                }
            } catch (Exception e) {
                logger.error("调用外部接口获取评论失败", e);
                wxUtil.sendTextMessage(fromWxid, "调用外部接口获取评论失败", 1, fromWxid, false);
                return;
            }
        }

        if (commentToUse == null) {
            wxUtil.sendTextMessage(fromWxid, "没有找到可用的评论数据", 1, fromWxid, false);
            return;
        }

        // 调用 DeepSeek 生成新的评论内容
        String deepSeekPrompt = COMMENT_TEMPLATES_DS + commentToUse.getCommentText();
        String deepSeekResponse;
        try {
            deepSeekResponse = deepSeekClientUtil.getDeepSeekResponse(deepSeekPrompt);
        } catch (IOException e) {
            logger.error("生成评论异常 - 用户: {}", fromWxid, e);
            wxUtil.sendTextMessage(fromWxid, "评论生成失败，请重试", 1, fromWxid, false);
            return;
        }

        // 发送生成的评论文本
        wxUtil.sendTextMessage(fromWxid, deepSeekResponse, 1, fromWxid, false);

        // 发送图片（如果有）
        String pictureUrls = commentToUse.getPictureUrls();
        if (pictureUrls != null && !pictureUrls.isEmpty()) {
            // 使用 fastjson 将 JSON 字符串解析为 List<String>
            List<String> urlList = JSON.parseArray(pictureUrls, String.class);

            for (String url : urlList) {
                wxUtil.sendImageMessage(fromWxid, url.trim()); // 假设 sendImageMessage 支持 URL
            }
        }


        // 更新评论状态为已使用
        commentToUse.setIsUse(1);
        commentRepository.save(commentToUse);

        // 重置状态
        resetState(fromWxid, loadOrCreateState(INTERACTION_STATE_PREFIX + fromWxid));
    }


    // 定义一个内部类来存储用户交互状态
    @Getter
    @Setter
    static class UserInteractionState {
        private List<String> selectedSkuIds; // 新增字段，存储多个商品SKU ID
        private List<String> selectedSkuNames; // 新增字段，存储多个商品名称
        private GiftMoneyStep currentStep; // 新增当前步骤字段
        private String lastInteractionTime;
        private ProcessState currentState;
        private Map<String, String> collectedFields; // 用于存储收集到的字段值
        private String currentField; // 当前正在询问的字段

        public UserInteractionState() {
            this.currentStep = STEP_CONFIRM_GIFT; // 初始
            this.lastInteractionTime = LocalDateTime.now().format(DATE_TIME_FORMATTER);
            this.currentState = INIT;
            this.collectedFields = new HashMap<>();
            this.currentField = null;
            this.selectedSkuIds = new ArrayList<>();
            this.selectedSkuNames = new ArrayList<>();

        }

        public void updateLastInteractionTime() {
            this.lastInteractionTime = LocalDateTime.now().format(DATE_TIME_FORMATTER);
        }

        public void reset() {
            this.currentState = INIT;
            this.collectedFields.clear();
            this.currentStep = STEP_CONFIRM_GIFT; // 明确重置步骤
            updateLastInteractionTime();
        }

        // 在UserInteractionState类中增加状态校验方法
        public boolean validateStep(GiftMoneyStep expectedStep) {
            return this.currentStep != null && this.currentStep.getCode() == expectedStep.getCode();
        }

        // 推荐使用枚举管理状态
        public enum ProcessState {
            INIT, GIFT_MONEY_FLOW, PRODUCT_PROMOTION, COMMENT_GENERATION
        }

        public enum GiftMoneyStep {
            STEP_CONFIRM_GIFT(0),  // 显式指定序号
            STEP_AMOUNT(1), STEP_QUANTITY(2);
            private final int code;

            GiftMoneyStep(int code) {
                this.code = code;
            }

            public int getCode() {
                return code;
            }

        }

    }

    // 限流异常类（需自定义）
    public static class RateLimitExceededException extends RuntimeException {
        public RateLimitExceededException(String message) {
            super(message);
        }
    }

    @Setter
    @Getter
    public static class OrderInfo {
        private String skuName;
        private Long count;
        private Long orderId;
        private Date orderDate;

    }

    // 统计指标DTO
    @Getter
    @AllArgsConstructor
    class OrderStats {
        private long totalOrders;          // 总订单数
        private long validOrders;          // 有效订单数（不含取消）
        private long paidOrders;           // 已付款订单
        private double paidCommission;     // 已付款佣金
        private long pendingOrders;        // 待付款订单
        private double pendingCommission;  // 待付款佣金
        private long canceledOrders;       // 已取消订单
        private long completedOrders;      // 已完成订单
        private double completedCommission;// 已完成佣金
        private long violations;           // 违规订单数
        private double violationCommission;// 违规佣金
    }
}
