using Microsoft.AspNetCore.Mvc;
using BLL.Interfaces;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System;
using System.Threading.Tasks;
using MDL.Models;
using MDL.DTOs;
using CONTROLLER.Configurations;
using CONTROLLER.Extensions;
using DinkToPdf;
using Microsoft.AspNetCore.Hosting;
using CONTROLLER.Utilities;
using DAL.Interfaces;
using System.IO;

namespace CONTROLLER.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class LabelController : ControllerBase
    {
        private readonly ILabelReplaceService _labelReplaceService;
        private readonly ILabelScanService _labelScanService;
        private readonly ITagTriggerService _tagTriggerService;
        private readonly ITagGenerationService _tagGenerationService;
        private readonly ICustomerRepository _customerRepository;
        private readonly ICustomerApiRepository _customerApiRepository;
        private readonly ILogger<LabelController> _logger;
        private readonly AppSettings _appSettings;
        private readonly IWebHostEnvironment _hostingEnvironment;
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly ILabelPdfCacheService _labelPdfCacheService;
        private readonly ICacheService _cacheService;

        public LabelController(ILabelReplaceService labelReplaceService, ILabelScanService labelScanService, ITagTriggerService tagTriggerService, ITagGenerationService tagGenerationService, ICustomerRepository customerRepository, ICustomerApiRepository customerApiRepository, ILogger<LabelController> logger, AppSettings appSettings, IWebHostEnvironment hostingEnvironment, IHttpClientFactory httpClientFactory, ILabelPdfCacheService labelPdfCacheService, ICacheService cacheService)
        {
            _labelReplaceService = labelReplaceService;
            _labelScanService = labelScanService;
            _tagTriggerService = tagTriggerService;
            _tagGenerationService = tagGenerationService;
            _customerRepository = customerRepository;
            _customerApiRepository = customerApiRepository;
            _logger = logger;
            _appSettings = appSettings;
            _hostingEnvironment = hostingEnvironment;
            _httpClientFactory = httpClientFactory;
            _labelPdfCacheService = labelPdfCacheService;
            _cacheService = cacheService;
        }

        private async Task<CustomerEntity?> GetCustomerWithCacheAsync(int customerId)
        {
            var cacheKey = $"customer:{customerId}";
            var cached = await _cacheService.GetAsync<CustomerEntity>(cacheKey);
            if (cached != null) return cached;

            var customer = await _customerRepository.GetByIdAsync(customerId);
            if (customer != null)
                await _cacheService.SetAsync(cacheKey, customer, expirationMinutes: 10);
            return customer;
        }

        /// <summary>
        /// 根据跟踪单号获取标签替换请求记录
        /// </summary>
        [HttpGet("label-replace/tracking/{trackingNumber}")]
        public async Task<IActionResult> GetLabelReplaceByTrackingNumber(string trackingNumber)
        {
            try
            {
                if (string.IsNullOrEmpty(trackingNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Tracking number is required"
                    });
                }

                _logger.LogInformation("Received request to get label replace by tracking number: {number}", trackingNumber);

                // 调用服务获取标签替换记录
                var requests = await _labelReplaceService.GetLabelReplaceRequestsByTrackingNumberAsync(trackingNumber);

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    trackingNumber = trackingNumber,
                    count = requests.Count,
                    data = requests
                };

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving label replace requests by tracking number");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 根据中性面单单号获取标签替换请求记录
        /// </summary>
        [HttpGet("label-replace/waybill/{waybillNumber}")]
        public async Task<IActionResult> GetLabelReplaceByWaybillNumber(string waybillNumber)
        {
            try
            {
                if (string.IsNullOrEmpty(waybillNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                _logger.LogInformation("Received request to get label replace by waybill number: {number}", waybillNumber);

                // 调用服务获取标签替换记录
                var request = await _labelReplaceService.GetLabelReplaceRequestByWaybillNumberAsync(waybillNumber);

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    waybillNumber = waybillNumber,
                    data = request
                };

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving label replace request by waybill number");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 根据中性面单单号获取标签文件并返回字节流
        /// </summary>
        [HttpGet("label-replace/waybill/{waybillNumber}/download")]
        public async Task<IActionResult> DownloadLabelByWaybillNumber(string waybillNumber)
       {
            // 初始化变量
            LabelReplaceEntity? request = null;
            ScanResult scanResult = ScanResult.NoLabelData;
            string scanDescription = "自动记录的标签下载扫描";
            int customerId = 0;
            string? referenceNumber = null;
            string? finalMileTrackingNumber = null;
            string? label = null;
            string caller = "system";
            string? deviceCode = HttpContext.GetDeviceCode();
            string? deviceName = HttpContext.GetDeviceName();
            DateTime scanTime = DateTime.UtcNow; // 扫描进入方法的时间
            DateTime? printTime = null; // 获取到pdf结果的时间

            try
            {
                if (string.IsNullOrEmpty(waybillNumber))
                {
                    return BadRequest(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                // 处理420开头的USPS单号特殊字符
                if (waybillNumber.StartsWith("420"))
                {
                    // 去除所有空白字符
                    char[] whitespaceChars = { ' ', '\t', '\n', '\r', '\u001d' };
                    waybillNumber = waybillNumber.Trim(whitespaceChars);
                    // 去除特殊字符（如运单号中的分隔符，ASCII 29和其他特殊字符）
                    char specialChar = (char)29;
                    waybillNumber = waybillNumber.Replace(specialChar.ToString(), "");
                    // 去除其他特殊字符，如↔
                    waybillNumber = waybillNumber.Replace("↔", "");
                }

               

                _logger.LogInformation("Received request to download label by waybill number: {number}", waybillNumber);

                caller = HttpContext.GetCaller();
                _logger.LogInformation("[Caller: {Caller}] DownloadLabel, WaybillNumber: {WaybillNumber}", caller, waybillNumber);

                // 创建取消令牌源，设置超时时间
                using var cts = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(_appSettings.ApiSettings.InterfaceTimeout));
                var token = cts.Token;

                try
                {
                    // 调用服务获取标签替换记录 todo:并且没有被扫描过的记录的情况下返回
                    request = await _labelReplaceService.GetLabelReplaceRequestByWaybillNumberAsync(waybillNumber);

                    if (request == null)
                    {
                        scanResult = ScanResult.NoOrderData;
                        scanDescription = "未找到对应的标签替换记录";
                        return Ok(new
                        {
                            status = "error",
                            message = "Label replace request not found for the provided waybill number"
                        });
                    }

                    // 从标签替换记录中获取客户ID和其他信息
                    customerId = request.CustomerId ?? 0;
                    referenceNumber = request.ReferenceNumber;
                    finalMileTrackingNumber = request.FinalMileTrackingNumber;



                    // 检查订单是否被冻结
                    if (request.ReplaceStatus == "N")
                    {
                        scanResult = ScanResult.OrderFrozen;
                        scanDescription = "订单被冻结，无法下载面单";

                        // 当订单处于冻结状态时，触发STOP标签
                        string htmlContent = string.Empty;
                        try
                        {
                            // 读取HTML模板文件
                            string templatePath = Path.Combine(_hostingEnvironment.ContentRootPath, "..", "stop_label_preview.html");
                            string htmlTemplate = System.IO.File.ReadAllText(templatePath);

                            // 生成条形码的Base64编码
                            string barcodeContent = await _tagGenerationService.GenerateBarcodeAsync(waybillNumber);

                            // 根据客户ID获取客户代码
                            string customerCode = "UNKNOWN";
                            if (customerId > 0)
                            {
                                var customer = await _customerRepository.GetByIdAsync(customerId);
                                if (customer != null)
                                {
                                    customerCode = customer.CustomerCode;
                                }
                            }

                            // 替换模板中的硬编码值为实际的STOP标签数据
                            htmlTemplate = htmlTemplate.Replace("1234567890", waybillNumber);
                            htmlTemplate = htmlTemplate.Replace("3PE", customerCode);
                            htmlTemplate = htmlTemplate.Replace("2026-02-02 10:00:00", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                            htmlTemplate = htmlTemplate.Replace("ACTIVE", "ACTIVE");

                            // 当订单处于冻结状态时，添加STOP触发原因
                            string stopReason = "<p class=\"tag-info\">STOP触发原因: 取消换单，已达到换单要求仍失败</p>";
                            htmlTemplate = htmlTemplate.Replace("{{stopReason}}", stopReason);

                            // 替换模板中的条形码为base64编码的图片
                            htmlTemplate = htmlTemplate.Replace("{{barcodeBase64}}", barcodeContent);

                            htmlContent = htmlTemplate;
                            _logger.LogInformation("STOP label template loaded and variables replaced successfully");
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Error loading STOP label template file");
                            // 如果加载模板文件出错，使用默认HTML
                            htmlContent = $@"<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>STOP标签</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        h1 {{ color: #333; }}
        .container {{ max-width: 800px; margin: 0 auto; }}
        .info {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; }}
        .barcode {{ margin: 20px 0; padding: 10px; background-color: #f5f5f5; }}
        table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #f2f2f2; }}
    </style>
</head>
<body>
    <div class='container'>
        <h1>STOP标签</h1>
        <div class='info'>
            <table>
                <tr>
                    <th>项目</th>
                    <th>值</th>
                </tr>
                <tr>
                    <td>中性单号</td>
                    <td>{waybillNumber}</td>
                </tr>
                <tr>
                    <td>客户ID</td>
                    <td>{customerId}</td>
                </tr>
                <tr>
                    <td>触发时间</td>
                    <td>{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}</td>
                </tr>
                <tr>
                    <td>标签状态</td>
                    <td>ACTIVE</td>
                </tr>
                <tr>
                    <td>STOP触发原因</td>
                    <td>取消换单，已达到换单要求仍失败</td>
                </tr>
            </table>
        </div>
        <div class='barcode'>
            <h3>条形码</h3>
            <p>{waybillNumber}</p>
        </div>
    </div>
</body>
</html>";
                        }

                        // 转换HTML为PDF
                        var doc = new HtmlToPdfDocument()
                        {
                            GlobalSettings = {
                        ColorMode = DinkToPdf.ColorMode.Color,
                        Orientation = DinkToPdf.Orientation.Portrait,
                        //PaperSize = DinkToPdf.PaperKind.A5,
                        PaperSize =new PechkinPaperSize("100","150"),
                    },
                            Objects = {
                        new ObjectSettings() {
                            PagesCount = true,
                            HtmlContent = htmlContent,
                            WebSettings = { DefaultEncoding = "utf-8" }
                        }
                    }
                        };

                        var converter = PdfConverterSingleton.Instance;
                        byte[] stopLabelBytes = converter.Convert(doc);

                        // 设置printTime为获取到PDF结果的时间
                        printTime = null;

                        // 返回STOP标签PDF
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功返回STOP标签";

                        var stopLabelFileName = $"stop_label_{waybillNumber}.pdf";
                        return File(stopLabelBytes, "application/pdf", stopLabelFileName);
                    }

                    // 标签模块判断逻辑：检查是否需要触发STOP标签
                    try
                    {
                        var triggerCheckDTO = new TriggerCheckDTO
                        {
                            ScanCode = waybillNumber,
                            ScanType = "DOWNLOAD",
                            Location = "SYSTEM",
                            ScanTime = DateTime.UtcNow,
                            Label=label
                        };

                        // 检查是否需要触发标签
                        var shouldTrigger = await _tagTriggerService.CheckTriggerAsync(triggerCheckDTO);

                        if (shouldTrigger)
                        {
                            string htmlContent = string.Empty;
                            try
                            {
                                // 读取HTML模板文件
                                string templatePath = Path.Combine(_hostingEnvironment.ContentRootPath, "..", "stop_label_preview.html");
                                string htmlTemplate = System.IO.File.ReadAllText(templatePath);

                                // 生成条形码的Base64编码
                                string barcodeContent = await _tagGenerationService.GenerateBarcodeAsync(waybillNumber);

                                // 根据客户ID获取客户代码
                                string customerCode = "UNKNOWN";
                                if (customerId > 0)
                                {
                                    var customer = await _customerRepository.GetByIdAsync(customerId);
                                    if (customer != null)
                                    {
                                        customerCode = customer.CustomerCode;
                                    }
                                }

                                // 替换模板中的硬编码值为实际的STOP标签数据
                                htmlTemplate = htmlTemplate.Replace("1234567890", waybillNumber);
                                htmlTemplate = htmlTemplate.Replace("3PE", customerCode);
                                htmlTemplate = htmlTemplate.Replace("2026-02-02 10:00:00", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                                htmlTemplate = htmlTemplate.Replace("ACTIVE", "ACTIVE");

                                // 非冻结状态下，不添加STOP触发原因
                                htmlTemplate = htmlTemplate.Replace("{{stopReason}}", "");

                                // 替换模板中的条形码为base64编码的图片
                                htmlTemplate = htmlTemplate.Replace("{{barcodeBase64}}", barcodeContent);

                                htmlContent = htmlTemplate;
                                _logger.LogInformation("STOP label template loaded and variables replaced successfully");
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(ex, "Error loading STOP label template file");
                                // 如果加载模板文件出错，使用默认HTML
                                htmlContent = $@"<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>STOP标签</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        h1 {{ color: #333; }}
        .container {{ max-width: 800px; margin: 0 auto; }}
        .info {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; }}
        .barcode {{ margin: 20px 0; padding: 10px; background-color: #f5f5f5; }}
        table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #f2f2f2; }}
    </style>
</head>
<body>
    <div class='container'>
        <h1>STOP标签</h1>
        <div class='info'>
            <table>
                <tr>
                    <th>项目</th>
                    <th>值</th>
                </tr>
                <tr>
                    <td>中性单号</td>
                    <td>{waybillNumber}</td>
                </tr>
                <tr>
                    <td>客户ID</td>
                    <td>{customerId}</td>
                </tr>
                <tr>
                    <td>触发时间</td>
                    <td>{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}</td>
                </tr>
                <tr>
                    <td>标签状态</td>
                    <td>ACTIVE</td>
                </tr>
            </table>
        </div>
        <div class='barcode'>
            <h3>条形码</h3>
            <p>{waybillNumber}</p>
        </div>
    </div>
</body>
</html>";
                            }

                            // 转换HTML为PDF
                            var doc = new HtmlToPdfDocument()
                            {
                                GlobalSettings = {
                            ColorMode = DinkToPdf.ColorMode.Color,
                            Orientation = DinkToPdf.Orientation.Portrait,
                            //PaperSize = DinkToPdf.PaperKind.A5,
                            PaperSize =new PechkinPaperSize("100","150"),
                        },
                                Objects = {
                            new ObjectSettings() {
                                PagesCount = true,
                                HtmlContent = htmlContent,
                                WebSettings = { DefaultEncoding = "utf-8" }
                            }
                        }
                            };

                            var converter = PdfConverterSingleton.Instance;
                            byte[] stopLabelBytes = converter.Convert(doc);

                            // 设置printTime为获取到PDF结果的时间
                            printTime = null;

                            // 返回STOP标签PDF
                            scanResult = ScanResult.ReturnedLabel;
                            scanDescription = "成功返回STOP标签";

                            var stopLabelFileName = $"stop_label_{waybillNumber}.pdf";
                            return File(stopLabelBytes, "application/pdf", stopLabelFileName);
                        }
                    }
                    catch (Exception ex)
                    {
                        // 标签模块异常不影响主流程，记录日志后继续执行
                        _logger.LogWarning(ex, "Error checking tag trigger for waybill number: {number}", waybillNumber);
                    }

                    if (string.IsNullOrEmpty(request.Label))
                    {
                        scanResult = ScanResult.NoLabelData;
                        scanDescription = "标签数据不可用";
                        return Ok(new
                        {
                            status = "error",
                            message = "Label data is not available for the request"
                        });
                    }

                    // 新增：先查询缓存
                    var cache = await _labelPdfCacheService.GetValidCacheAsync(waybillNumber);
                    if (cache != null && cache.PdfBytes != null)
                    {
                        _logger.LogInformation("Hit PDF cache for waybill: {number}", waybillNumber);
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功下载缓存标签";
                        printTime = DateTime.UtcNow;
                        return File(cache.PdfBytes, "application/pdf", $"label_{waybillNumber}.pdf");
                    }

                    byte[] labelBytes;

                    // 判断标签数据是base64编码还是URL
                    if (request.Label.StartsWith("data:"))
                    {
                        // 处理base64编码的data URL
                        var base64Data = request.Label.Substring(request.Label.IndexOf(",") + 1);
                        // 使用更高效的base64解码
                        labelBytes = Convert.FromBase64String(base64Data);
                    }
                    else if (request.Label.StartsWith("http://") || request.Label.StartsWith("https://"))
                    {
                        // 处理URL，下载文件，设置超时时间
                        using var httpClient = new HttpClient();
                        httpClient.Timeout = TimeSpan.FromSeconds(_appSettings.ApiSettings.LabelDownloadTimeout);
                        labelBytes = await httpClient.GetByteArrayAsync(request.Label, token);
                    }
                    else
                    {
                        // 假设是纯base64编码
                        try
                        {
                            // 使用更高效的base64解码
                            labelBytes = Convert.FromBase64String(request.Label);
                        }
                        catch (FormatException)
                        {
                            scanResult = ScanResult.NoLabelData;
                            scanDescription = "标签数据格式无效";
                            return Ok(new
                            {
                                status = "error",
                                message = "Label data format is invalid. Expected base64 encoded data or URL."
                            });
                        }
                    }

                    // 设置printTime为获取到PDF结果的时间
                    printTime = DateTime.UtcNow;

                    // 校验PDF页数
                    try
                    {
                        int pageCount = GetPdfPageCount(labelBytes);
                        if (pageCount > 1)
                        {
                            scanResult = ScanResult.Other;
                            scanDescription = $"PDF页数不符合要求，实际页数: {pageCount}";
                            return Ok(new
                            {
                                status = "error",
                                message = $"PDF页数不符合要求，当前页数: {pageCount}，要求: 1页"
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "PDF页数读取失败 for waybill number: {number}", waybillNumber);
                        scanResult = ScanResult.Other;
                        scanDescription = "PDF页数读取失败";
                        return Ok(new
                        {
                            status = "error",
                            message = "PDF页数读取失败"
                        });
                    }

                    // 检查PDF字节流大小是否异常（大于1500000）
                    if (labelBytes.Length > 1500000)
                    {
                        // 面单大小异常，记录为其他
                        scanResult = ScanResult.Other;
                        scanDescription = $"面单大小异常，字节大小: {labelBytes.Length}";
                    }
                    else
                    {
                        // 成功找到并处理标签，设置扫描结果为已返回面单
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功下载标签";
                        
                        // 改进方案v2.0：分离缓存和条码识别
                        var pageCount = GetPdfPageCount(labelBytes);
                        
                        // 第一步：同步保存核心缓存数据（立即返回，不等待）
                        try
                        {
                            await _labelPdfCacheService.SaveCacheAsync(
                                waybillNumber: waybillNumber,
                                pdfBytes: labelBytes,
                                pageCount: pageCount,
                                fileSize: labelBytes.Length,
                                originalUrl: request.Label,
                                finalMileTrackingNumber: finalMileTrackingNumber,
                                customerId: customerId);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "Failed to save PDF cache for waybill: {number}", waybillNumber);
                        }
                        
                        // 第二步：异步条码识别（后台执行，不阻塞用户）
                        _ = Task.Run(async () => 
                        {
                            try
                            {
                                // 条码识别
                                var (barcodeNumber, barcodeType, barcodeConfidence) = await _labelPdfCacheService.ExtractBarcodeFromPdfAsync(labelBytes);
                                
                                if (!string.IsNullOrEmpty(barcodeNumber))
                                {
                                    // 异步更新条码信息到已保存的缓存
                                    await _labelPdfCacheService.SaveCacheAsync(
                                        waybillNumber: waybillNumber,
                                        pdfBytes: labelBytes,
                                        pageCount: pageCount,
                                        fileSize: labelBytes.Length,
                                        originalUrl: request.Label,
                                        finalMileTrackingNumber: finalMileTrackingNumber,
                                        customerId: customerId,
                                        barcodeNumber: barcodeNumber,
                                        barcodeType: barcodeType,
                                        barcodeConfidence: barcodeConfidence);
                                }
                            }
                            catch (Exception ex)
                            {
                                _logger.LogWarning(ex, "Barcode extraction failed (PDF cache already saved) for waybill: {number}", waybillNumber);
                            }
                        });
                    }

                    // 设置响应头
                    var fileName = $"label_{request.NeutralWaybillNumber}.pdf";
                    return File(labelBytes, "application/pdf", fileName);
                }
                catch (OperationCanceledException)
                {
                    // 任务超时
                    scanResult = ScanResult.Other;
                    scanDescription = "处理标签下载请求超时";
                    _logger.LogWarning("Label download request timed out for waybill number: {number}", waybillNumber);

                    // 返回空字节流
                    return File(Array.Empty<byte>(), "application/pdf", $"label_{waybillNumber}.pdf");
                }
            }
            catch (HttpRequestException ex)
            {
                scanResult = ScanResult.Other;
                scanDescription = "下载标签时发生HTTP错误: " + ex.Message;

                _logger.LogError(ex, "Error downloading label from URL");
                return Ok(new
                {
                    status = "error",
                    message = "Failed to download label from URL: " + ex.Message
                });
            }
            catch (Exception ex)
            {
                scanResult = ScanResult.Other;
                scanDescription = "处理标签下载请求时发生错误: " + ex.Message;

                _logger.LogError(ex, "Error processing label download request");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during label download.",
                    errorDetails = ex.Message
                });
            }
            finally
            {
                var capturedCustomerId = customerId;
                var capturedWaybillNumber = waybillNumber;
                var capturedScanResult = scanResult;
                var capturedReferenceNumber = referenceNumber;
                var capturedFinalMile = finalMileTrackingNumber;
                var capturedScanDescription = scanDescription;
                var capturedScanTime = scanTime;
                var capturedPrintTime = printTime;
                var capturedCaller = caller;
                var capturedDeviceCode = deviceCode;
                var capturedDeviceName = deviceName;

                _ = Task.Run(async () =>
                {
                    try
                    {
                        await _labelScanService.RecordScanAsync(
                            customerId: capturedCustomerId,
                            neutralWaybillNumber: capturedWaybillNumber,
                            result: capturedScanResult,
                            createdBy: capturedCaller,
                            referenceNumber: capturedReferenceNumber,
                            finalMileTrackingNumber: capturedFinalMile,
                            description: capturedScanDescription,
                            deviceCode: capturedDeviceCode,
                            deviceName: capturedDeviceName
                        );
                        _logger.LogInformation("Recorded scan with result {result} for waybill number: {number}", capturedScanResult, capturedWaybillNumber);
                    }
                    catch (Exception scanEx)
                    {
                        _logger.LogWarning(scanEx, "Failed to record scan for waybill number: {number}", capturedWaybillNumber);
                    }
                });

                if (customerId > 0)
                {
                    try
                    {
                        var customer = await GetCustomerWithCacheAsync(capturedCustomerId);
                        if (customer != null)
                        {
                            _ = Task.Run(async () =>
                            {
                                try
                                {
                                    if (customer.CustomerCode == "PT_GZ")
                                    {
                                        await SendWebhookToPatuen(capturedWaybillNumber, capturedScanTime, capturedPrintTime);
                                    }
                                    else if (customer.CustomerCode == "ZY_SH")
                                    {
                                        await SendWebhookToZunYou(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedFinalMile);
                                    }
                                    else if (customer.CustomerCode == "XT_JX")
                                    {
                                        await SendWebhookToXunTong(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                    else if (customer.CustomerCode == "IDI_ZJ")
                                    {
                                        await SendWebhookToIDI(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                    else if (customer.CustomerCode == "WEM_ZJ")
                                    {
                                        await SendWebhookToWEM(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                    else if (customer.CustomerCode == "ZYT_GZ")
                                    {
                                        await SendWebhookToZYT(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                    else if (customer.CustomerCode == "BDGJ_YW")
                                    {
                                        await SendWebhookToBDGJ(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _logger.LogError(ex, "Error sending webhook for waybill number: {number}", capturedWaybillNumber);
                                }
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to get customer info for webhook notification, waybill number: {number}", capturedWaybillNumber);
                    }
                }
            }
        }


        [HttpGet("label-replace/waybill/{waybillNumber}/download/v2")]
        public async Task<IActionResult> DownloadLabelByWaybillNumberV2(string waybillNumber)
        {
            LabelReplaceEntity? request = null;
            ScanResult scanResult = ScanResult.NoLabelData;
            string scanDescription = "自动记录的标签下载扫描";
            int customerId = 0;
            string? referenceNumber = null;
            string? finalMileTrackingNumber = null;
            string? label = null;
            string caller = "system";
            string? deviceCode = HttpContext.GetDeviceCode();
            string? deviceName = HttpContext.GetDeviceName();
            DateTime scanTime = DateTime.UtcNow;
            DateTime? printTime = null;

            try
            {
                if (string.IsNullOrEmpty(waybillNumber))
                {
                    return BadRequest(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                if (waybillNumber.StartsWith("420"))
                {
                    char[] whitespaceChars = { ' ', '\t', '\n', '\r', '\u001d' };
                    waybillNumber = waybillNumber.Trim(whitespaceChars);
                    char specialChar = (char)29;
                    waybillNumber = waybillNumber.Replace(specialChar.ToString(), "");
                    waybillNumber = waybillNumber.Replace("↔", "");
                }

                _logger.LogInformation("Received request to download label by waybill number (v2): {number}", waybillNumber);

                caller = HttpContext.GetCaller();
                _logger.LogInformation("[Caller: {Caller}] DownloadLabelV2, WaybillNumber: {WaybillNumber}", caller, waybillNumber);

                using var cts = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(_appSettings.ApiSettings.InterfaceTimeout));
                var token = cts.Token;

                try
                {
                    // 并行查询订单记录和PDF缓存，消除串行等待
                    var requestTask = _labelReplaceService.GetLabelReplaceRequestByWaybillNumberAsync(waybillNumber);
                    var cacheTask = _labelPdfCacheService.GetValidCacheAsync(waybillNumber, null);
                    await Task.WhenAll(requestTask, cacheTask);

                    request = requestTask.Result;
                    var cache = cacheTask.Result;

                    if (request == null)
                    {
                        scanResult = ScanResult.NoOrderData;
                        scanDescription = "未找到对应的标签替换记录";
                        return Ok(new
                        {
                            status = "error",
                            message = "Label replace request not found for the provided waybill number"
                        });
                    }

                    customerId = request.CustomerId ?? 0;
                    referenceNumber = request.ReferenceNumber;
                    finalMileTrackingNumber = request.FinalMileTrackingNumber;

                    if (request.ReplaceStatus == "N")
                    {
                        scanResult = ScanResult.OrderFrozen;
                        scanDescription = "订单被冻结，无法下载面单";

                        string htmlContent = string.Empty;
                        try
                        {
                            string templatePath = Path.Combine(_hostingEnvironment.ContentRootPath, "..", "stop_label_preview.html");
                            string htmlTemplate = System.IO.File.ReadAllText(templatePath);

                            string barcodeContent = await _tagGenerationService.GenerateBarcodeAsync(waybillNumber);

                            string customerCode = "UNKNOWN";
                            if (customerId > 0)
                            {
                                var customer = await GetCustomerWithCacheAsync(customerId);
                                if (customer != null)
                                {
                                    customerCode = customer.CustomerCode;
                                }
                            }

                            htmlTemplate = htmlTemplate.Replace("1234567890", waybillNumber);
                            htmlTemplate = htmlTemplate.Replace("3PE", customerCode);
                            htmlTemplate = htmlTemplate.Replace("2026-02-02 10:00:00", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                            htmlTemplate = htmlTemplate.Replace("ACTIVE", "ACTIVE");

                            string stopReason = "<p class=\"tag-info\">STOP触发原因: 取消换单，已达到换单要求仍失败</p>";
                            htmlTemplate = htmlTemplate.Replace("{{stopReason}}", stopReason);
                            htmlTemplate = htmlTemplate.Replace("{{barcodeBase64}}", barcodeContent);

                            htmlContent = htmlTemplate;
                            _logger.LogInformation("STOP label template loaded and variables replaced successfully");
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Error loading STOP label template file");
                            htmlContent = $@"<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>STOP标签</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        h1 {{ color: #333; }}
        .container {{ max-width: 800px; margin: 0 auto; }}
        .info {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; }}
        .barcode {{ margin: 20px 0; padding: 10px; background-color: #f5f5f5; }}
        table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #f2f2f2; }}
    </style>
</head>
<body>
    <div class='container'>
        <h1>STOP标签</h1>
        <div class='info'>
            <table>
                <tr>
                    <th>项目</th>
                    <th>值</th>
                </tr>
                <tr>
                    <td>中性单号</td>
                    <td>{waybillNumber}</td>
                </tr>
                <tr>
                    <td>客户ID</td>
                    <td>{customerId}</td>
                </tr>
                <tr>
                    <td>触发时间</td>
                    <td>{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}</td>
                </tr>
                <tr>
                    <td>标签状态</td>
                    <td>ACTIVE</td>
                </tr>
                <tr>
                    <td>STOP触发原因</td>
                    <td>取消换单，已达到换单要求仍失败</td>
                </tr>
            </table>
        </div>
        <div class='barcode'>
            <h3>条形码</h3>
            <p>{waybillNumber}</p>
        </div>
    </div>
</body>
</html>";
                        }

                        var stopDoc = new HtmlToPdfDocument()
                        {
                            GlobalSettings = {
                                ColorMode = DinkToPdf.ColorMode.Color,
                                Orientation = DinkToPdf.Orientation.Portrait,
                                PaperSize = new PechkinPaperSize("100","150"),
                            },
                            Objects = {
                                new ObjectSettings() {
                                    PagesCount = true,
                                    HtmlContent = htmlContent,
                                    WebSettings = { DefaultEncoding = "utf-8" }
                                }
                            }
                        };

                        var stopConverter = PdfConverterSingleton.Instance;
                        byte[] stopLabelBytes = stopConverter.Convert(stopDoc);

                        printTime = null;
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功返回STOP标签";

                        var stopLabelFileName = $"stop_label_{waybillNumber}.pdf";
                        return File(stopLabelBytes, "application/pdf", stopLabelFileName);
                    }

                    // 缓存命中直接返回（此时 request.Label 空与否均不影响缓存路径）
                    if (cache != null && cache.PdfBytes != null)
                    {
                        _logger.LogInformation("Hit PDF cache for waybill (v2): {number}", waybillNumber);
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功下载缓存标签";
                        printTime = DateTime.UtcNow;
                        return File(cache.PdfBytes, "application/pdf", $"label_{waybillNumber}.pdf");
                    }

                    if (string.IsNullOrEmpty(request.Label))
                    {
                        scanResult = ScanResult.NoLabelData;
                        scanDescription = "标签数据不可用";
                        return Ok(new
                        {
                            status = "error",
                            message = "Label data is not available for the request"
                        });
                    }

                    label = request.Label;

                    // 检查触发器（此时 label 已有真实值）
                    try
                    {
                        var triggerCheckDTO = new TriggerCheckDTO
                        {
                            ScanCode = waybillNumber,
                            ScanType = "DOWNLOAD",
                            Location = "SYSTEM",
                            ScanTime = DateTime.UtcNow,
                            Label = label
                        };

                        var shouldTrigger = await _tagTriggerService.CheckTriggerAsync(triggerCheckDTO);

                        if (shouldTrigger)
                        {
                            string htmlContent = string.Empty;
                            try
                            {
                                string templatePath = Path.Combine(_hostingEnvironment.ContentRootPath, "..", "stop_label_preview.html");
                                string htmlTemplate = System.IO.File.ReadAllText(templatePath);

                                string barcodeContent = await _tagGenerationService.GenerateBarcodeAsync(waybillNumber);

                                string customerCode = "UNKNOWN";
                                if (customerId > 0)
                                {
                                    var customer = await GetCustomerWithCacheAsync(customerId);
                                    if (customer != null)
                                    {
                                        customerCode = customer.CustomerCode;
                                    }
                                }

                                htmlTemplate = htmlTemplate.Replace("1234567890", waybillNumber);
                                htmlTemplate = htmlTemplate.Replace("3PE", customerCode);
                                htmlTemplate = htmlTemplate.Replace("2026-02-02 10:00:00", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                                htmlTemplate = htmlTemplate.Replace("ACTIVE", "ACTIVE");
                                htmlTemplate = htmlTemplate.Replace("{{stopReason}}", "");
                                htmlTemplate = htmlTemplate.Replace("{{barcodeBase64}}", barcodeContent);

                                htmlContent = htmlTemplate;
                                _logger.LogInformation("STOP label template loaded and variables replaced successfully");
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError(ex, "Error loading STOP label template file");
                                htmlContent = $@"<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>STOP标签</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        h1 {{ color: #333; }}
        .container {{ max-width: 800px; margin: 0 auto; }}
        .info {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; }}
        .barcode {{ margin: 20px 0; padding: 10px; background-color: #f5f5f5; }}
        table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #f2f2f2; }}
    </style>
</head>
<body>
    <div class='container'>
        <h1>STOP标签</h1>
        <div class='info'>
            <table>
                <tr>
                    <th>项目</th>
                    <th>值</th>
                </tr>
                <tr>
                    <td>中性单号</td>
                    <td>{waybillNumber}</td>
                </tr>
                <tr>
                    <td>客户ID</td>
                    <td>{customerId}</td>
                </tr>
                <tr>
                    <td>触发时间</td>
                    <td>{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}</td>
                </tr>
                <tr>
                    <td>标签状态</td>
                    <td>ACTIVE</td>
                </tr>
            </table>
        </div>
        <div class='barcode'>
            <h3>条形码</h3>
            <p>{waybillNumber}</p>
        </div>
    </div>
</body>
</html>";
                            }

                            var trigDoc = new HtmlToPdfDocument()
                            {
                                GlobalSettings = {
                                    ColorMode = DinkToPdf.ColorMode.Color,
                                    Orientation = DinkToPdf.Orientation.Portrait,
                                    PaperSize = new PechkinPaperSize("100","150"),
                                },
                                Objects = {
                                    new ObjectSettings() {
                                        PagesCount = true,
                                        HtmlContent = htmlContent,
                                        WebSettings = { DefaultEncoding = "utf-8" }
                                    }
                                }
                            };

                            var trigConverter = PdfConverterSingleton.Instance;
                            byte[] trigStopBytes = trigConverter.Convert(trigDoc);

                            printTime = null;
                            scanResult = ScanResult.ReturnedLabel;
                            scanDescription = "成功返回STOP标签";

                            var trigStopFileName = $"stop_label_{waybillNumber}.pdf";
                            return File(trigStopBytes, "application/pdf", trigStopFileName);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Error checking tag trigger for waybill number: {number}", waybillNumber);
                    }

                    byte[] labelBytes;

                    if (label.StartsWith("data:"))
                    {
                        var base64Data = label.Substring(label.IndexOf(",") + 1);
                        labelBytes = Convert.FromBase64String(base64Data);
                    }
                    else if (label.StartsWith("http://") || label.StartsWith("https://"))
                    {
                        using var httpClient = _httpClientFactory.CreateClient();
                        httpClient.Timeout = TimeSpan.FromSeconds(_appSettings.ApiSettings.LabelDownloadTimeout);
                        labelBytes = await httpClient.GetByteArrayAsync(label, token);
                    }
                    else
                    {
                        try
                        {
                            labelBytes = Convert.FromBase64String(label);
                        }
                        catch (FormatException)
                        {
                            scanResult = ScanResult.NoLabelData;
                            scanDescription = "标签数据格式无效";
                            return Ok(new
                            {
                                status = "error",
                                message = "Label data format is invalid. Expected base64 encoded data or URL."
                            });
                        }
                    }

                    printTime = DateTime.UtcNow;

                    // 一次 GetPdfPageCount 调用，结果复用
                    int pageCount;
                    try
                    {
                        pageCount = GetPdfPageCount(labelBytes);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "PDF页数读取失败 for waybill number: {number}", waybillNumber);
                        scanResult = ScanResult.Other;
                        scanDescription = "PDF页数读取失败";
                        return Ok(new
                        {
                            status = "error",
                            message = "PDF页数读取失败"
                        });
                    }

                    if (pageCount > 1)
                    {
                        scanResult = ScanResult.Other;
                        scanDescription = $"PDF页数不符合要求，实际页数: {pageCount}";
                        return Ok(new
                        {
                            status = "error",
                            message = $"PDF页数不符合要求，当前页数: {pageCount}，要求: 1页"
                        });
                    }

                    if (labelBytes.Length > 1500000)
                    {
                        scanResult = ScanResult.Other;
                        scanDescription = $"面单大小异常，字节大小: {labelBytes.Length}";
                    }
                    else
                    {
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功下载标签";

                        try
                        {
                            await _labelPdfCacheService.SaveCacheAsync(
                                waybillNumber: waybillNumber,
                                pdfBytes: labelBytes,
                                pageCount: pageCount,
                                fileSize: labelBytes.Length,
                                originalUrl: label,
                                finalMileTrackingNumber: finalMileTrackingNumber,
                                customerId: customerId);
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "Failed to save PDF cache for waybill: {number}", waybillNumber);
                        }

                        _ = Task.Run(async () =>
                        {
                            try
                            {
                                var (barcodeNumber, barcodeType, barcodeConfidence) = await _labelPdfCacheService.ExtractBarcodeFromPdfAsync(labelBytes);

                                if (!string.IsNullOrEmpty(barcodeNumber))
                                {
                                    await _labelPdfCacheService.SaveCacheAsync(
                                        waybillNumber: waybillNumber,
                                        pdfBytes: labelBytes,
                                        pageCount: pageCount,
                                        fileSize: labelBytes.Length,
                                        originalUrl: label,
                                        finalMileTrackingNumber: finalMileTrackingNumber,
                                        customerId: customerId,
                                        barcodeNumber: barcodeNumber,
                                        barcodeType: barcodeType,
                                        barcodeConfidence: barcodeConfidence);
                                }
                            }
                            catch (Exception ex)
                            {
                                _logger.LogWarning(ex, "Barcode extraction failed (PDF cache already saved) for waybill: {number}", waybillNumber);
                            }
                        });
                    }

                    var fileName = $"label_{request.NeutralWaybillNumber}.pdf";
                    return File(labelBytes, "application/pdf", fileName);
                }
                catch (OperationCanceledException)
                {
                    scanResult = ScanResult.Other;
                    scanDescription = "处理标签下载请求超时";
                    _logger.LogWarning("Label download request timed out for waybill number: {number}", waybillNumber);

                    return File(Array.Empty<byte>(), "application/pdf", $"label_{waybillNumber}.pdf");
                }
            }
            catch (HttpRequestException ex)
            {
                scanResult = ScanResult.Other;
                scanDescription = "下载标签时发生HTTP错误: " + ex.Message;

                _logger.LogError(ex, "Error downloading label from URL");
                return Ok(new
                {
                    status = "error",
                    message = "Failed to download label from URL: " + ex.Message
                });
            }
            catch (Exception ex)
            {
                scanResult = ScanResult.Other;
                scanDescription = "处理标签下载请求时发生错误: " + ex.Message;

                _logger.LogError(ex, "Error processing label download request");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during label download.",
                    errorDetails = ex.Message
                });
            }
            finally
            {
                // 扫描记录异步写入，不阻塞响应
                var capturedCustomerId = customerId;
                var capturedWaybillNumber = waybillNumber;
                var capturedScanResult = scanResult;
                var capturedReferenceNumber = referenceNumber;
                var capturedFinalMile = finalMileTrackingNumber;
                var capturedScanDescription = scanDescription;
                var capturedScanTime = scanTime;
                var capturedPrintTime = printTime;
                var capturedCaller = caller;
                var capturedDeviceCode = deviceCode;
                var capturedDeviceName = deviceName;

                _ = Task.Run(async () =>
                {
                    try
                    {
                        await _labelScanService.RecordScanAsync(
                            customerId: capturedCustomerId,
                            neutralWaybillNumber: capturedWaybillNumber,
                            result: capturedScanResult,
                            createdBy: capturedCaller,
                            referenceNumber: capturedReferenceNumber,
                            finalMileTrackingNumber: capturedFinalMile,
                            description: capturedScanDescription,
                            deviceCode: capturedDeviceCode,
                            deviceName: capturedDeviceName
                        );
                        _logger.LogInformation("Recorded scan with result {result} for waybill number: {number}", capturedScanResult, capturedWaybillNumber);
                    }
                    catch (Exception scanEx)
                    {
                        _logger.LogWarning(scanEx, "Failed to record scan for waybill number: {number}", capturedWaybillNumber);
                    }
                });

                if (customerId > 0)
                {
                    try
                    {
                        var customer = await GetCustomerWithCacheAsync(customerId);
                        if (customer != null)
                        {
                            _ = Task.Run(async () =>
                            {
                                try
                                {
                                    if (customer.CustomerCode == "PT_GZ")
                                    {
                                        await SendWebhookToPatuen(capturedWaybillNumber, capturedScanTime, capturedPrintTime);
                                    }
                                    else if (customer.CustomerCode == "ZY_SH")
                                    {
                                        await SendWebhookToZunYou(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedFinalMile);
                                    }
                                    else if (customer.CustomerCode == "XT_JX")
                                    {
                                        await SendWebhookToXunTong(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                    else if (customer.CustomerCode == "IDI_ZJ")
                                    {
                                        await SendWebhookToIDI(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                    else if (customer.CustomerCode == "WEM_ZJ")
                                    {
                                        await SendWebhookToWEM(capturedWaybillNumber, capturedScanTime, capturedPrintTime, capturedScanResult, capturedScanDescription);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _logger.LogError(ex, "Error sending webhook for waybill number: {number}", capturedWaybillNumber);
                                }
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to get customer info for webhook notification, waybill number: {number}", waybillNumber);
                    }
                }
            }
        }


        [HttpGet("label-replace/waybill/{waybillNumber}/downloadNoTri")]
        public async Task<IActionResult> DownloadLabelByWaybillNumberNoTrigger(string waybillNumber)
        {
            // 初始化变量
            LabelReplaceEntity? request = null;
            ScanResult scanResult = ScanResult.NoLabelData;
            string scanDescription = "自动记录的标签下载扫描";
            int customerId = 0;
            string? referenceNumber = null;
            string? finalMileTrackingNumber = null;
            string caller = "system";
            string? deviceCode = HttpContext.GetDeviceCode();
            string? deviceName = HttpContext.GetDeviceName();
            DateTime scanTime = DateTime.UtcNow; // 扫描进入方法的时间
            DateTime? printTime = null; // 获取到pdf结果的时间

            try
            {
                if (string.IsNullOrEmpty(waybillNumber))
                {
                    return BadRequest(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                // 处理420开头的USPS单号特殊字符
                if (waybillNumber.StartsWith("420"))
                {
                    // 去除所有空白字符
                    char[] whitespaceChars = { ' ', '\t', '\n', '\r', '\u001d' };
                    waybillNumber = waybillNumber.Trim(whitespaceChars);
                    // 去除特殊字符（如运单号中的分隔符，ASCII 29和其他特殊字符）
                    char specialChar = (char)29;
                    waybillNumber = waybillNumber.Replace(specialChar.ToString(), "");
                    // 去除其他特殊字符，如↔
                    waybillNumber = waybillNumber.Replace("↔", "");
                }

                _logger.LogInformation("Received request to download label by waybill number: {number}", waybillNumber);

                caller = HttpContext.GetCaller();
                _logger.LogInformation("[Caller: {Caller}] DownloadLabelNoTrigger, WaybillNumber: {WaybillNumber}", caller, waybillNumber);

                // 创建取消令牌源，设置超时时间
                using var cts = new System.Threading.CancellationTokenSource(TimeSpan.FromSeconds(_appSettings.ApiSettings.InterfaceTimeout));
                var token = cts.Token;

                try
                {
                    // 调用服务获取标签替换记录 todo:并且没有被扫描过的记录的情况下返回
                    request = await _labelReplaceService.GetLabelReplaceRequestByWaybillNumberAsync(waybillNumber);

                    if (request == null)
                    {
                        scanResult = ScanResult.NoOrderData;
                        scanDescription = "未找到对应的标签替换记录";
                        return Ok(new
                        {
                            status = "error",
                            message = "Label replace request not found for the provided waybill number"
                        });
                    }

                    // 从标签替换记录中获取客户ID和其他信息
                    customerId = request.CustomerId ?? 0;
                    referenceNumber = request.ReferenceNumber;
                    finalMileTrackingNumber = request.FinalMileTrackingNumber;



                    // 检查订单是否被冻结
                    if (request.ReplaceStatus == "N")
                    {
                        scanResult = ScanResult.OrderFrozen;
                        scanDescription = "订单被冻结，无法下载面单";

                        // 当订单处于冻结状态时，触发STOP标签
                        string htmlContent = string.Empty;
                        try
                        {
                            // 读取HTML模板文件
                            string templatePath = Path.Combine(_hostingEnvironment.ContentRootPath, "..", "stop_label_preview.html");
                            string htmlTemplate = System.IO.File.ReadAllText(templatePath);

                            // 生成条形码的Base64编码
                            string barcodeContent = await _tagGenerationService.GenerateBarcodeAsync(waybillNumber);

                            // 根据客户ID获取客户代码
                            string customerCode = "UNKNOWN";
                            if (customerId > 0)
                            {
                                var customer = await _customerRepository.GetByIdAsync(customerId);
                                if (customer != null)
                                {
                                    customerCode = customer.CustomerCode;
                                }
                            }

                            // 替换模板中的硬编码值为实际的STOP标签数据
                            htmlTemplate = htmlTemplate.Replace("1234567890", waybillNumber);
                            htmlTemplate = htmlTemplate.Replace("3PE", customerCode);
                            htmlTemplate = htmlTemplate.Replace("2026-02-02 10:00:00", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                            htmlTemplate = htmlTemplate.Replace("ACTIVE", "ACTIVE");

                            // 当订单处于冻结状态时，添加STOP触发原因
                            string stopReason = "<p class=\"tag-info\">STOP触发原因: 取消换单，已达到换单要求仍失败</p>";
                            htmlTemplate = htmlTemplate.Replace("{{stopReason}}", stopReason);

                            // 替换模板中的条形码为base64编码的图片
                            htmlTemplate = htmlTemplate.Replace("{{barcodeBase64}}", barcodeContent);

                            htmlContent = htmlTemplate;
                            _logger.LogInformation("STOP label template loaded and variables replaced successfully");
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, "Error loading STOP label template file");
                            // 如果加载模板文件出错，使用默认HTML
                            htmlContent = $@"<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <title>STOP标签</title>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        h1 {{ color: #333; }}
        .container {{ max-width: 800px; margin: 0 auto; }}
        .info {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; }}
        .barcode {{ margin: 20px 0; padding: 10px; background-color: #f5f5f5; }}
        table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #f2f2f2; }}
    </style>
</head>
<body>
    <div class='container'>
        <h1>STOP标签</h1>
        <div class='info'>
            <table>
                <tr>
                    <th>项目</th>
                    <th>值</th>
                </tr>
                <tr>
                    <td>中性单号</td>
                    <td>{waybillNumber}</td>
                </tr>
                <tr>
                    <td>客户ID</td>
                    <td>{customerId}</td>
                </tr>
                <tr>
                    <td>触发时间</td>
                    <td>{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}</td>
                </tr>
                <tr>
                    <td>标签状态</td>
                    <td>ACTIVE</td>
                </tr>
                <tr>
                    <td>STOP触发原因</td>
                    <td>取消换单，已达到换单要求仍失败</td>
                </tr>
            </table>
        </div>
        <div class='barcode'>
            <h3>条形码</h3>
            <p>{waybillNumber}</p>
        </div>
    </div>
</body>
</html>";
                        }

                        // 转换HTML为PDF
                        var doc = new HtmlToPdfDocument()
                        {
                            GlobalSettings = {
                        ColorMode = DinkToPdf.ColorMode.Color,
                        Orientation = DinkToPdf.Orientation.Portrait,
                        //PaperSize = DinkToPdf.PaperKind.A5,
                        PaperSize =new PechkinPaperSize("100","150"),
                    },
                            Objects = {
                        new ObjectSettings() {
                            PagesCount = true,
                            HtmlContent = htmlContent,
                            WebSettings = { DefaultEncoding = "utf-8" }
                        }
                    }
                        };

                        var converter = PdfConverterSingleton.Instance;
                        byte[] stopLabelBytes = converter.Convert(doc);

                        // 设置printTime为获取到PDF结果的时间
                        printTime = null;

                        // 返回STOP标签PDF
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功返回STOP标签";

                        var stopLabelFileName = $"stop_label_{waybillNumber}.pdf";
                        return File(stopLabelBytes, "application/pdf", stopLabelFileName);
                    }

                    if (string.IsNullOrEmpty(request.Label))
                    {
                        scanResult = ScanResult.NoLabelData;
                        scanDescription = "标签数据不可用";
                        return Ok(new
                        {
                            status = "error",
                            message = "Label data is not available for the request"
                        });
                    }

                    byte[] labelBytes;

                    // 判断标签数据是base64编码还是URL
                    if (request.Label.StartsWith("data:"))
                    {
                        // 处理base64编码的data URL
                        var base64Data = request.Label.Substring(request.Label.IndexOf(",") + 1);
                        // 使用更高效的base64解码
                        labelBytes = Convert.FromBase64String(base64Data);
                    }
                    else if (request.Label.StartsWith("http://") || request.Label.StartsWith("https://"))
                    {
                        // 处理URL，下载文件，设置超时时间
                        using var httpClient = new HttpClient();
                        httpClient.Timeout = TimeSpan.FromSeconds(_appSettings.ApiSettings.LabelDownloadTimeout);
                        labelBytes = await httpClient.GetByteArrayAsync(request.Label, token);
                    }
                    else
                    {
                        // 假设是纯base64编码
                        try
                        {
                            // 使用更高效的base64解码
                            labelBytes = Convert.FromBase64String(request.Label);
                        }
                        catch (FormatException)
                        {
                            scanResult = ScanResult.NoLabelData;
                            scanDescription = "标签数据格式无效";
                            return Ok(new
                            {
                                status = "error",
                                message = "Label data format is invalid. Expected base64 encoded data or URL."
                            });
                        }
                    }

                    // 设置printTime为获取到PDF结果的时间
                    printTime = DateTime.UtcNow;

                    // 校验PDF页数
                    try
                    {
                        int pageCount = GetPdfPageCount(labelBytes);
                        if (pageCount > 1)
                        {
                            scanResult = ScanResult.Other;
                            scanDescription = $"PDF页数不符合要求，实际页数: {pageCount}";
                            return Ok(new
                            {
                                status = "error",
                                message = $"PDF页数不符合要求，当前页数: {pageCount}，要求: 1页"
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "PDF页数读取失败 for waybill number: {number}", waybillNumber);
                        scanResult = ScanResult.Other;
                        scanDescription = "PDF页数读取失败";
                        return Ok(new
                        {
                            status = "error",
                            message = "PDF页数读取失败"
                        });
                    }

                    // 检查PDF字节流大小是否异常（大于1500000）
                    if (labelBytes.Length > 1500000)
                    {
                        // 面单大小异常，记录为其他
                        scanResult = ScanResult.Other;
                        scanDescription = $"面单大小异常，字节大小: {labelBytes.Length}";
                    }
                    else
                    {
                        // 成功找到并处理标签，设置扫描结果为已返回面单
                        scanResult = ScanResult.ReturnedLabel;
                        scanDescription = "成功下载标签,无触发器";
                    }

                    // 设置响应头
                    var fileName = $"label_{request.NeutralWaybillNumber}.pdf";
                    return File(labelBytes, "application/pdf", fileName);
                }
                catch (OperationCanceledException)
                {
                    // 任务超时
                    scanResult = ScanResult.Other;
                    scanDescription = "处理标签下载请求超时";
                    _logger.LogWarning("Label download request timed out for waybill number: {number}", waybillNumber);

                    // 返回空字节流
                    return File(Array.Empty<byte>(), "application/pdf", $"label_{waybillNumber}.pdf");
                }
            }
            catch (HttpRequestException ex)
            {
                scanResult = ScanResult.Other;
                scanDescription = "下载标签时发生HTTP错误: " + ex.Message;

                _logger.LogError(ex, "Error downloading label from URL");
                return Ok(new
                {
                    status = "error",
                    message = "Failed to download label from URL: " + ex.Message
                });
            }
            catch (Exception ex)
            {
                scanResult = ScanResult.Other;
                scanDescription = "处理标签下载请求时发生错误: " + ex.Message;

                _logger.LogError(ex, "Error processing label download request");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during label download.",
                    errorDetails = ex.Message
                });
            }
            finally
            {
                // 确保每个请求只记录一次扫描，在finally块中执行，无论请求成功或失败都会记录
                try
                {
                    await _labelScanService.RecordScanAsync(
                        customerId: customerId,
                        neutralWaybillNumber: waybillNumber,
                        result: scanResult,
                        createdBy: caller,
                        referenceNumber: referenceNumber,
                        finalMileTrackingNumber: finalMileTrackingNumber,
                        description: scanDescription,
                        deviceCode: deviceCode,
                        deviceName: deviceName
                    );
                    _logger.LogInformation("Recorded scan with result {result} for waybill number: {number}", scanResult, waybillNumber);
                }
                catch (Exception scanEx)
                {
                    // 记录扫描失败不影响主流程
                    _logger.LogWarning(scanEx, "Failed to record scan for waybill number: {number}", waybillNumber);
                }

                // 检查是否需要向外部系统回传扫描结果
                if (customerId > 0)
                {
                    try
                    {
                        var customer = await _customerRepository.GetByIdAsync(customerId);
                        if (customer != null)
                        {
                            // 异步回传扫描结果，不阻塞主流程
                            _ = Task.Run(async () =>
                            {
                                try
                                {
                                    if (customer.CustomerCode == "PT_GZ")
                                    {
                                        // 向派通国际回传
                                        await SendWebhookToPatuen(waybillNumber, scanTime, printTime);
                                    }
                                    else if (customer.CustomerCode == "XT_JX")
                                    {
                                        // 向讯通系统回传
                                        await SendWebhookToXunTong(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                                    }
                                    else if (customer.CustomerCode == "ZY_SH")
                                    {
                                        // 向尊祐系统回传
                                        await SendWebhookToZunYou(waybillNumber, scanTime, printTime, scanResult, finalMileTrackingNumber);
                                    }
                                    else if (customer.CustomerCode == "IDI_ZJ")
                                    {
                                        await SendWebhookToIDI(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                                    }
                                    else if (customer.CustomerCode == "WEM_ZJ")
                                    {
                                        await SendWebhookToWEM(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                                    }
                                    else if (customer.CustomerCode == "ZYT_GZ")
                                    {
                                        await SendWebhookToZYT(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                                    }
                                    else if (customer.CustomerCode == "BDGJ_YW")
                                    {
                                        await SendWebhookToBDGJ(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    _logger.LogError(ex, "Error sending webhook for waybill number: {number}", waybillNumber);
                                }
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        // 客户信息获取失败不影响主流程
                        _logger.LogWarning(ex, "Failed to get customer info for webhook notification, waybill number: {number}", waybillNumber);
                    }
                }
            }
        }

        private int GetPdfPageCount(byte[] pdfBytes)
        {
            using var document = PdfSharp.Pdf.IO.PdfReader.Open(new MemoryStream(pdfBytes), PdfSharp.Pdf.IO.PdfDocumentOpenMode.Import);
            return document.PageCount;
        }

        /// <summary>
        /// 向派通国际发送webhook通知
        /// </summary>
        private async Task SendWebhookToPatuen(string waybillNumber, DateTime scanTime, DateTime? printTime)
        {
            try
            {
                // 使用HttpClientFactory创建HttpClient实例
                var httpClient = _httpClientFactory.CreateClient();
                httpClient.Timeout = TimeSpan.FromSeconds(10); // 设置webhook请求超时时间

                // 构建webhook请求数据
                var webhookData = new
                {
                    trackNo = waybillNumber,
                    eventTime = DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), // 使用UTC0时间
                    scanTime = scanTime.ToString("yyyy/MM/dd HH:mm:ss"), // 扫描进入方法的时间
                    printTime = printTime?.ToString("yyyy/MM/dd HH:mm:ss"), // 获取到pdf结果的时间
                    userId = 612 // 固定值
                };

                // 序列化请求数据
                var jsonContent = new StringContent(
                    System.Text.Json.JsonSerializer.Serialize(webhookData),
                    System.Text.Encoding.UTF8,
                    "application/json"
                );

                // 发送webhook请求
                var webhookUrl = "https://api.patuen.com/packetWebhook/scanNotify";
                var response = await httpClient.PostAsync(webhookUrl, jsonContent);

                _logger.LogInformation("Successfully JsonSerializer JSON  for waybill number: {number}, JSON: {JSON}", waybillNumber, jsonContent);

                // 记录webhook发送结果
                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync();
                    _logger.LogInformation("Successfully sent webhook to Patuen for waybill number: {number}, response: {response}", waybillNumber, responseContent);
                }
                else
                {
                    var errorContent = await response.Content.ReadAsStringAsync();
                    _logger.LogWarning("Failed to send webhook to Patuen for waybill number: {number}, status code: {status}, response: {response}",
                        waybillNumber, response.StatusCode, errorContent);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception sending webhook to Patuen for waybill number: {number}", waybillNumber);
                throw;
            }
        }

        /// <summary>
        /// 向讯通系统发送webhook通知
        /// </summary>
        private async Task SendWebhookToXunTong(string waybillNumber, DateTime scanTime, DateTime? printTime, ScanResult scanResult, string scanDescription)
        {
            int retryCount = 3;
            int delayMs = 1000;
            bool success = false;

            // 获取本机公网IP地址
            // string publicIpAddress = await GetPublicIpAddress();
            string publicIpAddress = "127.0.0.1";
            // 转换时间为UTC-5时区
            //TimeZoneInfo easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
            //DateTime utcMinus5ScanTime = TimeZoneInfo.ConvertTimeFromUtc(scanTime, easternTimeZone);
            //DateTime? utcMinus5PrintTime = printTime.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(printTime.Value, easternTimeZone) : (DateTime?)null;

            DateTime utcMinus5ScanTime= scanTime.AddHours(-5);

            // 在scanDescription中添加时区信息
            string updatedScanDescription = $"{scanDescription} (UTC-5)";

            for (int attempt = 1; attempt <= retryCount; attempt++)
            {
                try
                {
                    // 使用HttpClientFactory创建HttpClient实例
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置webhook请求超时时间为30秒

                    // 构建data参数的JSON对象
                    var dataObject = new
                    {
                        neutralWaybillNo = waybillNumber,
                        exchangeResult = scanResult == ScanResult.ReturnedLabel ? "SUCCESS" : "FAILURE",
                        exchangeTime = utcMinus5ScanTime.ToString("yyyy/MM/dd HH:mm:ss"),
                        resultMsg = updatedScanDescription.Length > 200 ? updatedScanDescription.Substring(0, 200) : updatedScanDescription
                    };

                    // 序列化data对象
                    string dataJson = System.Text.Json.JsonSerializer.Serialize(dataObject);

                    // 构建multipart/form-data请求
                    using var content = new MultipartFormDataContent();
                    content.Add(new StringContent("PRINTMARK"), "code");
                    content.Add(new StringContent(dataJson), "data");

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to XunTong: waybillNumber={number}, publicIp={ip}, requestData={data}",
                        waybillNumber, publicIpAddress, dataJson);

                    // 发送webhook请求
                    //var webhookUrl = "http://toms.ruantongbao.com/webservice/ChangeLabel/LabelService.ashx";
                    var webhookUrl = "http://shywn.rtb56.com/webservice/ChangeLabel/LabelService.ashx";
                    var startTime = DateTime.UtcNow;
                    var response = await httpClient.PostAsync(webhookUrl, content);
                    var endTime = DateTime.UtcNow;
                    var duration = (endTime - startTime).TotalMilliseconds;

                    // 记录webhook发送结果
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        _logger.LogInformation("Successfully sent webhook to XunTong for waybill number: {number}, response: {response}, duration: {duration}ms, publicIp: {ip}",
                            waybillNumber, responseContent, duration, publicIpAddress);
                        success = true;
                        break;
                    }
                    else
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        _logger.LogWarning("Failed to send webhook to XunTong for waybill number: {number}, status code: {status}, response: {response}, duration: {duration}ms, attempt: {attempt}, publicIp: {ip}",
                            waybillNumber, response.StatusCode, errorContent, duration, attempt, publicIpAddress);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception sending webhook to XunTong for waybill number: {number}, attempt: {attempt}, publicIp: {ip}", waybillNumber, attempt, publicIpAddress);
                }

                // 指数退避重试
                if (attempt < retryCount)
                {
                    await Task.Delay(delayMs);
                    delayMs *= 2;
                }
            }

            if (!success)
            {
                _logger.LogError("Failed to send webhook to XunTong after {retryCount} attempts for waybill number: {number}, publicIp: {ip}", retryCount, waybillNumber, publicIpAddress);
            }
        }

        /// <summary>
        /// 向WEM系统发送webhook通知
        /// </summary>
        private async Task SendWebhookToWEM(string waybillNumber, DateTime scanTime, DateTime? printTime, ScanResult scanResult, string scanDescription)
        {
            int retryCount = 3;
            int delayMs = 1000;
            bool success = false;

            // 获取本机公网IP地址
            // string publicIpAddress = await GetPublicIpAddress();
            string publicIpAddress = "127.0.0.1";
            // 转换时间为UTC-5时区
            //TimeZoneInfo easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
            //DateTime utcMinus5ScanTime = TimeZoneInfo.ConvertTimeFromUtc(scanTime, easternTimeZone);
            //DateTime? utcMinus5PrintTime = printTime.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(printTime.Value, easternTimeZone) : (DateTime?)null;

            DateTime utcMinus5ScanTime = scanTime.AddHours(-5);

            // 在scanDescription中添加时区信息
            string updatedScanDescription = $"{scanDescription} (UTC-5)";

            for (int attempt = 1; attempt <= retryCount; attempt++)
            {
                try
                {
                    // 使用HttpClientFactory创建HttpClient实例
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置webhook请求超时时间为30秒

                    // 构建data参数的JSON对象
                    var dataObject = new
                    {
                        neutralWaybillNo = waybillNumber,
                        exchangeResult = scanResult == ScanResult.ReturnedLabel ? "SUCCESS" : "FAILURE",
                        exchangeTime = utcMinus5ScanTime.ToString("yyyy/MM/dd HH:mm:ss"),
                        resultMsg = updatedScanDescription.Length > 200 ? updatedScanDescription.Substring(0, 200) : updatedScanDescription
                    };

                    // 序列化data对象
                    string dataJson = System.Text.Json.JsonSerializer.Serialize(dataObject);

                    // 构建multipart/form-data请求
                    using var content = new MultipartFormDataContent();
                    content.Add(new StringContent("PRINTMARK"), "code");
                    content.Add(new StringContent(dataJson), "data");

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to WEM: waybillNumber={number}, publicIp={ip}, requestData={data}",
                        waybillNumber, publicIpAddress, dataJson);

                    // 发送webhook请求
                    //var webhookUrl = "http://toms.ruantongbao.com/webservice/ChangeLabel/LabelService.ashx";
                    var webhookUrl = "http://zjwem.rtb56.com/webservice/ChangeLabel/LabelService.ashx";
                    var startTime = DateTime.UtcNow;
                    var response = await httpClient.PostAsync(webhookUrl, content);
                    var endTime = DateTime.UtcNow;
                    var duration = (endTime - startTime).TotalMilliseconds;

                    // 记录webhook发送结果
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        _logger.LogInformation("Successfully sent webhook to WEM for waybill number: {number}, response: {response}, duration: {duration}ms, publicIp: {ip}",
                            waybillNumber, responseContent, duration, publicIpAddress);
                        success = true;
                        break;
                    }
                    else
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        _logger.LogWarning("Failed to send webhook to WEM for waybill number: {number}, status code: {status}, response: {response}, duration: {duration}ms, attempt: {attempt}, publicIp: {ip}",
                            waybillNumber, response.StatusCode, errorContent, duration, attempt, publicIpAddress);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception sending webhook to WEM for waybill number: {number}, attempt: {attempt}, publicIp: {ip}", waybillNumber, attempt, publicIpAddress);
                }

                // 指数退避重试
                if (attempt < retryCount)
                {
                    await Task.Delay(delayMs);
                    delayMs *= 2;
                }
            }

            if (!success)
            {
                _logger.LogError("Failed to send webhook to WEM after {retryCount} attempts for waybill number: {number}, publicIp: {ip}", retryCount, waybillNumber, publicIpAddress);
            }
        }

        /// <summary>
        /// 向BDGJ系统发送webhook通知
        /// </summary>
        private async Task SendWebhookToBDGJ(string waybillNumber, DateTime scanTime, DateTime? printTime, ScanResult scanResult, string scanDescription)
        {
            int retryCount = 3;
            int delayMs = 1000;
            bool success = false;

            // 获取本机公网IP地址
            // string publicIpAddress = await GetPublicIpAddress();
            string publicIpAddress = "127.0.0.1";
            // 转换时间为UTC-5时区
            //TimeZoneInfo easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
            //DateTime utcMinus5ScanTime = TimeZoneInfo.ConvertTimeFromUtc(scanTime, easternTimeZone);
            //DateTime? utcMinus5PrintTime = printTime.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(printTime.Value, easternTimeZone) : (DateTime?)null;

            DateTime utcMinus5ScanTime = scanTime.AddHours(-5);

            // 在scanDescription中添加时区信息
            string updatedScanDescription = $"{scanDescription} (UTC-5)";

            for (int attempt = 1; attempt <= retryCount; attempt++)
            {
                try
                {
                    // 使用HttpClientFactory创建HttpClient实例
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置webhook请求超时时间为30秒

                    // 构建data参数的JSON对象
                    var dataObject = new
                    {
                        neutralWaybillNo = waybillNumber,
                        exchangeResult = scanResult == ScanResult.ReturnedLabel ? "SUCCESS" : "FAILURE",
                        exchangeTime = utcMinus5ScanTime.ToString("yyyy/MM/dd HH:mm:ss"),
                        resultMsg = updatedScanDescription.Length > 200 ? updatedScanDescription.Substring(0, 200) : updatedScanDescription
                    };

                    // 序列化data对象
                    string dataJson = System.Text.Json.JsonSerializer.Serialize(dataObject);

                    // 构建multipart/form-data请求
                    using var content = new MultipartFormDataContent();
                    content.Add(new StringContent("PRINTMARK"), "code");
                    content.Add(new StringContent(dataJson), "data");

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to BDGJ: waybillNumber={number}, publicIp={ip}, requestData={data}",
                        waybillNumber, publicIpAddress, dataJson);

                    // 发送webhook请求
                    //var webhookUrl = "http://toms.ruantongbao.com/webservice/ChangeLabel/LabelService.ashx";
                    var webhookUrl = "http://bdky.rtb56.com/webservice/ChangeLabel/LabelService.ashx";
                    var startTime = DateTime.UtcNow;
                    var response = await httpClient.PostAsync(webhookUrl, content);
                    var endTime = DateTime.UtcNow;
                    var duration = (endTime - startTime).TotalMilliseconds;

                    // 记录webhook发送结果
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        _logger.LogInformation("Successfully sent webhook to BDGJ for waybill number: {number}, response: {response}, duration: {duration}ms, publicIp: {ip}",
                            waybillNumber, responseContent, duration, publicIpAddress);
                        success = true;
                        break;
                    }
                    else
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        _logger.LogWarning("Failed to send webhook to BDGJ for waybill number: {number}, status code: {status}, response: {response}, duration: {duration}ms, attempt: {attempt}, publicIp: {ip}",
                            waybillNumber, response.StatusCode, errorContent, duration, attempt, publicIpAddress);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception sending webhook to BDGJ for waybill number: {number}, attempt: {attempt}, publicIp: {ip}", waybillNumber, attempt, publicIpAddress);
                }

                // 指数退避重试
                if (attempt < retryCount)
                {
                    await Task.Delay(delayMs);
                    delayMs *= 2;
                }
            }

            if (!success)
            {
                _logger.LogError("Failed to send webhook to BDGJ after {retryCount} attempts for waybill number: {number}, publicIp: {ip}", retryCount, waybillNumber, publicIpAddress);
            }
        }
        /// <summary>
        /// 向ZYT系统发送webhook通知
        /// </summary>
        private async Task SendWebhookToZYT(string waybillNumber, DateTime scanTime, DateTime? printTime, ScanResult scanResult, string scanDescription)
        {
            int retryCount = 3;
            int delayMs = 1000;
            bool success = false;

            // 获取本机公网IP地址
            // string publicIpAddress = await GetPublicIpAddress();
            string publicIpAddress = "127.0.0.1";
            // 转换时间为UTC-5时区
            //TimeZoneInfo easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
            //DateTime utcMinus5ScanTime = TimeZoneInfo.ConvertTimeFromUtc(scanTime, easternTimeZone);
            //DateTime? utcMinus5PrintTime = printTime.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(printTime.Value, easternTimeZone) : (DateTime?)null;

            DateTime utcMinus5ScanTime = scanTime.AddHours(-5);

            // 在scanDescription中添加时区信息
            string updatedScanDescription = $"{scanDescription} (UTC-5)";

            for (int attempt = 1; attempt <= retryCount; attempt++)
            {
                try
                {
                    // 使用HttpClientFactory创建HttpClient实例
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置webhook请求超时时间为30秒

                    // 构建data参数的JSON对象
                    var dataObject = new
                    {
                        neutralWaybillNo = waybillNumber,
                        exchangeResult = scanResult == ScanResult.ReturnedLabel ? "SUCCESS" : "FAILURE",
                        exchangeTime = utcMinus5ScanTime.ToString("yyyy/MM/dd HH:mm:ss"),
                        resultMsg = updatedScanDescription.Length > 200 ? updatedScanDescription.Substring(0, 200) : updatedScanDescription
                    };

                    // 序列化data对象
                    string dataJson = System.Text.Json.JsonSerializer.Serialize(dataObject);

                    // 构建multipart/form-data请求
                    using var content = new MultipartFormDataContent();
                    content.Add(new StringContent("PRINTMARK"), "code");
                    content.Add(new StringContent(dataJson), "data");

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to ZYT: waybillNumber={number}, publicIp={ip}, requestData={data}",
                        waybillNumber, publicIpAddress, dataJson);

                    // 发送webhook请求
                    //var webhookUrl = "http://toms.ruantongbao.com/webservice/ChangeLabel/LabelService.ashx";
                    var webhookUrl = "http://zyt.rtb56.com/webservice/ChangeLabel/LabelService.ashx";
                    var startTime = DateTime.UtcNow;
                    var response = await httpClient.PostAsync(webhookUrl, content);
                    var endTime = DateTime.UtcNow;
                    var duration = (endTime - startTime).TotalMilliseconds;

                    // 记录webhook发送结果
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        _logger.LogInformation("Successfully sent webhook to ZYT for waybill number: {number}, response: {response}, duration: {duration}ms, publicIp: {ip}",
                            waybillNumber, responseContent, duration, publicIpAddress);
                        success = true;
                        break;
                    }
                    else
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        _logger.LogWarning("Failed to send webhook to ZYT for waybill number: {number}, status code: {status}, response: {response}, duration: {duration}ms, attempt: {attempt}, publicIp: {ip}",
                            waybillNumber, response.StatusCode, errorContent, duration, attempt, publicIpAddress);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception sending webhook to ZYT for waybill number: {number}, attempt: {attempt}, publicIp: {ip}", waybillNumber, attempt, publicIpAddress);
                }

                // 指数退避重试
                if (attempt < retryCount)
                {
                    await Task.Delay(delayMs);
                    delayMs *= 2;
                }
            }

            if (!success)
            {
                _logger.LogError("Failed to send webhook to ZYT after {retryCount} attempts for waybill number: {number}, publicIp: {ip}", retryCount, waybillNumber, publicIpAddress);
            }
        }

        /// <summary>
        /// 向IDI系统发送webhook通知
        /// </summary>
        private async Task SendWebhookToIDI(string waybillNumber, DateTime scanTime, DateTime? printTime, ScanResult scanResult, string scanDescription)
        {
            int retryCount = 3;
            int delayMs = 1000;
            bool success = false;

            // 获取本机公网IP地址
            // string publicIpAddress = await GetPublicIpAddress();
            string publicIpAddress = "127.0.0.1";
            // 转换时间为UTC-5时区
            //TimeZoneInfo easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
            //DateTime utcMinus5ScanTime = TimeZoneInfo.ConvertTimeFromUtc(scanTime, easternTimeZone);
            //DateTime? utcMinus5PrintTime = printTime.HasValue ? TimeZoneInfo.ConvertTimeFromUtc(printTime.Value, easternTimeZone) : (DateTime?)null;

            DateTime utcMinus5ScanTime = scanTime.AddHours(-5);

            // 在scanDescription中添加时区信息
            string updatedScanDescription = $"{scanDescription} (UTC-5)";

            for (int attempt = 1; attempt <= retryCount; attempt++)
            {
                try
                {
                    // 使用HttpClientFactory创建HttpClient实例
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置webhook请求超时时间为30秒

                    // 构建data参数的JSON对象
                    var dataObject = new
                    {
                        neutralWaybillNo = waybillNumber,
                        exchangeResult = scanResult == ScanResult.ReturnedLabel ? "SUCCESS" : "FAILURE",
                        exchangeTime = utcMinus5ScanTime.ToString("yyyy/MM/dd HH:mm:ss"),
                        resultMsg = updatedScanDescription.Length > 200 ? updatedScanDescription.Substring(0, 200) : updatedScanDescription
                    };

                    // 序列化data对象
                    string dataJson = System.Text.Json.JsonSerializer.Serialize(dataObject);

                    // 构建multipart/form-data请求
                    using var content = new MultipartFormDataContent();
                    content.Add(new StringContent("PRINTMARK"), "code");
                    content.Add(new StringContent(dataJson), "data");

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to IDI: waybillNumber={number}, publicIp={ip}, requestData={data}",
                        waybillNumber, publicIpAddress, dataJson);

                    // 发送webhook请求
                    //var webhookUrl = "http://toms.ruantongbao.com/webservice/ChangeLabel/LabelService.ashx";
                    var webhookUrl = "http://hzada.rtb56.com/webservice/ChangeLabel/LabelService.ashx";
                    var startTime = DateTime.UtcNow;
                    var response = await httpClient.PostAsync(webhookUrl, content);
                    var endTime = DateTime.UtcNow;
                    var duration = (endTime - startTime).TotalMilliseconds;

                    // 记录webhook发送结果
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        _logger.LogInformation("Successfully sent webhook to IDI for waybill number: {number}, response: {response}, duration: {duration}ms, publicIp: {ip}",
                            waybillNumber, responseContent, duration, publicIpAddress);
                        success = true;
                        break;
                    }
                    else
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        _logger.LogWarning("Failed to send webhook to IDI for waybill number: {number}, status code: {status}, response: {response}, duration: {duration}ms, attempt: {attempt}, publicIp: {ip}",
                            waybillNumber, response.StatusCode, errorContent, duration, attempt, publicIpAddress);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception sending webhook to IDI for waybill number: {number}, attempt: {attempt}, publicIp: {ip}", waybillNumber, attempt, publicIpAddress);
                }

                // 指数退避重试
                if (attempt < retryCount)
                {
                    await Task.Delay(delayMs);
                    delayMs *= 2;
                }
            }

            if (!success)
            {
                _logger.LogError("Failed to send webhook to IDI after {retryCount} attempts for waybill number: {number}, publicIp: {ip}", retryCount, waybillNumber, publicIpAddress);
            }
        }

        /// <summary>
        /// 向尊祐系统发送webhook通知
        /// </summary>
        private async Task SendWebhookToZunYou(string waybillNumber, DateTime scanTime, DateTime? printTime, ScanResult scanResult, string finalMileTrackingNumber)
        {
            int retryCount = 3;
            int delayMs = 1000;
            bool success = false;

            for (int attempt = 1; attempt <= retryCount; attempt++)
            {
                try
                {
                    // 使用HttpClientFactory创建HttpClient实例
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(10); // 设置webhook请求超时时间

                    // 构建webhook请求数据
                    var webhookData = new[]
                    {
                        new
                        {
                            WaybillNumber = waybillNumber,
                            TrackingNumber = finalMileTrackingNumber,
                            Replaced = scanResult == ScanResult.ReturnedLabel,
                            ReplacedAt = scanTime.ToString("yyyy-MM-ddTHH:mm:ss")
                        }
                    };

                    // 序列化请求数据
                    var jsonString = System.Text.Json.JsonSerializer.Serialize(webhookData);
                    var jsonContent = new StringContent(
                        jsonString,
                        System.Text.Encoding.UTF8,
                        "application/json"
                    );

                    // 设置请求头
                    httpClient.DefaultRequestHeaders.Add("token", "1c96499e-3c58-4e20-bc5d-b52ce9f9e36d");

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to ZunYou: waybillNumber={number}, json={json}",
                        waybillNumber, jsonString);

                    // 记录请求详情
                    _logger.LogInformation("Sending webhook to ZunYou: waybillNumber={number}, trackingNumber={tracking}, replaced={replaced}",
                        waybillNumber, finalMileTrackingNumber, scanResult == ScanResult.ReturnedLabel);

                    // 发送webhook请求
                    var webhookUrl = "https://shzy.t6soft.com/api/eparcel/label-replace/status";
                    var startTime = DateTime.UtcNow;
                    var response = await httpClient.PostAsync(webhookUrl, jsonContent);
                    var endTime = DateTime.UtcNow;
                    var duration = (endTime - startTime).TotalMilliseconds;

                    // 记录webhook发送结果
                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        _logger.LogInformation("Successfully sent webhook to ZunYou for waybill number: {number}, response: {response}, duration: {duration}ms",
                            waybillNumber, responseContent, duration);
                        success = true;
                        break;
                    }
                    else
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        _logger.LogWarning("Failed to send webhook to ZunYou for waybill number: {number}, status code: {status}, response: {response}, duration: {duration}ms, attempt: {attempt}",
                            waybillNumber, response.StatusCode, errorContent, duration, attempt);
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Exception sending webhook to ZunYou for waybill number: {number}, attempt: {attempt}", waybillNumber, attempt);
                }

                // 指数退避重试
                if (attempt < retryCount)
                {
                    await Task.Delay(delayMs);
                    delayMs *= 2;
                }
            }

            if (!success)
            {
                _logger.LogError("Failed to send webhook to ZunYou after {retryCount} attempts for waybill number: {number}", retryCount, waybillNumber);
            }
        }

        /// <summary>
        /// 获取打印预览页面
        /// </summary>
        [HttpGet("print-preview")]
        public IActionResult GetPrintPreview()
        {
            var filePath = Path.Combine(_hostingEnvironment.ContentRootPath, "src", "Views", "PrintPreview.html");
            if (System.IO.File.Exists(filePath))
            {
                var content = System.IO.File.ReadAllText(filePath);
                return Content(content, "text/html");
            }
            return NotFound();
        }

        /// <summary>
        /// 获取本机公网IP地址
        /// </summary>
        private async Task<string> GetPublicIpAddress()
        {
            // 定义备用的IP地址获取服务
            var ipServices = new List<string>
            {
                "https://ipinfo.io/ip",
                "https://ifconfig.me/ip",
                "https://icanhazip.com"
            };

            foreach (var serviceUrl in ipServices)
            {
                try
                {
                    var httpClient = _httpClientFactory.CreateClient();
                    httpClient.Timeout = TimeSpan.FromSeconds(5); // 设置获取IP地址的超时时间

                    _logger.LogInformation("Attempting to get public IP address from {service}", serviceUrl);

                    // 发送请求获取IP地址
                    var response = await httpClient.GetStringAsync(serviceUrl);
                    string publicIp = response.Trim();
                    _logger.LogInformation("Successfully obtained public IP address from {service}: {ip}", serviceUrl, publicIp);
                    return publicIp;
                }
                catch (Exception ex)
                {
                    // 记录完整的异常信息，包括inner exception
                    string errorMessage = ex.Message;
                    Exception innerException = ex.InnerException;
                    while (innerException != null)
                    {
                        errorMessage += $"; Inner: {innerException.Message}";
                        innerException = innerException.InnerException;
                    }
                    _logger.LogWarning(ex, "Failed to get public IP address from {service}. Error message: {message}", serviceUrl, errorMessage);
                    // 继续尝试下一个服务
                }
            }

            // 所有服务都失败了
            _logger.LogWarning("All IP address services failed to respond");
            return "Unknown";
        }

        /// <summary>
        /// 测试讯通回传接口
        /// </summary>
        [HttpPost("label-scan/test-xuntong-webhook")]
        public async Task<IActionResult> TestXunTongWebhook([FromBody] TestWebhookRequest request)
        {
            try
            {
                if (request == null || string.IsNullOrEmpty(request.WaybillNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                _logger.LogInformation("Received test request for XunTong webhook: {number}", request.WaybillNumber);

                // 调用测试方法
                await SendWebhookToXunTong(
                    waybillNumber: request.WaybillNumber,
                    scanTime: DateTime.UtcNow,
                    printTime: DateTime.UtcNow,
                    scanResult: request.Success ? ScanResult.ReturnedLabel : ScanResult.NoLabelData,
                    scanDescription: request.Description ?? "Test webhook"
                );

                return Ok(new
                {
                    status = "ok",
                    message = "Test webhook sent successfully"
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error testing XunTong webhook");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during test",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 测试尊祐回传接口
        /// </summary>
        [HttpPost("label-scan/test-zunyou-webhook")]
        public async Task<IActionResult> TestZunYouWebhook([FromBody] TestWebhookRequest request)
        {
            try
            {
                if (request == null || string.IsNullOrEmpty(request.WaybillNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                _logger.LogInformation("Received test request for ZunYou webhook: {number}", request.WaybillNumber);

                // 调用测试方法
                await SendWebhookToZunYou(
                    waybillNumber: request.WaybillNumber,
                    scanTime: DateTime.UtcNow,
                    printTime: DateTime.UtcNow,
                    scanResult: request.Success ? ScanResult.ReturnedLabel : ScanResult.NoLabelData,
                    finalMileTrackingNumber: "TEST1234567890"
                );

                return Ok(new
                {
                    status = "ok",
                    message = "Test webhook sent successfully"
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error testing ZunYou webhook");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during test",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 测试webhook请求模型
        /// </summary>
        public class TestWebhookRequest
        {
            /// <summary>
            /// 中性面单单号
            /// </summary>
            public string WaybillNumber { get; set; }

            /// <summary>
            /// 是否成功
            /// </summary>
            public bool Success { get; set; } = true;

            /// <summary>
            /// 描述
            /// </summary>
            public string Description { get; set; }
        }

        /// <summary>
        /// 记录标签扫描
        /// </summary>
        [HttpPost("label-scan/record")]
        public async Task<IActionResult> RecordLabelScan([FromBody] ScanRecordRequest request)
        {
            try
            {
                if (request == null || string.IsNullOrEmpty(request.NeutralWaybillNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Neutral waybill number is required"
                    });
                }

                if (string.IsNullOrEmpty(request.CreatedBy))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Created by is required"
                    });
                }

                _logger.LogInformation("Received request to record scan for waybill number: {number}", request.NeutralWaybillNumber);

                // 调用服务记录扫描
                var scanRecord = await _labelScanService.RecordScanAsync(
                    customerId: request.CustomerId,
                    neutralWaybillNumber: request.NeutralWaybillNumber,
                    result: request.Result,
                    createdBy: request.CreatedBy,
                    referenceNumber: request.ReferenceNumber,
                    finalMileTrackingNumber: request.FinalMileTrackingNumber,
                    description: request.Description
                );

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    scanRecord = scanRecord
                };

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error recording label scan");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during label scan recording.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 根据中性面单查询扫描记录列表
        /// </summary>
        [HttpGet("label-scan/waybill/{waybillNumber}")]
        public async Task<IActionResult> GetScanRecordsByWaybillNumber(string waybillNumber)
        {
            try
            {
                if (string.IsNullOrEmpty(waybillNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Waybill number is required"
                    });
                }

                _logger.LogInformation("Received request to get scan records by waybill number: {number}", waybillNumber);

                // 调用服务获取扫描记录列表
                var scanRecords = await _labelScanService.GetScanRecordsByNeutralWaybillNumberAsync(waybillNumber);

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    waybillNumber = waybillNumber,
                    count = scanRecords.Count,
                    data = scanRecords
                };

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving scan records by waybill number");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during scan record retrieval.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 根据客户ID查询扫描记录列表
        /// </summary>
        [HttpGet("label-scan/customer/{customerId}")]
        public async Task<IActionResult> GetScanRecordsByCustomerId(int customerId)
        {
            try
            {
                _logger.LogInformation("Received request to get scan records by customer ID: {customerId}", customerId);

                // 调用服务获取扫描记录列表
                var scanRecords = await _labelScanService.GetScanRecordsByCustomerIdAsync(customerId);

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    customerId = customerId,
                    count = scanRecords.Count,
                    data = scanRecords
                };

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving scan records by customer ID");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during scan record retrieval.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 获取客户的扫描记录统计
        /// </summary>
        [HttpGet("label-scan/stats/customer/{customerId}")]
        public async Task<IActionResult> GetScanStatsByCustomerId(int customerId)
        {
            try
            {
                _logger.LogInformation("Received request to get scan statistics by customer ID: {customerId}", customerId);

                // 调用服务获取扫描记录统计
                var scanStats = await _labelScanService.GetScanStatsByCustomerAsync(customerId);

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    customerId = customerId,
                    stats = scanStats
                };

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving scan statistics by customer ID");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during scan statistics retrieval.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 扫描记录请求模型
        /// </summary>
        public class ScanRecordRequest
        {
            /// <summary>
            /// 客户ID
            /// </summary>
            public int CustomerId { get; set; }

            /// <summary>
            /// 中性面单单号
            /// </summary>
            public string NeutralWaybillNumber { get; set; }

            /// <summary>
            /// 扫描结果
            /// </summary>
            public ScanResult Result { get; set; }

            /// <summary>
            /// 创建人
            /// </summary>
            public string CreatedBy { get; set; }

            /// <summary>
            /// 参考号
            /// </summary>
            public string ReferenceNumber { get; set; }

            /// <summary>
            /// 尾程跟踪单号
            /// </summary>
            public string FinalMileTrackingNumber { get; set; }

            /// <summary>
            /// 描述
            /// </summary>
            public string Description { get; set; }
        }

        /// <summary>
        /// 批量查询标签替换请求
        /// </summary>
        [HttpGet("label-replace/batch")]
        public async Task<IActionResult> GetLabelReplaceBatch(
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 10,
            [FromQuery] string sortBy = "CreatedAt",
            [FromQuery] string sortOrder = "desc",
            [FromQuery] string billOfLadingNumber = null,
            [FromQuery] string masterPackageNumber = null,
            [FromQuery] string referenceNumber = null,
            [FromQuery] string neutralWaybillNumber = null,
            [FromQuery] string finalMileTrackingNumber = null,
            [FromQuery] string replaceStatus = null,
            [FromQuery] int? customerId = null,
            [FromQuery] string startCreatedAt = null,
            [FromQuery] string endCreatedAt = null,
            [FromQuery] string startReplacedAt = null,
            [FromQuery] string endReplacedAt = null,
            [FromQuery] string callback = null
        )
        {
            try
            {
                _logger.LogInformation("Received batch request for label replace requests");

                // 调用服务分页获取标签替换请求
                var (pagedRequests, totalCount) = await _labelReplaceService.GetLabelReplaceRequestsByPageAsync(
                    page, pageSize, sortBy, sortOrder, billOfLadingNumber, masterPackageNumber,
                    referenceNumber, neutralWaybillNumber, finalMileTrackingNumber, replaceStatus, customerId,
                    startCreatedAt, endCreatedAt, startReplacedAt, endReplacedAt
                );

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    totalCount = totalCount,
                    page = page,
                    pageSize = pageSize,
                    totalPages = (int)Math.Ceiling((double)totalCount / pageSize),
                    data = pagedRequests
                };

                // 处理 JSONP 请求
                if (!string.IsNullOrEmpty(callback))
                {
                    var jsonResult = System.Text.Json.JsonSerializer.Serialize(result);
                    var jsonpResult = $"{callback}({jsonResult})";
                    return Content(jsonpResult, "application/javascript");
                }

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving batch label replace requests");
                var errorResult = new
                {
                    status = "error",
                    message = "An unexpected error occurred during batch retrieval.",
                    errorDetails = ex.Message
                };

                // 处理 JSONP 错误
                if (!string.IsNullOrEmpty(callback))
                {
                    var jsonResult = System.Text.Json.JsonSerializer.Serialize(errorResult);
                    var jsonpResult = $"{callback}({jsonResult})";
                    return Content(jsonpResult, "application/javascript");
                }

                return Ok(errorResult);
            }
        }

        /// <summary>
        /// 批量查询标签扫描记录
        /// </summary>
        [HttpGet("label-scan/batch")]
        public async Task<IActionResult> GetLabelScanBatch(
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 10,
            [FromQuery] string sortBy = "CreatedAt",
            [FromQuery] string sortOrder = "desc",
            [FromQuery] int? customerId = null,
            [FromQuery] string referenceNumber = null,
            [FromQuery] string neutralWaybillNumber = null,
            [FromQuery] string finalMileTrackingNumber = null,
            [FromQuery] int? result = null,
            [FromQuery] string startCreatedAt = null,
            [FromQuery] string endCreatedAt = null,
            [FromQuery] string callback = null
        )
        {
            try
            {
                _logger.LogInformation("Received batch request for label scan records");

                // 调用服务分页获取标签扫描记录
                var (pagedRecords, totalCount) = await _labelScanService.GetLabelScanRecordsByPageAsync(
                    page, pageSize, sortBy, sortOrder, customerId, referenceNumber,
                    neutralWaybillNumber, finalMileTrackingNumber, result,
                    startCreatedAt, endCreatedAt
                );

                var scanResult = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    totalCount = totalCount,
                    page = page,
                    pageSize = pageSize,
                    totalPages = (int)Math.Ceiling((double)totalCount / pageSize),
                    data = pagedRecords
                };

                // 处理 JSONP 请求
                if (!string.IsNullOrEmpty(callback))
                {
                    var jsonResult = System.Text.Json.JsonSerializer.Serialize(scanResult);
                    var jsonpResult = $"{callback}({jsonResult})";
                    return Content(jsonpResult, "application/javascript");
                }

                return Ok(scanResult);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving batch label scan records");
                var errorResult = new
                {
                    status = "error",
                    message = "An unexpected error occurred during batch retrieval.",
                    errorDetails = ex.Message
                };

                // 处理 JSONP 错误
                if (!string.IsNullOrEmpty(callback))
                {
                    var jsonResult = System.Text.Json.JsonSerializer.Serialize(errorResult);
                    var jsonpResult = $"{callback}({jsonResult})";
                    return Content(jsonpResult, "application/javascript");
                }

                return Ok(errorResult);
            }
        }

        /// <summary>
        /// 导出标签替换请求为Excel
        /// </summary>
        [HttpGet("label-replace/export-excel")]
        public async Task<IActionResult> ExportLabelReplaceToExcel(
            [FromQuery] string billOfLadingNumber = null,
            [FromQuery] string masterPackageNumber = null,
            [FromQuery] string referenceNumber = null,
            [FromQuery] string neutralWaybillNumber = null,
            [FromQuery] string finalMileTrackingNumber = null,
            [FromQuery] string replaceStatus = null,
            [FromQuery] int? customerId = null,
            [FromQuery] string startCreatedAt = null,
            [FromQuery] string endCreatedAt = null,
            [FromQuery] string startReplacedAt = null,
            [FromQuery] string endReplacedAt = null
        )
        {
            try
            {
                _logger.LogInformation("Received request to export label replace requests to Excel");

                // 获取所有符合条件的记录（不分页）
                var (requests, _) = await _labelReplaceService.GetLabelReplaceRequestsByPageAsync(
                    1, int.MaxValue, "CreatedAt", "desc",
                    billOfLadingNumber, masterPackageNumber,
                    referenceNumber, neutralWaybillNumber,
                    finalMileTrackingNumber, replaceStatus, customerId,
                    startCreatedAt, endCreatedAt, startReplacedAt, endReplacedAt
                );

                // 创建Excel文件
                using (var package = new OfficeOpenXml.ExcelPackage())
                {
                    var worksheet = package.Workbook.Worksheets.Add("Label Replace Requests");

                    // 设置表头
                    worksheet.Cells["A1"].Value = "ID";
                    worksheet.Cells["B1"].Value = "客户简称";
                    worksheet.Cells["C1"].Value = "提单号";
                    worksheet.Cells["D1"].Value = "大包号";
                    worksheet.Cells["E1"].Value = "参考号";
                    worksheet.Cells["F1"].Value = "中性面单单号";
                    worksheet.Cells["G1"].Value = "尾程跟踪单号";
                    worksheet.Cells["H1"].Value = "换单状态";
                    worksheet.Cells["I1"].Value = "换单完成时间";
                    worksheet.Cells["J1"].Value = "标签推送时间";
                    worksheet.Cells["K1"].Value = "标签URL";
                    worksheet.Cells["L1"].Value = "创建时间";
                    worksheet.Cells["M1"].Value = "更新时间";

                    // 填充数据
                    for (int i = 0; i < requests.Count; i++)
                    {
                        var request = requests[i];
                        int row = i + 2;

                        worksheet.Cells[$"A{row}"].Value = request.Id;
                        worksheet.Cells[$"B{row}"].Value = request.CustomerCode;
                        worksheet.Cells[$"C{row}"].Value = request.BillOfLadingNumber;
                        worksheet.Cells[$"D{row}"].Value = request.MasterPackageNumber;
                        worksheet.Cells[$"E{row}"].Value = request.ReferenceNumber;
                        worksheet.Cells[$"F{row}"].Value = request.NeutralWaybillNumber;
                        worksheet.Cells[$"G{row}"].Value = request.FinalMileTrackingNumber;
                        worksheet.Cells[$"H{row}"].Value = request.ReplaceStatus;
                        worksheet.Cells[$"I{row}"].Value = request.ReplacedAt?.ToString("yyyy-MM-dd HH:mm:ss");
                        worksheet.Cells[$"J{row}"].Value = request.LabelRetrievedAt?.ToString("yyyy-MM-dd HH:mm:ss");
                        worksheet.Cells[$"K{row}"].Value = request.Label;
                        worksheet.Cells[$"L{row}"].Value = request.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss");
                        worksheet.Cells[$"M{row}"].Value = request.UpdatedAt.ToString("yyyy-MM-dd HH:mm:ss");
                    }

                    // 自动调整列宽
                    worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();

                    // 导出文件
                    var stream = new System.IO.MemoryStream();
                    package.SaveAs(stream);
                    stream.Position = 0;

                    var fileName = $"LabelReplaceRequests_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.xlsx";
                    return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error exporting label replace requests to Excel");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during export.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 批量取消订单
        /// </summary>
        [HttpPost("label-replace/batch-cancel")]
        public async Task<IActionResult> BatchCancelOrders([FromBody] BatchCancelRequest request)
        {
            try
            {
                if (request == null || request.WaybillNumbers == null || request.WaybillNumbers.Count == 0)
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Waybill numbers are required"
                    });
                }

                _logger.LogInformation("Received batch cancel request for {count} orders", request.WaybillNumbers.Count);

                // 调用服务批量取消订单
                var result = await _labelReplaceService.BatchCancelOrdersAsync(
                    request.CustomerCode,
                    request.ApiKey,
                    request.WaybillNumbers
                );

                return Ok(new
                {
                    status = result.Status,
                    timestamp = result.Timestamp,
                    successCount = result.SuccessCount,
                    failedCount = result.FailedCount,
                    failedItems = result.FailedItems,
                    message = result.Message
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing batch cancel request");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during batch cancellation.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 批量取消订单请求模型
        /// </summary>
        public class BatchCancelRequest
        {
            /// <summary>
            /// 客户代码
            /// </summary>
            public string CustomerCode { get; set; }

            /// <summary>
            /// API密钥
            /// </summary>
            public string ApiKey { get; set; }

            /// <summary>
            /// 中性面单单号列表
            /// </summary>
            public List<string> WaybillNumbers { get; set; }
        }

        /// <summary>
        /// 导出标签扫描记录为Excel
        /// </summary>
        [HttpGet("label-scan/export-excel")]
        public async Task<IActionResult> ExportLabelScanToExcel(
            [FromQuery] int? customerId = null,
            [FromQuery] string referenceNumber = null,
            [FromQuery] string neutralWaybillNumber = null,
            [FromQuery] string finalMileTrackingNumber = null,
            [FromQuery] int? result = null,
            [FromQuery] string startCreatedAt = null,
            [FromQuery] string endCreatedAt = null
        )
        {
            try
            {
                _logger.LogInformation("Received request to export label scan records to Excel");

                // 获取所有符合条件的记录（不分页）
                var (scans, _) = await _labelScanService.GetLabelScanRecordsByPageAsync(
                    1, int.MaxValue, "CreatedAt", "desc",
                    customerId, referenceNumber,
                    neutralWaybillNumber, finalMileTrackingNumber, result,
                    startCreatedAt, endCreatedAt
                );

                // 创建Excel文件
                using (var package = new OfficeOpenXml.ExcelPackage())
                {
                    var worksheet = package.Workbook.Worksheets.Add("Label Scan Records");

                    // 设置表头
                    worksheet.Cells["A1"].Value = "ID";
                    worksheet.Cells["B1"].Value = "客户简称";
                    worksheet.Cells["C1"].Value = "参考号";
                    worksheet.Cells["D1"].Value = "中性面单单号";
                    worksheet.Cells["E1"].Value = "尾程跟踪单号";
                    worksheet.Cells["F1"].Value = "扫描结果";
                    worksheet.Cells["G1"].Value = "描述";
                    worksheet.Cells["H1"].Value = "创建人";
                    worksheet.Cells["I1"].Value = "创建时间";
                    worksheet.Cells["J1"].Value = "更新时间";

                    // 扫描结果映射
                    var scanResultMap = new Dictionary<int, string>
                    {
                        { 0, "已返回面单" },
                        { 1, "无面单数据" },
                        { 2, "无下单数据" },
                        { 3, "订单被冻结" },
                        { 4, "订单已销毁" },
                        { 5, "其他" }
                    };

                    // 填充数据
                    for (int i = 0; i < scans.Count; i++)
                    {
                        var scan = scans[i];
                        int row = i + 2;

                        worksheet.Cells[$"A{row}"].Value = scan.Id;
                        worksheet.Cells[$"B{row}"].Value = scan.CustomerCode;
                        worksheet.Cells[$"C{row}"].Value = scan.ReferenceNumber;
                        worksheet.Cells[$"D{row}"].Value = scan.NeutralWaybillNumber;
                        worksheet.Cells[$"E{row}"].Value = scan.FinalMileTrackingNumber;
                        worksheet.Cells[$"F{row}"].Value = scanResultMap.TryGetValue((int)scan.Result, out var resultText) ? resultText : scan.Result.ToString();
                        worksheet.Cells[$"G{row}"].Value = scan.Description;
                        worksheet.Cells[$"H{row}"].Value = scan.CreatedBy;
                        worksheet.Cells[$"I{row}"].Value = scan.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss"); worksheet.Cells[$"J{row}"].Value = scan.UpdatedAt.ToString("yyyy-MM-dd HH:mm:ss");
                    }

                    // 自动调整列宽
                    worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();

                    // 导出文件
                    var stream = new System.IO.MemoryStream();
                    package.SaveAs(stream);
                    stream.Position = 0;

                    var fileName = $"LabelScanRecords_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.xlsx";
                    return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error exporting label scan records to Excel");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during export.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 获取客户列表
        /// </summary>
        [HttpGet("customers")]
        public async Task<IActionResult> GetCustomers(
            [FromQuery] string callback = null
        )
        {
            try
            {
                _logger.LogInformation("Received request to get customers list");

                // 获取所有客户
                var customers = await _customerRepository.GetAllAsync();

                var result = new
                {
                    status = "ok",
                    timestamp = DateTime.UtcNow,
                    data = customers
                };

                // 处理 JSONP 请求
                if (!string.IsNullOrEmpty(callback))
                {
                    var jsonResult = System.Text.Json.JsonSerializer.Serialize(result);
                    var jsonpResult = $"{callback}({jsonResult})";
                    return Content(jsonpResult, "application/javascript");
                }

                return Ok(result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving customers list");
                var errorResult = new
                {
                    status = "error",
                    message = "An unexpected error occurred during customers retrieval.",
                    errorDetails = ex.Message
                };

                // 处理 JSONP 错误
                if (!string.IsNullOrEmpty(callback))
                {
                    var jsonResult = System.Text.Json.JsonSerializer.Serialize(errorResult);
                    var jsonpResult = $"{callback}({jsonResult})";
                    return Content(jsonpResult, "application/javascript");
                }

                return Ok(errorResult);
            }
        }

        /// <summary>
        /// 获取对象属性值
        /// </summary>
        private object GetPropertyValue(object obj, string propertyName)
        {
            var property = obj.GetType().GetProperty(propertyName);
            return property?.GetValue(obj) ?? string.Empty;
        }

        /// <summary>
        /// 批量查询换单状态
        /// </summary>
        [HttpPost("label-replace/status")]
        public async Task<IActionResult> GetLabelReplaceStatus([FromBody] LabelReplaceStatusRequest request)
        {
            try
            {
                // 从请求头获取customerCode和apiKey
                var customerCode = Request.Headers["customerCode"].FirstOrDefault();
                var apiKey = Request.Headers["apiKey"].FirstOrDefault();

                // 验证头部参数
                if (string.IsNullOrEmpty(customerCode) || string.IsNullOrEmpty(apiKey))
                {
                    return Ok(new
                    {
                        code = 400,
                        message = "customerCode and apiKey are required in headers"
                    });
                }

                // 验证API凭证
                var customerApiInfo = await _customerApiRepository.ValidateAndGetApiCredentialsAsync(customerCode, apiKey);
                if (customerApiInfo == null)
                {
                    return Ok(new
                    {
                        code = 401,
                        message = "Invalid API credentials. Please check your customerCode and apiKey."
                    });
                }

                // 验证CustomerId是否在customers表中存在
                var customerExists = await _customerRepository.GetByIdAsync(customerApiInfo.CustomerId) != null;
                if (!customerExists)
                {
                    return Ok(new
                    {
                        code = 500,
                        message = "Internal server error: Invalid customer configuration."
                    });
                }

                // 验证请求参数
                if (request == null)
                {
                    return Ok(new
                    {
                        code = 400,
                        message = "Request body is required"
                    });
                }

                // 验证至少提供了一个单号参数
                var waybillNumbers = new List<string>();
                var trackingNumbers = new List<string>();

                if (request.numbers != null && request.numbers.Count > 0)
                {
                    // 将所有单号同时用于中性面单和尾程单号查询
                    waybillNumbers = request.numbers;
                    trackingNumbers = request.numbers;
                }
                else
                {
                    return Ok(new
                    {
                        code = 400,
                        message = "Numbers parameter is required"
                    });
                }

                _logger.LogInformation("Received request to get label replace status. CustomerCode: {customerCode}, Numbers: {numberCount}",
                    customerCode, waybillNumbers.Count);

                // 调用服务获取换单状态
                var results = await _labelReplaceService.GetLabelReplaceStatusAsync(customerCode, waybillNumbers, trackingNumbers);

                var response = new
                {
                    code = 200,
                    timestamp = DateTime.UtcNow,
                    count = results.Count,
                    data = results
                };

                return Ok(response);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving label replace status");
                return Ok(new
                {
                    code = 500,
                    message = "An unexpected error occurred.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 批量查询换单状态请求模型
        /// </summary>
        public class LabelReplaceStatusRequest
        {
            /// <summary>
            /// 单号列表（中性面单或尾程单号）
            /// </summary>
            public List<string> numbers { get; set; }
        }

        /// <summary>
        /// 将指定中性面单号对应的Label从base64转换为URL格式，保持LabelRetrievedAt不变
        /// </summary>
        [HttpPost("label-replace/convert-base64-to-url")]
        public async Task<IActionResult> ConvertBase64LabelToUrl([FromBody] ConvertBase64ToUrlRequest request)
        {
            try
            {
                if (request == null || string.IsNullOrEmpty(request.NeutralWaybillNumber))
                {
                    return Ok(new
                    {
                        status = "error",
                        message = "Neutral waybill number is required"
                    });
                }

                _logger.LogInformation("Received request to convert base64 label to URL for waybill: {number}", request.NeutralWaybillNumber);

                // 调用服务进行转换
                var result = await _labelReplaceService.ConvertBase64LabelToUrlAsync(request.NeutralWaybillNumber);

                return Ok(new
                {
                    status = result.Status,
                    timestamp = result.Timestamp,
                    neutralWaybillNumber = result.NeutralWaybillNumber,
                    converted = result.Converted,
                    url = result.Url,
                    message = result.Message,
                    errorDetails = result.ErrorDetails
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error converting base64 label to URL");
                return Ok(new
                {
                    status = "error",
                    message = "An unexpected error occurred during conversion.",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 批量解析订单标签数据 - 用于补充解析已有的订单标签
        /// </summary>
        /// <param name="request">解析请求</param>
        /// <returns>解析结果</returns>
        [HttpPost("batch-parse")]
        public async Task<IActionResult> BatchParseLabels([FromBody] BatchParseLabelRequest request)
        {
            var startTime = DateTime.UtcNow;
            var startTimestamp = new DateTimeOffset(startTime).ToUnixTimeMilliseconds();
            var processRecords = new List<BatchProcessItemRecord>();

            try
            {
                if (request == null || string.IsNullOrEmpty(request.Mode))
                {
                    return BadRequest(new { message = "请提供有效的请求参数" });
                }

                _logger.LogInformation("Starting batch parse labels, mode: {mode}", request.Mode);

                int processedCount = 0;
                int successCount = 0;
                int errorCount = 0;

                switch (request.Mode.ToLower())
                {
                    case "all":
                    {
                        var allOrders = await _labelReplaceService.GetAllOrdersWithLabelsAsync(request.Limit ?? 1000);
                        processedCount = allOrders.Count;
                        foreach (var order in allOrders)
                        {
                            var itemStartTime = DateTime.UtcNow;
                            var itemRecord = new BatchProcessItemRecord
                            {
                                WaybillNumber = order.NeutralWaybillNumber,
                                Timestamp = new DateTimeOffset(itemStartTime).ToUnixTimeMilliseconds()
                            };

                            var (isSuccess, errorMessage) = await _labelPdfCacheService.ProcessSingleCacheTaskAsync(order.NeutralWaybillNumber);
                            if (isSuccess)
                            {
                                successCount++;
                                itemRecord.Status = "success";
                            }
                            else
                            {
                                errorCount++;
                                itemRecord.Status = "error";
                                itemRecord.ErrorMessage = errorMessage;
                            }

                            itemRecord.Duration = (int)(DateTime.UtcNow - itemStartTime).TotalMilliseconds;
                            processRecords.Add(itemRecord);
                        }
                        break;
                    }

                    case "range":
                    {
                        if (!request.StartDate.HasValue || !request.EndDate.HasValue)
                        {
                            return BadRequest(new { message = "时间范围模式需要 StartDate 和 EndDate 参数" });
                        }

                        var rangeOrders = await _labelReplaceService.GetOrdersWithLabelsByDateRangeAsync(
                            request.StartDate.Value, request.EndDate.Value, request.Limit ?? 1000);
                        processedCount = rangeOrders.Count;

                        foreach (var order in rangeOrders)
                        {
                            var itemStartTime = DateTime.UtcNow;
                            var itemRecord = new BatchProcessItemRecord
                            {
                                WaybillNumber = order.NeutralWaybillNumber,
                                Timestamp = new DateTimeOffset(itemStartTime).ToUnixTimeMilliseconds()
                            };

                            var (isSuccess, errorMessage) = await _labelPdfCacheService.ProcessSingleCacheTaskAsync(order.NeutralWaybillNumber);
                            if (isSuccess)
                            {
                                successCount++;
                                itemRecord.Status = "success";
                            }
                            else
                            {
                                errorCount++;
                                itemRecord.Status = "error";
                                itemRecord.ErrorMessage = errorMessage;
                            }

                            itemRecord.Duration = (int)(DateTime.UtcNow - itemStartTime).TotalMilliseconds;
                            processRecords.Add(itemRecord);
                        }
                        break;
                    }

                    case "customer":
                    {
                        if (!request.CustomerId.HasValue)
                        {
                            return BadRequest(new { message = "客户模式需要 CustomerId 参数" });
                        }

                        var customerOrders = await _labelReplaceService.GetOrdersWithLabelsByCustomerAsync(
                            request.CustomerId.Value, request.Limit ?? 1000);
                        processedCount = customerOrders.Count;

                        foreach (var order in customerOrders)
                        {
                            var itemStartTime = DateTime.UtcNow;
                            var itemRecord = new BatchProcessItemRecord
                            {
                                WaybillNumber = order.NeutralWaybillNumber,
                                Timestamp = new DateTimeOffset(itemStartTime).ToUnixTimeMilliseconds()
                            };

                            var (isSuccess, errorMessage) = await _labelPdfCacheService.ProcessSingleCacheTaskAsync(order.NeutralWaybillNumber);
                            if (isSuccess)
                            {
                                successCount++;
                                itemRecord.Status = "success";
                            }
                            else
                            {
                                errorCount++;
                                itemRecord.Status = "error";
                                itemRecord.ErrorMessage = errorMessage;
                            }

                            itemRecord.Duration = (int)(DateTime.UtcNow - itemStartTime).TotalMilliseconds;
                            processRecords.Add(itemRecord);
                        }
                        break;
                    }

                    case "single":
                    {
                        if (string.IsNullOrEmpty(request.WaybillNumber))
                        {
                            return BadRequest(new { message = "单条模式需要 WaybillNumber 参数" });
                        }

                        processedCount = 1;
                        var singleItemStartTime = DateTime.UtcNow;
                        var singleRecord = new BatchProcessItemRecord
                        {
                            WaybillNumber = request.WaybillNumber,
                            Timestamp = new DateTimeOffset(singleItemStartTime).ToUnixTimeMilliseconds()
                        };

                        var (isSuccess, errorMessage) = await _labelPdfCacheService.ProcessSingleCacheTaskAsync(request.WaybillNumber);
                        if (isSuccess)
                        {
                            successCount = 1;
                            singleRecord.Status = "success";
                        }
                        else
                        {
                            errorCount = 1;
                            singleRecord.Status = "error";
                            singleRecord.ErrorMessage = errorMessage;
                        }

                        singleRecord.Duration = (int)(DateTime.UtcNow - singleItemStartTime).TotalMilliseconds;
                        processRecords.Add(singleRecord);
                        break;
                    }

                    case "batch":
                    {
                        if (request.WaybillNumbers == null || request.WaybillNumbers.Count == 0)
                        {
                            return BadRequest(new { message = "批量模式需要 WaybillNumbers 参数（订单号数组）" });
                        }

                        processedCount = request.WaybillNumbers.Count;
                        foreach (var waybillNumber in request.WaybillNumbers)
                        {
                            var itemStartTime = DateTime.UtcNow;
                            var itemRecord = new BatchProcessItemRecord
                            {
                                WaybillNumber = waybillNumber,
                                Timestamp = new DateTimeOffset(itemStartTime).ToUnixTimeMilliseconds()
                            };

                            var (isSuccess, errorMessage) = await _labelPdfCacheService.ProcessSingleCacheTaskAsync(waybillNumber);
                            if (isSuccess)
                            {
                                successCount++;
                                itemRecord.Status = "success";
                            }
                            else
                            {
                                errorCount++;
                                itemRecord.Status = "error";
                                itemRecord.ErrorMessage = errorMessage;
                            }

                            itemRecord.Duration = (int)(DateTime.UtcNow - itemStartTime).TotalMilliseconds;
                            processRecords.Add(itemRecord);
                        }
                        break;
                    }

                    default:
                        return BadRequest(new
                        {
                            message = "无效的处理模式，请使用: all, range, customer, single, batch"
                        });
                }

                var endTime = DateTime.UtcNow;
                var endTimestamp = new DateTimeOffset(endTime).ToUnixTimeMilliseconds();
                var totalDuration = (endTimestamp - startTimestamp);

                _logger.LogInformation("Batch parse completed. Total: {total}, Success: {success}, Error: {error}, Duration: {duration}ms",
                    processedCount, successCount, errorCount, totalDuration);

                return Ok(new
                {
                    status = "success",
                    message = "批量解析完成",
                    data = new
                    {
                        totalProcessed = processedCount,
                        successCount = successCount,
                        errorCount = errorCount,
                        mode = request.Mode,
                        startTimestamp = startTimestamp,
                        endTimestamp = endTimestamp,
                        totalDuration = totalDuration,
                        processRecords = processRecords
                    }
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in batch parse labels");
                var endTime = DateTime.UtcNow;
                var endTimestamp = new DateTimeOffset(endTime).ToUnixTimeMilliseconds();
                var totalDuration = (endTimestamp - startTimestamp);

                return Ok(new
                {
                    status = "error",
                    message = "批量解析失败",
                    errorDetails = ex.Message,
                    data = new
                    {
                        startTimestamp = startTimestamp,
                        endTimestamp = endTimestamp,
                        totalDuration = totalDuration,
                        processRecords = processRecords
                    }
                });
            }
        }

        /// <summary>
        /// 查看缓存统计信息
        /// </summary>
        [HttpGet("cache-statistics")]
        public async Task<IActionResult> GetCacheStatistics()
        {
            try
            {
                var stats = await _labelPdfCacheService.GetCacheStatisticsAsync();

                return Ok(new
                {
                    status = "success",
                    message = "缓存统计信息",
                    data = stats
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting cache statistics");
                return Ok(new
                {
                    status = "error",
                    message = "获取统计信息失败",
                    errorDetails = ex.Message
                });
            }
        }

        /// <summary>
        /// 批量推送扫描记录到客户系统
        /// </summary>
        [HttpPost("webhook/batch-push")]
        public async Task<IActionResult> BatchPushWebhook([FromBody] MDL.DTOs.BatchPushRequestDto request)
        {
            try
            {
                _logger.LogInformation("Received batch push webhook request");

                // 参数校验
                if (request == null)
                {
                    return Ok(new MDL.DTOs.BatchPushResponseDto
                    {
                        Status = "error",
                        Message = "请求参数不能为空",
                        TotalOrders = 0,
                        PushedCount = 0,
                        SkippedCount = 0,
                        Details = new List<MDL.DTOs.PushResultDetail>()
                    });
                }

                // 检查订单号列表
                bool hasWaybillNumbers = request.WaybillNumbers != null && request.WaybillNumbers.Count > 0;

                // 验证订单号数量限制（最大2000条）
                if (hasWaybillNumbers && request.WaybillNumbers.Count > 2000)
                {
                    return Ok(new MDL.DTOs.BatchPushResponseDto
                    {
                        Status = "error",
                        Message = "单次批量推送最多支持2000条订单",
                        TotalOrders = 0,
                        PushedCount = 0,
                        SkippedCount = 0,
                        Details = new List<MDL.DTOs.PushResultDetail>()
                    });
                }

                // 解析时间参数
                DateTime? startTime = null;
                DateTime? endTime = null;
                if (!string.IsNullOrEmpty(request.StartTime) && DateTime.TryParse(request.StartTime, out DateTime parsedStartTime))
                {
                    startTime = parsedStartTime.ToUniversalTime();
                }
                if (!string.IsNullOrEmpty(request.EndTime) && DateTime.TryParse(request.EndTime, out DateTime parsedEndTime))
                {
                    endTime = parsedEndTime.ToUniversalTime();
                }

                // 如果指定了客户代码，获取客户ID
                int? targetCustomerId = null;
                string targetCustomerCode = null;
                if (!string.IsNullOrEmpty(request.CustomerCode))
                {
                    var customer = await _customerRepository.GetByCustomerCodeAsync(request.CustomerCode);
                    if (customer != null)
                    {
                        targetCustomerId = customer.Id;
                        targetCustomerCode = customer.CustomerCode;
                    }
                    else
                    {
                        return Ok(new MDL.DTOs.BatchPushResponseDto
                        {
                            Status = "error",
                            Message = $"未找到客户代码: {request.CustomerCode}",
                            TotalOrders = 0,
                            PushedCount = 0,
                            SkippedCount = 0,
                            Details = new List<MDL.DTOs.PushResultDetail>()
                        });
                    }
                }

                // 获取最新扫描记录
                var scanRecords = await _labelScanService.GetLatestScanRecordsAsync(
                    request.WaybillNumbers,
                    startTime,
                    endTime,
                    targetCustomerId
                );

                _logger.LogInformation("Found {count} latest scan records for batch push", scanRecords.Count);

                // 批量获取客户信息
                var customerIds = scanRecords.Select(s => s.CustomerId).Distinct().ToList();
                var customers = await _customerRepository.GetByIdsAsync(customerIds);
                var customerMap = customers.ToDictionary(c => c.Id, c => c);

                // 准备推送结果列表
                var details = new List<MDL.DTOs.PushResultDetail>();
                int pushedCount = 0;
                int skippedCount = 0;

                // 逐个推送
                foreach (var record in scanRecords)
                {
                    var detail = new MDL.DTOs.PushResultDetail
                    {
                        WaybillNumber = record.NeutralWaybillNumber,
                        ScanTime = record.CreatedAt
                    };

                    // 获取客户信息
                    if (customerMap.TryGetValue(record.CustomerId, out var customer))
                    {
                        detail.CustomerCode = customer.CustomerCode;

                        // 如果指定了目标客户代码，只处理匹配的客户
                        if (!string.IsNullOrEmpty(targetCustomerCode) && detail.CustomerCode != targetCustomerCode)
                        {
                            detail.Success = false;
                            detail.Message = "客户不匹配，跳过";
                            skippedCount++;
                            details.Add(detail);
                            continue;
                        }

                        // 根据客户代码调用对应的webhook方法
                        try
                        {
                            await SendWebhookByCustomerCode(
                                customer.CustomerCode,
                                record.NeutralWaybillNumber,
                                record.CreatedAt,
                                null,  // printTime 从扫描记录中无法获取
                                record.Result,
                                record.Description,
                                record.FinalMileTrackingNumber
                            );

                            detail.Success = true;
                            detail.Message = "推送成功";
                            pushedCount++;
                            _logger.LogInformation("Successfully pushed webhook for waybill: {number}, customer: {customer}", 
                                record.NeutralWaybillNumber, customer.CustomerCode);
                        }
                        catch (Exception ex)
                        {
                            detail.Success = false;
                            detail.Message = $"推送失败: {ex.Message}";
                            skippedCount++;
                            _logger.LogError(ex, "Failed to push webhook for waybill: {number}, customer: {customer}", 
                                record.NeutralWaybillNumber, customer.CustomerCode);
                        }
                    }
                    else
                    {
                        detail.Success = false;
                        detail.Message = "未找到客户信息";
                        skippedCount++;
                    }

                    details.Add(detail);
                }

                // 返回结果
                return Ok(new MDL.DTOs.BatchPushResponseDto
                {
                    Status = "ok",
                    Message = "批量推送完成",
                    TotalOrders = scanRecords.Count,
                    PushedCount = pushedCount,
                    SkippedCount = skippedCount,
                    Details = details
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in batch push webhook");
                return Ok(new MDL.DTOs.BatchPushResponseDto
                {
                    Status = "error",
                    Message = $"批量推送过程中发生错误: {ex.Message}",
                    TotalOrders = 0,
                    PushedCount = 0,
                    SkippedCount = 0,
                    Details = new List<MDL.DTOs.PushResultDetail>()
                });
            }
        }

        /// <summary>
        /// 根据客户代码发送webhook
        /// </summary>
        private async Task SendWebhookByCustomerCode(
            string customerCode,
            string waybillNumber,
            DateTime scanTime,
            DateTime? printTime,
            ScanResult scanResult,
            string scanDescription,
            string finalMileTrackingNumber)
        {
            switch (customerCode)
            {
                case "PT_GZ":
                    await SendWebhookToPatuen(waybillNumber, scanTime, printTime);
                    break;
                case "XT_JX":
                    await SendWebhookToXunTong(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                    break;
                case "ZY_SH":
                    await SendWebhookToZunYou(waybillNumber, scanTime, printTime, scanResult, finalMileTrackingNumber);
                    break;
                case "IDI_ZJ":
                    await SendWebhookToIDI(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                    break;
                case "WEM_ZJ":
                    await SendWebhookToWEM(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                    break;
                case "BDGJ_YW":
                    await SendWebhookToBDGJ(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                    break;
                case "ZYT_GZ":
                    await SendWebhookToZYT(waybillNumber, scanTime, printTime, scanResult, scanDescription);
                    break;
                default:
                    _logger.LogWarning("No webhook method configured for customer: {customer}", customerCode);
                    break;
            }
        }
    }
}