package com.ruoyi.jarvis.service.impl;

import com.ruoyi.jarvis.domain.OrderRows;
import com.ruoyi.jarvis.domain.JDOrder;
import com.ruoyi.jarvis.service.IInstructionService;
import com.ruoyi.jarvis.service.IOrderRowsService;
import com.ruoyi.jarvis.service.IJDOrderService;
import com.ruoyi.jarvis.service.IProductJdConfigService;
import com.ruoyi.jarvis.service.SuperAdminService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.concurrent.TimeUnit;

/**
 * 将 jd 项目中 JDUtil 的指令能力，抽取为无微信依赖的本地执行版。
 * 仅实现最常用统计/订单查询与转链占位能力，按需扩展。
 */
@Service
public class InstructionServiceImpl implements IInstructionService {

    @Resource
    private IOrderRowsService orderRowsService;
    @Resource
    private IJDOrderService jdOrderService;
    @Resource
    private SuperAdminService superAdminService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IProductJdConfigService productJdConfigService;

    // 录单模板（与 jd/JDUtil 中 WENAN_D 保持一致）
    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" + "下单人：\n" + "\n" + "京粉实际价格：\n" + "\n";

    @Override
    public List<String> execute(String command) {
        // 存储接收的消息到Redis队列
        storeMessageToRedis("instruction:request", command);

        List<String> result;

        if (command == null || command.trim().isEmpty()) {
            result = Collections.singletonList("请输入指令");
        } else {
            String input = command.trim();

            // 一级命令分流：京系（统计/订单）、录单/慢单、转链/礼金…
            if (input.startsWith("京") || menuKeywords().contains(input)) {
                result = Collections.singletonList(handleJingFen(input.replaceFirst("^京", "")));
            }
            // TF/H/生/拼多多 生成类指令
            else if (input.startsWith("TF")) {
                result = Collections.singletonList(handleTF(input));
            } else if (input.startsWith("H")) {
                result = Collections.singletonList(handleH(input));
            } else if (input.startsWith("生")) {
                result = Collections.singletonList(handleSheng(input));
            } else if (input.equals("拼多多") || input.startsWith("拼多多\n") || input.startsWith("拼多多\r\n") || isPDDFormat(input)) {
                result = Collections.singletonList(handlePDD(input));
            } else if (input.startsWith("录单") || input.startsWith("慢单") || input.startsWith("慢搜") || input.startsWith("慢查") || input.startsWith("单")) {
                result = handleRecordLikeMulti(input);
            } else if (input.startsWith("转链") || input.startsWith("文案") || input.startsWith("转")) {
                result = Collections.singletonList(handleTransferLike(input));
            } else {
                result = Collections.singletonList(helpText());
            }
        }

        // 存储返回的消息到Redis队列
        String response = result != null ? String.join("\n", result) : "";
        storeMessageToRedis("instruction:response", response);

        return result;
    }

    /**
     * 将消息存储到Redis队列，最多保留100条
     * @param key Redis键
     * @param message 消息内容
     */
    private void storeMessageToRedis(String key, String message) {
        if (stringRedisTemplate == null || message == null) {
            return;
        }
        try {
            // 添加时间戳
            String timestampedMessage = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " | " + message;
            // 从左边推入消息（新消息在前）
            stringRedisTemplate.opsForList().leftPush(key, timestampedMessage);
            // 保持列表最多100条，删除最早的消息
            stringRedisTemplate.opsForList().trim(key, 0, 999);
        } catch (Exception e) {
            // 记录异常但不影响主流程
            System.err.println("存储消息到Redis失败: " + e.getMessage());
        }
    }

    @Override
    public List<String> getHistory(String type, Integer limit) {
        if (stringRedisTemplate == null) {
            return Collections.emptyList();
        }

        try {
            // 确定Redis键
            String key;
            if ("request".equalsIgnoreCase(type)) {
                key = "instruction:request";
            } else if ("response".equalsIgnoreCase(type)) {
                key = "instruction:response";
            } else {
                return Collections.emptyList();
            }

            // 确定获取数量，默认100条
            int count = (limit != null && limit > 0) ? Math.min(limit, 1000) : 1000;

            // 从Redis获取历史消息（索引0到count-1）
            List<String> messages = stringRedisTemplate.opsForList().range(key, 0, count - 1);

            return messages != null ? messages : Collections.emptyList();
        } catch (Exception e) {
            System.err.println("获取历史消息失败: " + e.getMessage());
            return Collections.emptyList();
        }
    }

    private Set<String> menuKeywords() {
        return new HashSet<>(Arrays.asList("菜单", "今日统计", "昨日统计", "三日统计", "七日统计", "一个月统计", "两个月统计", "三个月统计", "这个月统计", "上个月统计", "今日订单", "昨日订单", "七日订单", "总统计"));
    }

    private String handleJingFen(String cmd) {
        String action = cmd.trim();
        if (action.isEmpty() || action.equals("菜单")) {
            return jingMenu();
        }

        // 取出所有订单（排除被删除/无效：这里沿用 OrderRowsService 的常规查询，必要时可增加过滤参数）
        List<OrderRows> all = orderRowsService.selectOrderRowsList(new OrderRows());
        if (all == null) all = Collections.emptyList();

        switch (action) {
            case "今日统计":
                return statsText(filterByDays(all, 0), "今日统计");
            case "昨日统计":
                return statsText(filterYesterday(all), "昨日统计");
            case "三日统计":
                return statsText(filterByRange(all, 3), "三日统计");
            case "七日统计":
                return statsText(filterByRange(all, 7), "七日统计");
            case "一个月统计":
                return statsText(filterByRange(all, 30), "一个月统计");
            case "两个月统计":
                return statsText(filterByRange(all, 60), "两个月统计");
            case "三个月统计":
                return statsText(filterByRange(all, 90), "三个月统计");
            case "这个月统计":
                return statsText(filterThisMonth(all), "这个月统计");
            case "上个月统计":
                return statsText(filterLastMonth(all), "上个月统计");
            case "总统计":
                return statsText(all, "总统计");
            case "今日订单":
                return listOrders(filterByDays(all, 0), "今日订单");
            case "昨日订单":
                return listOrders(filterYesterday(all), "昨日订单");
            case "七日订单":
                return listOrders(filterByRange(all, 7), "七日订单");
            default:
                // 高级命令：违规N、SKU、搜索、JF… 此处按需扩展
                if (action.startsWith("高级")) {
                    return "高级指令暂未开放";
                }
                return jingMenu();
        }
    }

    private List<String> handleRecordLikeMulti(String input) {
        // 仅实现“慢搜/慢查 关键词”与“录单/慢单 日期范围”的只读输出，避免侵入写库
        if (input.startsWith("慢搜") || input.startsWith("慢查")) {
            String kw = input.replaceFirst("^慢搜|^慢查", "").trim();
            if (kw.isEmpty()) return Collections.singletonList("请输入搜索关键词");
            List<JDOrder> list = jdOrderService.selectJDOrderList(new JDOrder());
            if (list == null) list = Collections.emptyList();
            // 统一截取分销标记
            list.forEach(order -> order.setDistributionMark(truncateDistributionMark(order.getDistributionMark())));
            String low = kw.toLowerCase(Locale.ROOT);
            List<JDOrder> matched = list.stream().filter(o -> contains(o.getRemark(), low) || contains(o.getOrderId(), low) || contains(o.getModelNumber(), low) || contains(o.getAddress(), low) || contains(o.getBuyer(), low)).limit(50).collect(Collectors.toList());
            if (matched.isEmpty()) return Collections.singletonList("未找到匹配的订单");
            StringBuilder sb = new StringBuilder();
            int i = 0;
            for (JDOrder o : matched) {
                i++;
                sb.append(i).append(",   单：").append(nvl(o.getRemark())).append("\n分销标记：").append(nvl(o.getDistributionMark())).append("\n型号：").append(nvl(o.getModelNumber())).append("\n链接：").append(nvl(o.getLink())).append("\n下单付款：").append(nvl(o.getPaymentAmount())).append("\n后返金额：").append(nvl(o.getRebateAmount())).append("\n地址：").append(nvl(o.getAddress())).append("\n物流链接：").append(nvl(o.getLogisticsLink())).append("\n订单号：").append(nvl(o.getOrderId())).append("\n下单人：").append(nvl(o.getBuyer())).append("\n下单时间：").append(nvl(o.getOrderTime())).append("\n备注：").append(nvl(o.getStatus())).append("\n━━━━━━━━━━━━\n");
            }
            return Collections.singletonList(sb.toString());
        }
        if (input.startsWith("录单")) {
            // 录单导出样式（tab）
            List<LocalDate> range = parseDateRange(input.replaceFirst("^录单", "").trim());
            if (range == null) {
                LocalDate today = effectiveToday().toLocalDate();
                range = Arrays.asList(today, today);
            }
            Date start = Date.from(range.get(0).atStartOfDay(ZoneId.systemDefault()).toInstant());
            Date end = Date.from(range.get(1).atTime(LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());
            List<JDOrder> list = jdOrderService.selectJDOrderList(new JDOrder());
            if (list == null) list = Collections.emptyList();
            // 统一截取分销标记
            list.forEach(order -> order.setDistributionMark(truncateDistributionMark(order.getDistributionMark())));
            // 过滤条件：时间范围 + 参与统计标记（isCountEnabled为null或1表示参与统计）
            List<JDOrder> filtered = list.stream().filter(o -> o.getOrderTime() != null && !o.getOrderTime().before(start) && !o.getOrderTime().after(end) && (o.getIsCountEnabled() == null || o.getIsCountEnabled() == 1)).collect(Collectors.toList());
            if (filtered.isEmpty()) return Collections.singletonList("今天没有订单。");
            // 按 remark 排序
            List<JDOrder> sorted = filtered.stream().sorted(Comparator.comparing(JDOrder::getRemark, Comparator.nullsFirst(String::compareTo))).collect(Collectors.toList());
            StringBuilder sb = new StringBuilder();
            for (JDOrder o : sorted) {
                sb.append(nvl(o.getRemark())).append('\t').append(nvl(o.getOrderId())).append('\t').append(fmt(o.getOrderTime()).split(" ")[0]).append('\t').append(nvl(o.getModelNumber())).append('\t').append(nvl(o.getAddress())).append('\t').append(nvl(o.getLogisticsLink())).append('\t').append('\t').append(nvl(o.getBuyer())).append('\t').append(nvl(o.getPaymentAmount())).append('\t').append(nvl(o.getRebateAmount())).append('\t').append(mapDistribution(o.getDistributionMark())).append('\t').append(nvl(o.getStatus())).append("\n");
            }
            return Collections.singletonList(sb.toString());
        }
        if (input.startsWith("慢单")) {
            // 慢单：分销标记分组 -> 型号统计 + 详情 + 算钱文本
            List<LocalDate> range = parseDateRange(input.replaceFirst("^慢单", "").trim());
            if (range == null) {
                LocalDate today = effectiveToday().toLocalDate();
                range = Arrays.asList(today, today);
            }
            Date start = Date.from(range.get(0).atStartOfDay(ZoneId.systemDefault()).toInstant());
            Date end = Date.from(range.get(1).atTime(LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());
            List<JDOrder> list = jdOrderService.selectJDOrderList(new JDOrder());
            if (list == null) list = Collections.emptyList();
            // 统一截取分销标记
            list.forEach(order -> order.setDistributionMark(truncateDistributionMark(order.getDistributionMark())));
            // 过滤条件：时间范围 + 参与统计标记（isCountEnabled为null或1表示参与统计）
            List<JDOrder> filtered = list.stream().filter(o -> o.getOrderTime() != null && !o.getOrderTime().before(start) && !o.getOrderTime().after(end) && (o.getIsCountEnabled() == null || o.getIsCountEnabled() == 1)).collect(Collectors.toList());
            if (filtered.isEmpty()) return Collections.singletonList("今天没有订单。");

            Map<String, List<JDOrder>> byDM = filtered.stream().filter(o -> o.getStatus() == null || !"拍错退款".equals(o.getStatus())).collect(Collectors.groupingBy(JDOrder::getDistributionMark));
            List<String> outputs = new ArrayList<>();
            List<Map.Entry<String, List<JDOrder>>> dmEntries = new ArrayList<>(byDM.entrySet());
            dmEntries.sort(Comparator.comparing(en -> en.getKey() == null ? "" : en.getKey()));

            for (Map.Entry<String, List<JDOrder>> e : dmEntries) {
                String dm = e.getKey() != null ? e.getKey() : "未提供";
                List<JDOrder> orders = e.getValue();

                Map<String, Long> byModel = orders.stream().collect(Collectors.groupingBy(JDOrder::getModelNumber, Collectors.counting()));

                int totalCount = 0;
                StringBuilder summary = new StringBuilder();
                List<Map.Entry<String, Long>> modelEntries = new ArrayList<>(byModel.entrySet());
                modelEntries.sort(Comparator.comparing(en -> en.getKey() == null ? "" : en.getKey()));

                // 记录该分组中每个型号的最高单价订单
                Map<String, JDOrder> groupMaxPriceOrders = new HashMap<>();
                Map<String, Integer> groupModelCounts = new HashMap<>();

                for (Map.Entry<String, Long> em : modelEntries) {
                    int c = em.getValue().intValue();
                    totalCount += c;
                    String model = em.getKey() != null ? em.getKey() : "未知";

                    summary.append("型号：").append(model).append("   数量：").append(c).append("\n");

                    // 记录该分组的型号数量
                    groupModelCounts.put(model, c);

                    // 找到该型号价格最高的订单
                    for (JDOrder order : orders) {
                        if (model.equals(order.getModelNumber())) {
                            JDOrder currentMax = groupMaxPriceOrders.get(model);
                            if (currentMax == null ||
                                (order.getPaymentAmount() != null &&
                                 (currentMax.getPaymentAmount() == null || order.getPaymentAmount() > currentMax.getPaymentAmount()))) {
                                groupMaxPriceOrders.put(model, order);
                            }
                        }
                    }
                }
                summary.append("总计：").append(totalCount).append("\n详情：");

                List<JDOrder> sorted = orders.stream().sorted(Comparator.comparing(JDOrder::getRemark, Comparator.nullsFirst(String::compareTo))).collect(Collectors.toList());
                StringBuilder detail = new StringBuilder();
                int idx = 0;
                for (JDOrder o : sorted) {
                    if ("拍错退款".equals(o.getStatus())) continue;
                    idx++;
                    detail.append("\n").append(idx).append("  ────────────\n").append("单：").append(o.getRemark() != null ? o.getRemark() : "未提供").append("\n备注：").append(o.getStatus() != null ? o.getStatus() : " ").append("\n型号：").append(o.getModelNumber() != null ? o.getModelNumber() : "未提供").append("\n地址：").append(o.getAddress() != null ? o.getAddress() : "未提供").append("\n物流链接：\n").append(o.getLogisticsLink() != null ? o.getLogisticsLink() : "无");
                }
                // 拆分为多条消息 - 订单详情
                StringBuilder infoSingle = new StringBuilder();
                infoSingle.append("分销标记：").append(dm).append("\n").append(summary).append(detail).append("\n");
                outputs.add(infoSingle.toString().trim());

                // 为该分组添加算钱文本
                if (!groupModelCounts.isEmpty()) {
                    StringBuilder priceText = new StringBuilder();
                    priceText.append("分销标记：").append(dm).append("\n");

                    // 先输出型号和数量
                    List<Map.Entry<String, Integer>> sortedEntries = groupModelCounts.entrySet().stream()
                        .sorted(Comparator.comparing(Map.Entry::getKey))
                        .collect(Collectors.toList());

                    for (Map.Entry<String, Integer> entry : sortedEntries) {
                        String model = entry.getKey();
                        int count = entry.getValue();
                        priceText.append("型号：").append(model).append("   数量：").append(count).append("\n");
                    }

                    priceText.append("\n");

                    // 输出金额计算（单台价格-返现+佣金=净价×数量=总价）
                    double grandTotal = 0.0;
                    StringBuilder calculationLines = new StringBuilder();
                    List<Double> totalPricesList = new ArrayList<>();

                    for (Map.Entry<String, Integer> entry : sortedEntries) {
                        String model = entry.getKey();
                        int count = entry.getValue();

                        // 获取该型号最高价格的订单
                        JDOrder maxPriceOrder = groupMaxPriceOrders.get(model);
                        double singlePayment = 0.0;
                        double singleRebate = 0.0;

                        if (maxPriceOrder != null) {
                            singlePayment = maxPriceOrder.getPaymentAmount() != null ? maxPriceOrder.getPaymentAmount() : 0.0;
                            singleRebate = maxPriceOrder.getRebateAmount() != null ? maxPriceOrder.getRebateAmount() : 0.0;
                        }

                        // 四舍五入到2位小数
                        singlePayment = Math.round(singlePayment * 100.0) / 100.0;
                        singleRebate = Math.round(singleRebate * 100.0) / 100.0;

                        // 从Redis获取佣金（收取）
                        double commission = 0.0;
                        try {
                            com.ruoyi.jarvis.domain.ProductJdConfig config = productJdConfigService.selectProductJdConfigByModel(model);
                            if (config != null) {
                                // 优先使用新的佣金（收取）字段，如果没有则使用旧的commission字段
                                if (config.getCommissionReceive() != null) {
                                    commission = config.getCommissionReceive().doubleValue();
                                } else if (config.getCommission() != null) {
                                    commission = config.getCommission().doubleValue();
                                }
                            }
                        } catch (Exception ex) {
                            // 如果获取失败，佣金为0
                        }

                        // 计算净价（单台价格 - 返现 + 佣金）
                        double netPrice = singlePayment - singleRebate + commission;
                        // 四舍五入到2位小数
                        netPrice = Math.round(netPrice * 100.0) / 100.0;

                        // 计算总价
                        double totalPrice = netPrice * count;
                        // 四舍五入到2位小数
                        totalPrice = Math.round(totalPrice * 100.0) / 100.0;
                        totalPricesList.add(totalPrice);
                        grandTotal += totalPrice;

                        // 格式：单台价格-返现+佣金=净价×数量=总价
                        if (count == 1) {
                            // 数量为1时，不显示×1
                            calculationLines.append(String.format("%.2f-%.2f+%.2f=%.2f\n",
                                singlePayment, singleRebate, commission, totalPrice));
                        } else {
                            calculationLines.append(String.format("%.2f-%.2f+%.2f=%.2f×%d=%.2f\n",
                                singlePayment, singleRebate, commission, netPrice, count, totalPrice));
                        }
                    }

                    priceText.append(calculationLines);

                    // 输出汇总（各型号总价相加）
                    if (sortedEntries.size() > 1) {
                        priceText.append("\n");
                        // 构建汇总公式
                        for (int i = 0; i < totalPricesList.size(); i++) {
                            if (i > 0) {
                                priceText.append("+");
                            }
                            priceText.append(String.format("%.2f", totalPricesList.get(i)));
                        }
                        // 四舍五入汇总到2位小数
                        grandTotal = Math.round(grandTotal * 100.0) / 100.0;
                        priceText.append(String.format("=%.2f", grandTotal));
                    }

                    outputs.add(priceText.toString().trim());
                }
            }

            // ==================== 追加：按下单人分组统计 ====================
            outputs.add("\n━━━━━━━ 按下单人统计 ━━━━━━━");
            
            // 按下单人分组（过滤掉拍错退款）
            Map<String, List<JDOrder>> byBuyer = filtered.stream()
                .filter(o -> o.getStatus() == null || !"拍错退款".equals(o.getStatus()))
                .filter(o -> o.getBuyer() != null && !o.getBuyer().isEmpty())
                .collect(Collectors.groupingBy(JDOrder::getBuyer));
            
            List<Map.Entry<String, List<JDOrder>>> buyerEntries = new ArrayList<>(byBuyer.entrySet());
            buyerEntries.sort(Comparator.comparing(en -> en.getKey() == null ? "" : en.getKey()));
            
            for (Map.Entry<String, List<JDOrder>> e : buyerEntries) {
                String buyer = e.getKey() != null ? e.getKey() : "未提供";
                List<JDOrder> orders = e.getValue();
                
                Map<String, Long> byModel = orders.stream()
                    .collect(Collectors.groupingBy(JDOrder::getModelNumber, Collectors.counting()));
                
                int totalCount = 0;
                StringBuilder summary = new StringBuilder();
                List<Map.Entry<String, Long>> modelEntries = new ArrayList<>(byModel.entrySet());
                modelEntries.sort(Comparator.comparing(en -> en.getKey() == null ? "" : en.getKey()));
                
                // 记录该下单人每个型号的最高单价订单
                Map<String, JDOrder> buyerMaxPriceOrders = new HashMap<>();
                Map<String, Integer> buyerModelCounts = new HashMap<>();
                
                for (Map.Entry<String, Long> em : modelEntries) {
                    int c = em.getValue().intValue();
                    totalCount += c;
                    String model = em.getKey() != null ? em.getKey() : "未知";
                    
                    summary.append("型号：").append(model).append("   数量：").append(c).append("\n");
                    
                    buyerModelCounts.put(model, c);
                    
                    // 找到该型号价格最高的订单
                    for (JDOrder order : orders) {
                        if (model.equals(order.getModelNumber())) {
                            JDOrder currentMax = buyerMaxPriceOrders.get(model);
                            if (currentMax == null ||
                                (order.getPaymentAmount() != null &&
                                 (currentMax.getPaymentAmount() == null || 
                                  order.getPaymentAmount() > currentMax.getPaymentAmount()))) {
                                buyerMaxPriceOrders.put(model, order);
                            }
                        }
                    }
                }
                summary.append("总计：").append(totalCount).append("\n详情：");
                
                List<JDOrder> sorted = orders.stream()
                    .sorted(Comparator.comparing(JDOrder::getRemark, Comparator.nullsFirst(String::compareTo)))
                    .collect(Collectors.toList());
                StringBuilder detail = new StringBuilder();
                int idx = 0;
                for (JDOrder o : sorted) {
                    if ("拍错退款".equals(o.getStatus())) continue;
                    idx++;
                    detail.append("\n").append(idx).append("  ────────────\n")
                        .append("单：").append(o.getRemark() != null ? o.getRemark() : "未提供").append("\n")
                        .append("备注：").append(o.getStatus() != null ? o.getStatus() : " ").append("\n")
                        .append("型号：").append(o.getModelNumber() != null ? o.getModelNumber() : "未提供").append("\n")
                        .append("地址：").append(o.getAddress() != null ? o.getAddress() : "未提供").append("\n")
                        .append("物流链接：\n").append(o.getLogisticsLink() != null ? o.getLogisticsLink() : "无");
                }
                
                // 订单详情
                StringBuilder infoSingle = new StringBuilder();
                infoSingle.append("下单人：").append(buyer).append("\n").append(summary).append(detail).append("\n");
                outputs.add(infoSingle.toString().trim());
                
                // 算钱文本（使用佣金支付）
                if (!buyerModelCounts.isEmpty()) {
                    StringBuilder priceText = new StringBuilder();
                    priceText.append("下单人：").append(buyer).append("\n");
                    
                    // 先输出型号和数量
                    List<Map.Entry<String, Integer>> sortedEntries = buyerModelCounts.entrySet().stream()
                        .sorted(Comparator.comparing(Map.Entry::getKey))
                        .collect(Collectors.toList());
                    
                    for (Map.Entry<String, Integer> entry : sortedEntries) {
                        String model = entry.getKey();
                        int count = entry.getValue();
                        priceText.append("型号：").append(model).append("   数量：").append(count).append("\n");
                    }
                    
                    priceText.append("\n");
                    
                    // 输出金额计算（使用佣金支付字段）
                    double grandTotal = 0.0;
                    StringBuilder calculationLines = new StringBuilder();
                    List<Double> totalPricesList = new ArrayList<>();
                    
                    for (Map.Entry<String, Integer> entry : sortedEntries) {
                        String model = entry.getKey();
                        int count = entry.getValue();
                        
                        // 获取该型号最高价格的订单
                        JDOrder maxPriceOrder = buyerMaxPriceOrders.get(model);
                        double singlePayment = 0.0;
                        double singleRebate = 0.0;
                        
                        if (maxPriceOrder != null) {
                            singlePayment = maxPriceOrder.getPaymentAmount() != null ? maxPriceOrder.getPaymentAmount() : 0.0;
                            singleRebate = maxPriceOrder.getRebateAmount() != null ? maxPriceOrder.getRebateAmount() : 0.0;
                        }
                        
                        singlePayment = Math.round(singlePayment * 100.0) / 100.0;
                        singleRebate = Math.round(singleRebate * 100.0) / 100.0;
                        
                        // 从Redis获取佣金（支付）- 支付给下单人的佣金
                        double commissionPay = 0.0;
                        try {
                            com.ruoyi.jarvis.domain.ProductJdConfig config = productJdConfigService.selectProductJdConfigByModel(model);
                            if (config != null) {
                                // 优先使用新的佣金（支付）字段，如果没有则使用旧的commission字段
                                if (config.getCommissionPay() != null) {
                                    commissionPay = config.getCommissionPay().doubleValue();
                                } else if (config.getCommission() != null) {
                                    commissionPay = config.getCommission().doubleValue();
                                }
                            }
                        } catch (Exception ex) {
                            // 如果获取失败，佣金为0
                        }
                        
                        // 计算净价（单台价格 - 返现 + 佣金支付）
                        double netPrice = singlePayment - singleRebate + commissionPay;
                        netPrice = Math.round(netPrice * 100.0) / 100.0;
                        
                        // 计算总价
                        double totalPrice = netPrice * count;
                        totalPrice = Math.round(totalPrice * 100.0) / 100.0;
                        totalPricesList.add(totalPrice);
                        grandTotal += totalPrice;
                        
                        // 格式：单台价格-返现+佣金=净价×数量=总价
                        if (count == 1) {
                            calculationLines.append(String.format("%.2f-%.2f+%.2f=%.2f\n",
                                singlePayment, singleRebate, commissionPay, totalPrice));
                        } else {
                            calculationLines.append(String.format("%.2f-%.2f+%.2f=%.2f×%d=%.2f\n",
                                singlePayment, singleRebate, commissionPay, netPrice, count, totalPrice));
                        }
                    }
                    
                    priceText.append(calculationLines);
                    
                    // 输出汇总
                    if (sortedEntries.size() > 1) {
                        priceText.append("\n");
                        for (int i = 0; i < totalPricesList.size(); i++) {
                            if (i > 0) {
                                priceText.append("+");
                            }
                            priceText.append(String.format("%.2f", totalPricesList.get(i)));
                        }
                        grandTotal = Math.round(grandTotal * 100.0) / 100.0;
                        priceText.append(String.format("=%.2f", grandTotal));
                    }
                    
                    outputs.add(priceText.toString().trim());
                }
            }
            // ==================== 按下单人统计结束 ====================

            return outputs.isEmpty() ? Collections.singletonList("无数据") : outputs;
        }
        if (input.startsWith("单")) {
            return Collections.singletonList(handleDanWriteDb(input));
        }
        return Collections.singletonList(helpText());
    }

    // ===== TF/H/生 处理 =====
    // 产品京东配置已迁移到Redis，通过productJdConfigService获取

    private static final List<String> phoneWithTF = new ArrayList<>();

    static {
        /*

13103996539 
15514755615 
17746927935 
13140433517 
17746921532 
15514786055 
          */
        phoneWithTF.add("13103996539");
        phoneWithTF.add("15514755615");
        phoneWithTF.add("17746927935");
        phoneWithTF.add("13140433517");
        phoneWithTF.add("17746921532");
        phoneWithTF.add("15514786055");

    }

private String handleTF(String input) {
    String body = input.replaceFirst("^TF\\s*", "");
    body = body.replaceAll("[啊阿]", "");
    String[] lines = body.split("\\r?\\n+");
    List<String> outputs = new ArrayList<>();
    for (String line : lines) {
        if (line == null) continue;
        line = line.trim();
        if (line.isEmpty()) continue;
        String[] parts = line.split("\t"); // 使用制表符分割每一行
        /**
         * 原来的
         * ZQD180F-EB200	1	石**[7796]	13243039070	上海市 上海市 普陀区 水泉南路58弄3-12-502[阿15783543077转7796]
         * 改成
         * 10.10 	腾锋	JY202510093195	ZQD180F-EB200	1	石**[7796]	13243039070	上海市 上海市 普陀区 水泉南路58弄3-12-502[阿15783543077转7796] 	1650	有货		2
         * 型号，地址，电话的处理逻辑不变，将10.10 	腾锋	JY202510093195 设置成分销标识这个字段，比如之前是H-TF，现在改成H-TF(10.10 	腾锋	JY202510093195)
         * */
        if (parts.length >= 7) {  // 至少需要分销信息(3) + 型号(1) + 数量(1) + 姓名(1) + 电话(1) = 7个字段
            // 处理分销标记: 简化格式，只保留H-TF和第三方单号（第三方单号已单独存储）
            // 提取第三方单号（第3个字段，格式如：JY202511051374）
            String thirdPartyOrderNo = parts.length > 2 ? parts[2].trim() : "";
            String fenxiaoInfo = "H-TF";
            // 如果第三方单号存在，添加到分销标记中（但保持简短）
            if (!thirdPartyOrderNo.isEmpty()) {
                fenxiaoInfo = "H-TF(" + thirdPartyOrderNo + ")";
            }

            // 提取型号（第4个字段）
            String modelNumber = parts[3].replace("\\n", "");

            // 提取数量（第5个字段）
            String quantityStr = parts[4];

            // 提取姓名部分（第6个字段）
            String namePart = parts[5];

            // 提取电话（第7个字段）
            String phone = parts[6];
            //每天可以使用 phoneWithTF 中的多个不同号码，每个号码只用一次
            if ("13243039070".equals(phone) || "17530176250".equals(phone)) {
                String today = new java.text.SimpleDateFormat("yyyy-MM-dd").format(new Date());
                String usedPhonesKey = "phone_used_today:" + today;
                
                if (stringRedisTemplate != null) {
                    try {
                        // 获取今天已经使用过的号码集合
                        Set<String> usedPhonesToday = stringRedisTemplate.opsForSet().members(usedPhonesKey);
                        
                        // 找出今天还没使用过的号码
                        List<String> availablePhones = new ArrayList<>();
                        for (String p : phoneWithTF) {
                            if (usedPhonesToday == null || !usedPhonesToday.contains(p)) {
                                availablePhones.add(p);
                            }
                        }
                        
                        if (!availablePhones.isEmpty()) {
                            // 随机选择一个今天还没用过的号码
                            phone = availablePhones.get(new Random().nextInt(availablePhones.size()));
                            // 记录今天使用的号码（24小时后自动过期）
                            stringRedisTemplate.opsForSet().add(usedPhonesKey, phone);
                            stringRedisTemplate.expire(usedPhonesKey, 1, TimeUnit.DAYS);
                        } else {
                            // phoneWithTF 中的号码今天都用完了，使用备用号码（轮换使用）
                            String backupUsedKey = "backup_phone_used_today:" + today;
                            Set<String> backupUsedToday = stringRedisTemplate.opsForSet().members(backupUsedKey);
                            
                            // 检查两个备用号码哪个还没用过
                            if (backupUsedToday == null || !backupUsedToday.contains("15639125541")) {
                                phone = "15639125541";
                            } else if (!backupUsedToday.contains("13243039070")) {
                                phone = "13243039070";
                            } else {
                                // 两个备用号码今天都用过了，继续轮换使用
                                String lastBackupKey = "last_backup_phone:" + today;
                                String lastBackup = stringRedisTemplate.opsForValue().get(lastBackupKey);
                                if ("15639125541".equals(lastBackup)) {
                                    phone = "13243039070";
                                } else {
                                    phone = "15639125541";
                                }
                            }
                            
                            // 记录今天使用的备用号码
                            stringRedisTemplate.opsForSet().add(backupUsedKey, phone);
                            stringRedisTemplate.expire(backupUsedKey, 1, TimeUnit.DAYS);
                            stringRedisTemplate.opsForValue().set("last_backup_phone:" + today, phone, 1, TimeUnit.DAYS);
                        }
                    } catch (Exception e) {
                        // Redis操作失败，使用随机号码作为降级方案
                        phone = phoneWithTF.get(new Random().nextInt(phoneWithTF.size()));
                    }
                } else {
                    // Redis不可用，使用随机号码
                    phone = phoneWithTF.get(new Random().nextInt(phoneWithTF.size()));
                }
            }

            // 构建地址：姓名+电话+地址信息
            StringBuilder address = new StringBuilder();

            // 使用正则表达式提取中文字符（常用于姓名开头）
            Pattern pattern = Pattern.compile("[\\u4E00-\\u9FA5]+");
            Matcher matcher = pattern.matcher(namePart);
            if (matcher.find()) {
                address = new StringBuilder(matcher.group());
            }
            address.append(phone);

            // 添加地址信息（从第8个字段开始的所有剩余内容）
            for (int i = 7; i < parts.length; i++) {
                if (!parts[i].trim().isEmpty()) {
                    // 过滤掉纯数字的价格信息
                    if (!parts[i].matches("^\\d+$") && !parts[i].matches("^[有无缺]货$")) {
                        address.append(parts[i]);
                    }
                }
            }

            String jf = productJdConfigService.getJdUrlByProductModel(modelNumber);

            StringBuilder order = new StringBuilder();
            order.append("生"+phone).append("\n").append(fenxiaoInfo).append("\n").append(modelNumber).append("\n").append(jf).append("\n").append(quantityStr).append("\n").append(address);
            outputs.add(generateOrderText(order.toString()));
        } else {
            outputs.add("TF 指令格式：TF\t分销信息\t分销信息\t分销信息\t型号\t数量\t姓名\t电话\t地址 ；也支持多行，每行一条数据");
        }
    }
    return String.join("\n\n", outputs);
}



    private String handleH(String input) {
        String[] lines = input.replaceFirst("^H", "").split("\n");
        if (lines.length < 3) return "H 指令需三行：姓名[后缀]\n电话\n地址 … [后缀] 型号";

        String nameLine = lines[0].trim();
        String phone = lines[1].trim();
        String addressLine = lines[2].trim();

        String name = extractChinese(nameLine);
        String suffix = extractBetweenBrackets(nameLine);

        String modelNumber = extractLastNonChineseToken(addressLine);
        String cleanedAddress = addressLine.replaceAll("\\[.*?]", "").replace(modelNumber, "").replaceAll("\\s+", " ").trim();
        String fullAddress = cleanedAddress + " 安装派送联系" + phone + (suffix.isEmpty() ? "" : "转" + suffix);

        StringBuilder sheng = new StringBuilder();
        sheng.append("生\n").append("H\n").append(modelNumber).append("\n").append("\n") // 转链链接留空
                .append("1\n").append(name).append(fullAddress);
        return generateOrderText(sheng.toString());
    }

    private String handleSheng(String input) {
        // 输入格式：
        // 生\n分销标记\n型号\n转链链接\n数量\n地址
        String[] split = input.split("\n");
        if (split.length != 6) {
            return "生 指令格式：\n生\n分销标记\n型号\n转链链接\n数量\n地址";
        }
        // 轻度清洗：移除**、| 等噪声
        split[2] = sanitizeModel(split[2]);
        split[3] = sanitizeLink(split[3]);
        split[5] = sanitizeAddress(split[5]);
        return generateOrderText(String.join("\n", split));
    }

    /**
     * 判断是否为拼多多格式
     * 拼多多格式特征：第一行包含🕒符号，或者行数>=4
     */
    private boolean isPDDFormat(String input) {
        if (input == null || input.trim().isEmpty()) {
            return false;
        }
        String[] lines = input.split("\r?\n");
        if (lines.length >= 4) {
            // 检查第一行是否包含🕒符号
            if (lines[0].contains("🕒")) {
                return true;
            }
            // 或者检查是否有4行数据且第二行看起来像电话号码
            if (lines.length >= 4 && lines[1].trim().matches("^1[3-9]\\d{9}$")) {
                return true;
            }
        }
        return false;
    }

    private String handlePDD(String input) {
        // 拼多多新格式：
        // 拼多多251102-457567158704072
        // 赵政委[6947]
        // 17283248756
        // 安徽省 宿州市 埇桥区 映月湾东区3栋103[6947]
        // eb150
        
        // 旧格式兼容：
        // 🕒 林[1518]
        // 17284023487
        // 广西壮族自治区 柳州市 柳北区 绿城·杨柳郡柳园7栋[1518]
        // eb150
        
        // 如果输入只是"拼多多"，返回提示信息
        if (input.equals("拼多多") || input.trim().equals("拼多多")) {
            return "请粘贴拼多多格式数据：\n新格式（推荐）：\n拼多多251102-457567158704072\n赵政委[6947]\n17283248756\n安徽省 宿州市 埇桥区 映月湾东区3栋103[6947]\neb150\n\n旧格式（兼容）：\n🕒 林[1518]\n17284023487\n广西壮族自治区 柳州市 柳北区 绿城·杨柳郡柳园7栋[1518]\neb150";
        }
        
        String[] lines = input.split("\r?\n");
        String thirdPartyOrderNo = null;
        int nameLineIndex = 0;
        boolean isNewFormat = false;
        
        // 检查是否是新格式（第一行包含"拼多多"）
        if (lines.length > 0) {
            String firstLine = lines[0].trim();
            
            // 格式1：拼多多数字-数字（一行格式，如：拼多多251102-457567158704072）
            Pattern orderNoPattern = Pattern.compile("拼多多(\\d+-\\d+)");
            Matcher matcher = orderNoPattern.matcher(firstLine);
            if (matcher.find()) {
                thirdPartyOrderNo = matcher.group(1); // 提取订单号部分（不含"拼多多"）
                isNewFormat = true;
                nameLineIndex = 1; // 新格式下，姓名在第二行
            } 
            // 格式2：第一行是"拼多多"，第二行是订单号（多行格式）
            else if (firstLine.equals("拼多多") && lines.length > 1) {
                String secondLine = lines.length > 1 ? lines[1].trim() : "";
                // 检查第二行是否是订单号格式（数字-数字）
                Pattern orderNoPattern2 = Pattern.compile("^(\\d+-\\d+)$");
                Matcher matcher2 = orderNoPattern2.matcher(secondLine);
                if (matcher2.find()) {
                    thirdPartyOrderNo = matcher2.group(1); // 提取订单号
                    isNewFormat = true;
                    nameLineIndex = 2; // 多行格式下，姓名在第三行
                } else {
                    // 旧格式：移除"拼多多"前缀（如果有）
                    String data = input.replaceFirst("^拼多多\\s*[\r\n]+", "").trim();
                    lines = data.split("\r?\n");
                    nameLineIndex = 0;
                }
            } else {
                // 旧格式：移除"拼多多"前缀（如果有）
                String data = input.replaceFirst("^拼多多\\s*[\r\n]+", "").trim();
                lines = data.split("\r?\n");
                nameLineIndex = 0;
            }
        }
        
        // 检查行数
        // 如果第三方单号在第二行（多行格式），需要6行；如果在第一行（一行格式），需要5行
        int requiredLines = isNewFormat ? (nameLineIndex == 2 ? 6 : 5) : 4;
        if (lines.length < requiredLines) {
            String formatDesc = isNewFormat ? 
                (nameLineIndex == 2 ? 
                    "\n1. 拼多多\n2. 订单号\n3. 姓名[编号]\n4. 电话\n5. 地址[编号]\n6. 型号" :
                    "\n1. 拼多多订单号\n2. 姓名[编号]\n3. 电话\n4. 地址[编号]\n5. 型号") :
                "\n1. 🕒 姓名[编号]\n2. 电话\n3. 地址[编号]\n4. 型号";
            return "拼多多格式错误，需要" + requiredLines + "行数据：" + formatDesc;
        }
        
        // 解析姓名行
        String nameLine = lines[nameLineIndex].trim();
        // 移除emoji和特殊字符，提取中文姓名
        String name = extractChinese(nameLine);
        // 如果提取失败，尝试直接从第一行提取（去除emoji、符号和括号内容后剩余的中文）
        if (name.isEmpty()) {
            // 移除所有emoji和特殊符号，只保留中文
            String cleaned = nameLine.replaceAll("[🕒\\[\\]]", "").replaceAll("\\[.*?\\]", "").trim();
            // 只保留中文字符
            name = extractChinese(cleaned);
        }
        // 提取编号（如果有）
        String suffix = extractBetweenBrackets(nameLine);
        
        // 解析电话行
        int phoneLineIndex = nameLineIndex + 1;
        String phone = lines[phoneLineIndex].trim();
        
        // 解析地址行
        int addressLineIndex = nameLineIndex + 2;
        String addressLine = lines[addressLineIndex].trim();
        // 移除编号括号和其中的内容
        String address = addressLine.replaceAll("\\[.*?]", "").trim();
        
        // 解析型号行
        int modelLineIndex = nameLineIndex + 3;
        String modelNumber = lines[modelLineIndex].trim();
        // 清洗型号
        modelNumber = sanitizeModel(modelNumber);
        
        // 构建完整地址：姓名 + 固定号码(13068923963) + 地址 + 原始电话 + 转 + 编号
        // 格式：赵政委 13068923963 安徽省 宿州市 埇桥区 映月湾东区3栋103 17283248756转6947
        StringBuilder fullAddress = new StringBuilder();
        // 确保姓名不为空，如果仍为空则使用默认值（但这种情况应该不会发生）
        if (!name.isEmpty()) {
            fullAddress.append(name);
        } else {
            // 如果姓名提取失败，记录日志（生产环境可以移除）
            System.err.println("警告：拼多多格式姓名提取失败，姓名行内容：" + nameLine);
        }
        // 固定的号码
        fullAddress.append(" 13068923963 ");
        // 地址
        fullAddress.append(address);
        // 原始电话和编号
        fullAddress.append(" ").append(phone);
        if (!suffix.isEmpty()) {
            fullAddress.append("转").append(suffix);
        }
        
        // 获取转链链接
        String jf = productJdConfigService.getJdUrlByProductModel(modelNumber);
        
        // 构建分销标记：只保存 PDD，不包含第三方单号
        String distributionMark = "PDD";
        
        // 构建"生"指令格式
        StringBuilder sheng = new StringBuilder();
        sheng.append("生\n")
            .append(distributionMark)  // 分销标记：PDD
            .append("\n")
            .append(modelNumber)
            .append("\n")
            .append(jf != null ? jf : "")  // 转链链接
            .append("\n")
            .append("1")  // 数量默认为1
            .append("\n")
            .append(fullAddress.toString());
        
        // 传递第三方单号给 generateOrderText
        return generateOrderText(sheng.toString(), thirdPartyOrderNo);
    }

    private String generateOrderText(String shengInput) {
        return generateOrderText(shengInput, null);
    }
    
    private String generateOrderText(String shengInput, String providedThirdPartyOrderNo) {
        String[] split = shengInput.split("\n");
        // 第一行可能是 生 或 生{备注}
        String head = split[0].trim();
        String remark = head.replace("{生}", "").replace("生", "").replace("\n", "").trim();
        String fenxiao = split[1].trim();
        String model = split[2].trim();
        String link = split[3].trim();
        int num = 1;
        try {
            num = Integer.parseInt(split[4].trim());
        } catch (Exception ignore) {
        }
        String address = split[5].trim();

        // 第一重判断：从分销标记中提取订单编号进行去重（如 JY202510093195）
        // 如果提供了第三方单号，也用于去重判断
        String orderNumberForDedup = providedThirdPartyOrderNo;
        if (orderNumberForDedup == null || orderNumberForDedup.isEmpty()) {
            orderNumberForDedup = extractOrderNumber(fenxiao);
        }
        if (stringRedisTemplate != null && orderNumberForDedup != null && !orderNumberForDedup.isEmpty()) {
            String orderNumberKey = "order_number:" + orderNumberForDedup;
            String existedOrderNumber = stringRedisTemplate.opsForValue().get(orderNumberKey);
            if (existedOrderNumber != null) {
                String warn = "[炸弹] [炸弹] [炸弹] 此订单编号(" + orderNumberForDedup + ")已经存在，请勿重复生成订单 [炸弹] [炸弹] [炸弹] ";
                StringBuilder warnOut = new StringBuilder();
                warnOut.append(warn).append("\n");
                return warnOut.toString().trim();
            }
            // 记录订单编号，24小时过期
            stringRedisTemplate.opsForValue().set(orderNumberKey, orderNumberForDedup, 1, TimeUnit.DAYS);
        }

        // 第二重判断：地址 24 小时去重校验（白名单放行）
        if (stringRedisTemplate != null) {
            String addressKey = "address:" + address;
            String existed = stringRedisTemplate.opsForValue().get(addressKey);
            if (existed != null) {
                if (!(existed.contains("李波") || existed.contains("吴胜硕") || existed.contains("小硕硕"))) {
                    String warn = "[炸弹] [炸弹] [炸弹] 此地址已经存在，请勿重复生成订单 [炸弹] [炸弹] [炸弹] ";
                    StringBuilder warnOut = new StringBuilder();
                    warnOut.append(warn).append("\n");
                    return warnOut.toString().trim();
                }
            }
            stringRedisTemplate.opsForValue().set(addressKey, address, 1, TimeUnit.DAYS);
        }

        String today = new java.text.SimpleDateFormat("yyyy-MM-dd ").format(new Date());
        String todayNoSpace = today.trim();
        String keyWithSpace = "order_count:" + today;      // 带空格
        String keyNoSpace = "order_count:" + todayNoSpace; // 不带空格
        String redisKey = keyNoSpace;
        if (stringRedisTemplate != null) {
            try {
                Boolean noSpaceExists = stringRedisTemplate.hasKey(keyNoSpace);
                Boolean spaceExists = stringRedisTemplate.hasKey(keyWithSpace);
                if (Boolean.TRUE.equals(noSpaceExists)) {
                    redisKey = keyNoSpace;
                } else if (Boolean.TRUE.equals(spaceExists)) {
                    redisKey = keyWithSpace;
                } else {
                    redisKey = keyNoSpace; // 默认使用不带空格
                }
            } catch (Exception ignore) {
                redisKey = keyNoSpace;
            }
        }
        StringBuilder out = new StringBuilder();
        int total = Math.max(1, num);

        int startCount = 1;
        if (stringRedisTemplate != null) {
            try {
                String s = stringRedisTemplate.opsForValue().get(redisKey);
                int count = s != null ? Integer.parseInt(s) : 0;
                startCount = count + 1;
                int endCount = count + total;
                stringRedisTemplate.opsForValue().set(redisKey, String.valueOf(endCount), 30, TimeUnit.DAYS);
            } catch (Exception ignore) {
            }
        }

        // 优先使用提供的第三方单号，如果没有则从分销标记中提取
        String thirdPartyOrderNo = providedThirdPartyOrderNo;
        if (thirdPartyOrderNo == null || thirdPartyOrderNo.isEmpty()) {
            thirdPartyOrderNo = extractOrderNumber(fenxiao);
        }
        String thirdPartyOrderNoValue = (thirdPartyOrderNo != null && !thirdPartyOrderNo.isEmpty()) ? thirdPartyOrderNo : "";
        
        for (int i = 0; i < total; i++) {
            int currentCount = startCount + i;
            String orderId = today + String.format("%03d", currentCount);
            String current = WENAN_D.replace("{单号}", orderId).replace("{单的备注}", remark).replace("{分销标记}", fenxiao).replace("{第三方单号}", thirdPartyOrderNoValue).replace("{链接}", link).replace("{地址}", address).replace("{型号}", model).replaceAll("[|]", "");
            out.append(current);
            if (i < total - 1) out.append("\n");
        }
        return out.toString();
    }

    /**
     * 从分销标记中提取订单编号
     * 例如：从 "H-TF(10.10 	腾锋	JY202510093195)" 中提取 "JY202510093195"
     * 例如：从 "PDD(251102-457567158704072)" 中提取 "251102-457567158704072"
     */
    private String extractOrderNumber(String fenxiao) {
        if (fenxiao == null || fenxiao.isEmpty()) {
            return null;
        }
        // 优先匹配 JY 开头后跟数字的模式（TF订单）
        Pattern jyPattern = Pattern.compile("JY\\d+");
        Matcher jyMatcher = jyPattern.matcher(fenxiao);
        if (jyMatcher.find()) {
            return jyMatcher.group();
        }
        // 匹配拼多多订单号格式：数字-数字（在括号内）
        Pattern pddPattern = Pattern.compile("\\(([\\d-]+)\\)");
        Matcher pddMatcher = pddPattern.matcher(fenxiao);
        if (pddMatcher.find()) {
            String orderNo = pddMatcher.group(1);
            // 验证格式是否为数字-数字（拼多多格式）
            if (orderNo.matches("\\d+-\\d+")) {
                return orderNo;
            }
        }
        return null;
    }

    private String extractChinese(String s) {
        Matcher m = Pattern.compile("[\\u4E00-\\u9FA5]+").matcher(s);
        return m.find() ? m.group() : "";
    }

    private String extractBetweenBrackets(String s) {
        int a = s.indexOf('[');
        int b = s.indexOf(']');
        if (a != -1 && b != -1 && b > a) return s.substring(a + 1, b);
        return "";
    }

    private String extractLastNonChineseToken(String s) {
        String[] tokens = s.split("\\s+");
        String result = "";
        for (String t : tokens) {
            if (!t.matches(".*[\\u4E00-\\u9FA5].*")) result = t;
        }
        return result;
    }

    // ===== 文本清洗 =====
    private String sanitizeModel(String s) {
        if (s == null) return "";
        s = s.replace("\\n", "");
        s = removeNoiseSymbols(s);
        return normalizeWhitespace(s);
    }

    private String sanitizeAddress(String s) {
        if (s == null) return "";
        s = s.replaceAll("\\[.*?]", "");
        s = removeNoiseSymbols(s);
        return normalizeWhitespace(s);
    }

    private String sanitizeLink(String s) {
        if (s == null) return "";
        return normalizeWhitespace(s.trim());
    }

    private String removeNoiseSymbols(String s) {
        // 移除常见噪声：**、*、|（含全角）、零宽字符等
        s = s.replaceAll("\\*+", "");
        s = s.replace("|", "").replace("｜", "");
        s = s.replace("\u200B", "").replace("\uFEFF", "");
        return s;
    }

    private String normalizeWhitespace(String s) {
        return s.replaceAll("[\\t ]+", " ").replaceAll("\n{3,}", "\n\n").trim();
    }

    // ===== “单 …” 写库 =====
    private String handleDanWriteDb(String input) {
        // 保存原始输入，用于返回前端时保留完整物流链接
        String originalInput = input.trim().replace("元", "");
        // 与 JDUtil.parseOrderFromText 一致的模板字段
        JDOrder order = parseOrderFromText(originalInput);

        // 字段校验并返回缺失项
        StringBuilder missing = new StringBuilder();
        if (isEmpty(order.getOrderId())) missing.append("单号\n");
        if (isEmpty(order.getBuyer())) missing.append("下单人\n");
        if (order.getPaymentAmount() == null || order.getPaymentAmount() == 0) missing.append("下单价格\n");
        if (order.getRebateAmount() == null) missing.append("后返金额\n");
        if (isEmpty(order.getLogisticsLink())) missing.append("物流链接\n");
        if (isEmpty(order.getAddress())) missing.append("收货地址\n");
        if (isEmpty(order.getModelNumber())) missing.append("型号\n");
        if (missing.length() > 0) {
            String warn = "[炸弹] [炸弹] [炸弹] 录单警告!!! \n缺少表单字段 \n" + missing;
            return warn;
        }

        // 订单号重复校验
        if (!isEmpty(order.getOrderId())) {
            JDOrder existingByOrderId = jdOrderService.selectJDOrderByOrderId(order.getOrderId());
            if (existingByOrderId != null) {
                // 如果是更新同一条记录（remark相同），则不提示重复
                if (!order.getRemark().equals(existingByOrderId.getRemark())) {
                    String warn = "[炸弹] [炸弹] [炸弹] 录单警告!!! \n订单号重复！\n" + 
                                  "订单号：" + order.getOrderId() + "\n" +
                                  "已存在的订单：" + existingByOrderId.getRemark() + "\n" +
                                  "下单时间：" + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(existingByOrderId.getOrderTime());
                    return warn;
                }
            }
        }

        // 物流链接重复校验
        if (!isEmpty(order.getLogisticsLink())) {
            JDOrder existingByLogistics = jdOrderService.selectJDOrderByLogisticsLink(order.getLogisticsLink());
            if (existingByLogistics != null) {
                // 如果是更新同一条记录（remark相同），则不提示重复
                if (!order.getRemark().equals(existingByLogistics.getRemark())) {
                    String warn = "[炸弹] [炸弹] [炸弹] 录单警告!!! \n物流链接重复！\n" + 
                                  "物流链接：" + order.getLogisticsLink() + "\n" +
                                  "已存在的订单：" + existingByLogistics.getRemark() + "\n" +
                                  "下单时间：" + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(existingByLogistics.getOrderTime());
                    return warn;
                }
            }
        }

        // 地址重复提示（不阻断写入，与 JDUtil 提示一致）
        List<JDOrder> byAddress = jdOrderService.selectJDOrderListByAddress(order.getAddress());
        if (byAddress != null && !byAddress.isEmpty()) {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String latest = sdf.format(byAddress.get(0).getOrderTime());
            // 仅提示
        }

        // 根据订单号查询order_rows，获取京粉实际价格
        OrderRows orderRow = null;
        if (!isEmpty(order.getOrderId())) {
            try {
                orderRow = orderRowsService.selectOrderRowsByOrderId(order.getOrderId());
                if (orderRow != null && orderRow.getEstimateCosPrice() != null) {
                    order.setJingfenActualPrice(orderRow.getEstimateCosPrice());
                }
            } catch (Exception e) {
                // 查询失败不影响主流程，继续执行
            }
        }

        // 验证1：如果查询不到对应订单，提示用户
        if (isEmpty(order.getOrderId()) || orderRow == null) {
            String warn = "[炸弹] [炸弹] [炸弹] 录单警告!!! \n查询不到对应订单（使用红包 或者 转链），请五分钟后再试，或重新下单";
            return warn;
        }

        // 验证2：如果京粉实际价格不为空，检查与付款金额的差值是否大于等于100
        if (order.getJingfenActualPrice() != null && order.getPaymentAmount() != null) {
            double diff = Math.abs(order.getPaymentAmount() - order.getJingfenActualPrice());
            // 如果差额大于等于100，则提示警告
            if (diff >= 100.0) {
                String warn = "[炸弹] [炸弹] [炸弹] 录单警告!!! \n付款金额和实际金额相差" + String.format("%.2f", diff) + "，请联系管理员录单\n" +
                              "付款金额：" + order.getPaymentAmount() + "\n" +
                              "京粉实际价格：" + order.getJingfenActualPrice() + "\n" +
                              "差额：" + String.format("%.2f", diff);
                return warn;
            }
        }

        // 按 remark 判断新增/更新
        JDOrder exists = jdOrderService.selectJDOrderByRemark(order.getRemark());
        if (exists != null) {
            order.setId(exists.getId());
            jdOrderService.updateJDOrder(order);
        } else {
            jdOrderService.insertJDOrder(order);
        }

        // 返回完整的表单格式，使用原始输入保留完整物流链接
        return formatOrderForm(order, originalInput);
    }

    private boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }

    /**
     * 格式化订单为完整表单格式
     * @param order 订单对象
     * @param originalInput 原始输入文本，用于提取完整的物流链接
     */
    private String formatOrderForm(JDOrder order, String originalInput) {
        StringBuilder sb = new StringBuilder();
        
        // 从原始输入中提取完整的物流链接
        String originalLogisticsLink = extractOriginalLogisticsLink(originalInput);
        
        sb.append("单：\n");
        sb.append(order.getRemark() != null ? order.getRemark() : "").append("\n");
        sb.append("备注：").append(order.getStatus() != null ? order.getStatus() : "").append("\n");
        sb.append("分销标记：").append(order.getDistributionMark() != null ? order.getDistributionMark() : "").append("\n");
        sb.append("第三方单号：").append(order.getThirdPartyOrderNo() != null ? order.getThirdPartyOrderNo() : "").append("\n");
        sb.append("型号：\n");
        sb.append(order.getModelNumber() != null ? order.getModelNumber() : "").append("\n");
        sb.append("链接：\n");
        sb.append(order.getLink() != null ? order.getLink() : "").append("\n");
        sb.append("下单付款：\n");
        sb.append(order.getPaymentAmount() != null ? order.getPaymentAmount().toString() : "").append("\n");
        sb.append("后返金额：\n");
        sb.append(order.getRebateAmount() != null ? order.getRebateAmount().toString() : "").append("\n");
        sb.append("地址：\n");
        sb.append(order.getAddress() != null ? order.getAddress() : "").append("\n");
        sb.append("物流链接：\n");
        // 使用原始输入的完整物流链接，如果没有则使用数据库中的值
        sb.append(originalLogisticsLink != null ? originalLogisticsLink : (order.getLogisticsLink() != null ? order.getLogisticsLink() : "")).append("\n");
        sb.append("订单号：\n");
        sb.append(order.getOrderId() != null ? order.getOrderId() : "").append("\n");
        sb.append("下单人：\n");
        sb.append(order.getBuyer() != null ? order.getBuyer() : "").append("\n");
        sb.append("京粉实际价格：\n");
        sb.append(order.getJingfenActualPrice() != null ? order.getJingfenActualPrice().toString() : "").append("\n");
        
        return sb.toString();
    }
    
    /**
     * 从原始输入中提取完整的物流链接文本（不做清理）
     */
    private String extractOriginalLogisticsLink(String input) {
        if (input == null || input.isEmpty()) {
            return null;
        }
        // 提取"物流链接："到"订单号："之间的完整内容
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("物流链接：\\s*(.*?)\\s*(?=订单号：|\\Z)", java.util.regex.Pattern.DOTALL);
        java.util.regex.Matcher matcher = pattern.matcher(input);
        if (matcher.find()) {
            String logisticsLink = matcher.group(1).trim();
            // 如果为空，返回null
            return logisticsLink.isEmpty() ? null : logisticsLink;
        }
        return null;
    }

    // 参照 JDUtil.parseOrderFromText
    private JDOrder parseOrderFromText(String input) {
        // 不要替换所有空格，保留换行符用于正确解析
        Map<String, String> fields = new HashMap<>();
        
        // 先尝试新格式（带第三方单号和京粉实际价格）
        extractField(input, fields, "单：", "备注：");
        extractField(input, fields, "备注：", "分销标记：");
        
        // 检查是否有"第三方单号："字段，如果没有则是旧格式
        boolean hasThirdPartyOrderNo = input.contains("第三方单号：");
        boolean hasJingfenPrice = input.contains("京粉实际价格：");
        
        if (hasThirdPartyOrderNo) {
            // 新格式：有第三方单号字段
            extractField(input, fields, "分销标记：", "第三方单号：");
            extractField(input, fields, "第三方单号：", "型号：");
        } else {
            // 旧格式：分销标记后面直接是型号
            extractField(input, fields, "分销标记：", "型号：");
        }
        
        extractField(input, fields, "型号：", "链接：");
        extractField(input, fields, "链接：", "下单付款：");
        extractField(input, fields, "下单付款：", "后返金额：");
        extractField(input, fields, "后返金额：", "地址：");
        extractField(input, fields, "地址：", "物流链接：");
        extractField(input, fields, "物流链接：", "订单号：");
        extractField(input, fields, "订单号：", "下单人：");
        
        // 京粉实际价格不从表单解析，而是从数据库查询获取
        // 如果表单中有这个字段，也提取出来（但不会使用，仅用于兼容）
        if (hasJingfenPrice) {
            extractField(input, fields, "下单人：", "京粉实际价格：");
            extractField(input, fields, "京粉实际价格：", "");
        } else {
            extractField(input, fields, "下单人：", "");
        }
        
        // 使用正则提取下单人（兼容新旧格式）
        String nextField = hasJingfenPrice ? "京粉实际价格：" : "单：";
        java.util.regex.Pattern buyerPattern = java.util.regex.Pattern.compile("下单人：\\s*(.*?)\\s*(?=" + nextField + "|\\Z)", java.util.regex.Pattern.DOTALL);
        java.util.regex.Matcher buyerMatcher = buyerPattern.matcher(input);
        if (buyerMatcher.find()) {
            String buyer = buyerMatcher.group(1).trim();
            // 如果提取的内容包含换行符，可能是提取过度了，只取第一行
            if (buyer.contains("\n")) {
                buyer = buyer.split("\n")[0].trim();
            }
            fields.put("下单人", buyer);
        }

        JDOrder order = new JDOrder();
        order.setRemark(fields.getOrDefault("单", null));
        
        // 处理分销标记：如果提取的内容包含换行符，说明可能提取过度了，只取第一行
        String distributionMark = fields.getOrDefault("分销标记", null);
        if (distributionMark != null && distributionMark.contains("\n")) {
            // 如果包含换行符，只取第一行，并清理可能的额外内容
            String firstLine = distributionMark.split("\n")[0].trim();
            // 检查第一行是否包含其他字段的关键词（如"型号："），如果有则截断
            if (firstLine.contains("型号：") || firstLine.contains("链接：")) {
                int index = firstLine.indexOf("型号：");
                if (index < 0) index = firstLine.indexOf("链接：");
                if (index > 0) {
                    firstLine = firstLine.substring(0, index).trim();
                }
            }
            distributionMark = firstLine;
        }
        order.setDistributionMark(distributionMark);
        
        // 优先从字段中获取第三方单号，如果没有则从分销标记中提取
        String thirdPartyOrderNo = fields.getOrDefault("第三方单号", null);
        if (thirdPartyOrderNo != null) {
            // 清理换行符和空白字符
            thirdPartyOrderNo = thirdPartyOrderNo.replaceAll("\\s+", "").trim();
        }
        if (thirdPartyOrderNo == null || thirdPartyOrderNo.isEmpty()) {
            if (distributionMark != null && !distributionMark.isEmpty()) {
                thirdPartyOrderNo = extractOrderNumber(distributionMark);
            }
        }
        // 保存第三方单号到订单对象
        order.setThirdPartyOrderNo(thirdPartyOrderNo != null && !thirdPartyOrderNo.trim().isEmpty() ? thirdPartyOrderNo.trim() : null);
        order.setModelNumber(fields.getOrDefault("型号", null));
        order.setLink(fields.getOrDefault("链接", null));
        order.setStatus(fields.getOrDefault("备注", null));
        try {
            order.setPaymentAmount(Double.parseDouble(fields.getOrDefault("下单付款", "0")));
        } catch (Exception ignore) {
        }
        try {
            order.setRebateAmount(Double.parseDouble(fields.getOrDefault("后返金额", "0")));
        } catch (Exception ignore) {
        }
        order.setAddress(fields.getOrDefault("地址", null));
        // 写入数据库时清理物流链接，只保留URL
        order.setLogisticsLink(extractFirstUrl(fields.getOrDefault("物流链接", "")));
        order.setOrderId(fields.getOrDefault("订单号", null));
        order.setBuyer(fields.getOrDefault("下单人", null));
        // 京粉实际价格不从表单解析，而是从数据库order_rows表中查询获取
        // 默认参与统计
        order.setIsCountEnabled(1);
        try {
            String dateStr = fields.getOrDefault("单", "").split(" ")[0];
            java.text.SimpleDateFormat sdf2 = new java.text.SimpleDateFormat("yyyy-MM-dd");
            order.setOrderTime(sdf2.parse(dateStr));
        } catch (Exception e) {
            order.setOrderTime(new Date());
        }
        return order;
    }

    private void extractField(String input, Map<String, String> map, String startKeyword, String endKeyword) {
        // 如果结束关键词为空，匹配到字符串末尾
        String endPattern = endKeyword.isEmpty() ? "\\Z" : endKeyword;
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(startKeyword + "\\s*(.*?)\\s*(?=" + endPattern + ")", java.util.regex.Pattern.DOTALL);
        java.util.regex.Matcher matcher = pattern.matcher(input);
        if (matcher.find()) {
            String value = matcher.group(1).trim();
            // 移除可能的前缀（如果value以startKeyword开头）
            if (value.startsWith(startKeyword)) {
                value = value.substring(startKeyword.length()).trim();
            }
            // 如果值包含换行符，且结束关键词存在，需要确保只取到第一个换行符或结束关键词之前
            if (!endKeyword.isEmpty() && value.contains("\n")) {
                // 检查是否包含结束关键词
                int endIndex = value.indexOf(endKeyword);
                if (endIndex >= 0) {
                    value = value.substring(0, endIndex).trim();
                } else {
                    // 如果找不到结束关键词，取第一个换行符之前的内容
                    value = value.split("\n")[0].trim();
                }
            }
            map.put(startKeyword.replace("：", ""), value);
        }
    }

    private String extractFirstUrl(String text) {
        if (text == null || text.isEmpty()) return null;
        java.util.regex.Pattern urlPattern = java.util.regex.Pattern.compile("(https?://[^\\s]+)");
        java.util.regex.Matcher matcher = urlPattern.matcher(text);
        return matcher.find() ? matcher.group(0) : null;
    }

    private String handleTransferLike(String input) {
        // 前端仍复用已有 /jarvis/jdorder/generatePromotionContent 接口，这里仅提供一个回显占位
        return "指令入口：请在\"一键转链\"页面使用(输入文案/链接后点生成)";
    }

    // ===== 统计与列表渲染 =====
    private String statsText(List<OrderRows> rows, String title) {
        long total = rows.size();
        long paid = rows.stream().filter(o -> Integer.valueOf(16).equals(o.getValidCode())).count();
        long pending = rows.stream().filter(o -> Integer.valueOf(15).equals(o.getValidCode())).count();
        long completed = rows.stream().filter(o -> Integer.valueOf(17).equals(o.getValidCode())).count();
        long canceled = rows.stream().filter(o -> o.getValidCode() != null && o.getValidCode() != 16 && o.getValidCode() != 17).count();
        long violation = rows.stream().filter(o -> o.getValidCode() != null && (o.getValidCode() == 13 || o.getValidCode() == 25 || o.getValidCode() == 26 || o.getValidCode() == 27 || o.getValidCode() == 28 || o.getValidCode() == 29)).count();
        double paidCommission = rows.stream().filter(o -> Integer.valueOf(16).equals(o.getValidCode()) && o.getEstimateFee() != null).mapToDouble(OrderRows::getEstimateFee).sum();
        double pendingCommission = rows.stream().filter(o -> Integer.valueOf(15).equals(o.getValidCode()) && o.getEstimateFee() != null).mapToDouble(OrderRows::getEstimateFee).sum();
        double completedCommission = rows.stream().filter(o -> Integer.valueOf(17).equals(o.getValidCode()) && o.getEstimateFee() != null).mapToDouble(OrderRows::getEstimateFee).sum();
        double violationCommission = rows.stream().filter(o -> o.getValidCode() != null && (o.getValidCode() == 13 || o.getValidCode() == 25 || o.getValidCode() == 26 || o.getValidCode() == 27 || o.getValidCode() == 28 || o.getValidCode() == 29) && o.getEstimateCosPrice() != null && o.getCommissionRate() != null).mapToDouble(o -> o.getEstimateCosPrice() * o.getCommissionRate() * 0.01).sum();

        StringBuilder sb = new StringBuilder();
        sb.append("* ").append(title).append(" *\n").append("━━━━━━━━━━━━\n").append("订单总数：").append(total).append("\n").append("有效订单：").append(total - canceled).append("\n").append("已取消：").append(canceled).append("\n").append("────────────\n").append("已付款：").append(paid).append("\n").append("已付款佣金：").append(fmt(paidCommission)).append("\n").append("────────────\n").append("待付款：").append(pending).append("\n").append("待付款佣金：").append(fmt(pendingCommission)).append("\n").append("────────────\n").append("已完成：").append(completed).append("\n").append("已完成佣金：").append(fmt(completedCommission)).append("\n").append("────────────\n").append("违规订单：").append(violation).append("\n").append("违规佣金：").append(fmt(violationCommission)).append("\n").append("━━━━━━━━━━━━");
        return sb.toString();
    }

    private String listOrders(List<OrderRows> rows, String title) {
        if (rows.isEmpty()) return title + "：无";
        StringBuilder sb = new StringBuilder();
        sb.append(title).append("（").append(rows.size()).append("条）\n");
        int i = 0;
        for (OrderRows r : rows) {
            i++;
            sb.append(i).append(". ").append(Optional.ofNullable(r.getSkuName()).orElse("-")).append(" | 订单号:").append(Optional.ofNullable(r.getOrderId()).map(String::valueOf).orElse("-")).append(" | 时间:").append(fmt(r.getOrderTime())).append(" | 有效:").append(r.getValidCode() == null ? "-" : r.getValidCode()).append("\n");
            if (i >= 100) break; // 最多100条
        }
        return sb.toString();
    }

    // ===== 过滤器 =====
    private List<OrderRows> filterByDays(List<OrderRows> list, int daysBack) {
        LocalDate now = LocalDate.now();
        return list.stream().filter(o -> {
            Date d = o.getOrderTime();
            if (d == null) return false;
            LocalDate od = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            if (daysBack == 0) return od.equals(now);
            return !od.isBefore(now.minusDays(daysBack)) && !od.isAfter(now);
        }).collect(Collectors.toList());
    }

    private List<OrderRows> filterByRange(List<OrderRows> list, int days) {
        return filterByDays(list, days);
    }

    private List<OrderRows> filterYesterday(List<OrderRows> list) {
        LocalDate y = LocalDate.now().minusDays(1);
        return list.stream().filter(o -> {
            Date d = o.getOrderTime();
            if (d == null) return false;
            LocalDate od = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            return od.equals(y);
        }).collect(Collectors.toList());
    }

    private List<OrderRows> filterThisMonth(List<OrderRows> list) {
        LocalDate now = LocalDate.now();
        return list.stream().filter(o -> {
            Date d = o.getOrderTime();
            if (d == null) return false;
            LocalDate od = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            return od.getYear() == now.getYear() && od.getMonth() == now.getMonth();
        }).collect(Collectors.toList());
    }

    private List<OrderRows> filterLastMonth(List<OrderRows> list) {
        LocalDate now = LocalDate.now().minusMonths(1);
        return list.stream().filter(o -> {
            Date d = o.getOrderTime();
            if (d == null) return false;
            LocalDate od = d.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            return od.getYear() == now.getYear() && od.getMonth() == now.getMonth();
        }).collect(Collectors.toList());
    }

    // ===== 工具 =====
    private String jingMenu() {
        StringBuilder content = new StringBuilder();
        content.append("菜单：京+命令，如： 京今日统计\r\n").append("今日统计\r\n").append("昨日统计\r\n").append("七日统计\r\n").append("一个月统计\r\n").append("两个月统计\r\n").append("三个月统计\r\n").append("总统计\r\n").append("这个月统计\r\n").append("上个月统计\r\n").append("\r\n").append("今日订单\r\n").append("昨日订单\r\n").append("七日订单\r\n");
        return content.toString();
    }

    private String helpText() {
        return "可用指令示例：\n" + "1) 京菜单（查看所有可用命令）\n" + "2) 京今日统计 / 京昨日统计 / 京七日统计 / 京一个月统计 等\n" + "3) 京今日订单 / 京昨日订单 / 京七日订单\n" + "4) 慢搜 关键词 / 慢查 关键词（从录单库模糊查询）\n" + "5) 录单20250101-20250107 或 录单昨日|三日|七日（仅查询导出）\n" + "\n提示：转链与礼金请前往‘一键转链’页面使用。";
    }

    private LocalDateTime effectiveToday() {
        LocalDateTime now = LocalDateTime.now();
        if (now.getHour() < 8) return now.minusDays(1);
        return now;
    }

    private List<LocalDate> parseDateRange(String s) {
        if (s == null || s.isEmpty()) return null;
        if ("昨日".equals(s)) {
            LocalDate y = LocalDate.now().minusDays(1);
            return Arrays.asList(y, y);
        }
        if ("三日".equals(s)) {
            LocalDate end = LocalDate.now().minusDays(1);
            LocalDate start = LocalDate.now().minusDays(3);
            return Arrays.asList(start, end);
        }
        if ("七日".equals(s)) {
            LocalDate end = LocalDate.now().minusDays(1);
            LocalDate start = LocalDate.now().minusDays(7);
            return Arrays.asList(start, end);
        }
        Pattern p = Pattern.compile("(\\d{8})(?:-(\\d{8}))?");
        Matcher m = p.matcher(s);
        if (m.find()) {
            LocalDate d1 = parseYmd(m.group(1));
            LocalDate d2 = m.group(2) != null ? parseYmd(m.group(2)) : d1;
            return Arrays.asList(d1, d2);
        }
        return null;
    }

    private LocalDate parseYmd(String ymd) {
        int y = Integer.parseInt(ymd.substring(0, 4));
        int mo = Integer.parseInt(ymd.substring(4, 6));
        int d = Integer.parseInt(ymd.substring(6, 8));
        return LocalDate.of(y, mo, d);
    }

    /**
     * 截取分销标记，如果长度大于4则进行截取
     * @param v 原始分销标记
     * @return 截取后的分销标记
     */
    private String truncateDistributionMark(String v) {
        if (v == null) return "";

        // 如果长度大于4，进行截取
        if (v.length() > 4) {
            // 查找第一个左括号的位置
            int leftParenIndex = v.indexOf('(');
            if (leftParenIndex > 0) {
                // 截取到左括号之前的部分
                return v.substring(0, leftParenIndex);
            } else {
                // 如果没有括号，直接截取前4个字符
                return v.substring(0, 4);
            }
        }

        return v;
    }

    private String mapDistribution(String v) {
        if (v == null) return "";

        String processedV = truncateDistributionMark(v);

        if (processedV.startsWith("H")) return "鸿";
        if (processedV.startsWith("F")) return "凡";
        return "";
    }

    private boolean contains(Object field, String kwLower) {
        if (field == null) return false;
        return String.valueOf(field).toLowerCase(Locale.ROOT).contains(kwLower);
    }

    private String nvl(Object v) {
        return v == null ? "" : String.valueOf(v);
    }

    private String fmt(Object v) {
        if (v == null) return "";
        if (v instanceof Number) {
            return String.format(Locale.ROOT, "%.2f", ((Number) v).doubleValue());
        }
        if (v instanceof Date) {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format((Date) v);
        }
        return String.valueOf(v);
    }
}



