using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models;
using HoneyBox.Model.Models.Order;
using HoneyBox.Model.Models.Payment;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 仓库服务实现
/// </summary>
public class WarehouseService : IWarehouseService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<WarehouseService> _logger;
    private readonly ILogisticsService _logisticsService;
    private readonly IWechatPayService _wechatPayService;

    public WarehouseService(
        HoneyBoxDbContext dbContext, 
        ILogger<WarehouseService> logger,
        ILogisticsService logisticsService,
        IWechatPayService wechatPayService)
    {
        _dbContext = dbContext;
        _logger = logger;
        _logisticsService = logisticsService;
        _wechatPayService = wechatPayService;
    }

    #region 仓库查询

    /// <inheritdoc />
    public async Task<WarehouseIndexResponseDto> GetWarehouseIndexAsync(int userId, WarehouseIndexRequest request)
    {
        var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        var showDadajuan = true;

        // 自动将预售商品转为现货（当sale_time <= 当前时间）
        await AutoConvertPresaleToAvailableAsync(userId, currentTime);

        var response = new WarehouseIndexResponseDto();

        switch (request.Type)
        {
            case 1: // 赏品
                response = await GetPrizesWarehouseAsync(userId, request, currentTime);
                showDadajuan = await CheckShowDadajuanAsync(userId, response.Data.Any());
                break;
            case 2: // 预售
                response = await GetPresaleWarehouseAsync(userId, request);
                break;
            case 3: // 卡册
                response = await GetCardAlbumWarehouseAsync(userId, request);
                break;
            case 4: // 保险柜
                response = await GetSafeWarehouseAsync(userId, request);
                break;
            case 5: // 无限赏
                response = await GetInfiniteWarehouseAsync(userId, request);
                break;
            default:
                throw new InvalidOperationException("请求错误");
        }

        // 获取运费设置
        response.Yufei = await GetShippingFeeConfigAsync(request.Type);
        response.ShowDadajuan = showDadajuan;

        return response;
    }

    /// <summary>
    /// 自动将预售商品转为现货
    /// </summary>
    private async Task AutoConvertPresaleToAvailableAsync(int userId, long currentTime)
    {
        var presaleItems = await _dbContext.OrderItems
            .Where(o => o.UserId == userId && o.Status == 0 && o.GoodslistType == 2)
            .Select(o => new { o.Id, o.GoodslistId, o.UserId, o.GoodslistSaleTime })
            .ToListAsync();

        var currentDateTime = DateTimeOffset.FromUnixTimeSeconds(currentTime).DateTime;

        foreach (var item in presaleItems)
        {
            var goodsItem = await _dbContext.GoodsItems
                .Where(g => g.Id == item.GoodslistId)
                .Select(g => new { g.SaleTime })
                .FirstOrDefaultAsync();

            bool shouldConvert = false;
            if (goodsItem?.SaleTime != null)
            {
                shouldConvert = goodsItem.SaleTime <= currentDateTime;
            }
            else if (item.GoodslistSaleTime > 0 && item.GoodslistSaleTime <= currentTime)
            {
                shouldConvert = true;
            }

            if (shouldConvert)
            {
                await _dbContext.OrderItems
                    .Where(o => o.Id == item.Id && o.Status == 0 && o.UserId == userId && o.GoodslistType == 2)
                    .ExecuteUpdateAsync(s => s.SetProperty(o => o.GoodslistType, (byte)1));
            }
        }
    }

    /// <summary>
    /// 获取赏品仓库（type=1）
    /// </summary>
    private async Task<WarehouseIndexResponseDto> GetPrizesWarehouseAsync(int userId, WarehouseIndexRequest request, long currentTime)
    {
        var response = new WarehouseIndexResponseDto();
        var total = 0;

        var goodsGroups = await _dbContext.OrderItems
            .Where(o => o.UserId == userId 
                && o.Status == 0 
                && o.GoodslistType == 1 
                && o.InsuranceIs == 0 
                && o.OrderType != 4)
            .GroupBy(o => o.GoodsId)
            .Select(g => g.Key)
            .OrderBy(g => g)
            .ToListAsync();

        foreach (var goodsId in goodsGroups)
        {
            var goodsTitle = await GetGoodsTitleAsync(goodsId);

            var query = _dbContext.OrderItems
                .Where(o => o.GoodsId == goodsId
                    && o.UserId == userId
                    && o.Status == 0
                    && o.GoodslistType == 1
                    && o.InsuranceIs == 0
                    && o.OrderType != 4);

            if (!string.IsNullOrEmpty(request.Keyword))
            {
                query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
            }

            var orderListItems = await query
                .GroupBy(o => o.PrizeCode)
                .Select(g => new
                {
                    Id = g.First().Id,
                    GoodslistTitle = g.First().GoodslistTitle,
                    GoodslistImgurl = g.First().GoodslistImgurl,
                    GoodslistMoney = g.First().GoodslistMoney,
                    GoodsId = g.First().GoodsId,
                    ShangId = g.First().ShangId,
                    PrizeCode = g.Key,
                    PrizeNum = g.Count()
                })
                .OrderBy(o => o.ShangId)
                .ToListAsync();

            var orderListDtos = new List<WarehouseItemDto>();
            foreach (var item in orderListItems)
            {
                var orderListIds = await _dbContext.OrderItems
                    .Where(o => o.GoodsId == item.GoodsId
                        && o.UserId == userId
                        && o.Status == 0
                        && o.GoodslistType == 1
                        && o.InsuranceIs == 0
                        && o.OrderType != 4 && o.OrderType != 9
                        && o.PrizeCode == item.PrizeCode)
                    .OrderBy(o => o.ShangId)
                    .Select(o => o.Id)
                    .ToListAsync();

                var shangTitle = await GetShangTitleAsync(item.ShangId);

                orderListDtos.Add(new WarehouseItemDto
                {
                    Id = item.Id,
                    GoodsListTitle = item.GoodslistTitle ?? string.Empty,
                    GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
                    GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
                    GoodsId = item.GoodsId ?? 0,
                    ShangId = item.ShangId,
                    PrizeCode = item.PrizeCode,
                    PrizeNum = item.PrizeNum,
                    OrderListIds = orderListIds,
                    ShangTitle = shangTitle
                });
            }

            var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
            total += orderListTotal;

            response.Data.Add(new WarehouseGoodsGroupDto
            {
                GoodsId = goodsId ?? 0,
                GoodsTitle = goodsTitle,
                OrderList = orderListDtos,
                OrderListTotal = orderListTotal,
                OrderListLength = orderListDtos.Count
            });
        }

        response.Total = total;
        return response;
    }

    /// <summary>
    /// 获取预售仓库（type=2）
    /// </summary>
    private async Task<WarehouseIndexResponseDto> GetPresaleWarehouseAsync(int userId, WarehouseIndexRequest request)
    {
        var response = new WarehouseIndexResponseDto();
        var total = 0;

        var goodsGroups = await _dbContext.OrderItems
            .Where(o => o.UserId == userId 
                && o.Status == 0 
                && o.GoodslistType == 2 
                && o.InsuranceIs == 0 
                && o.OrderType != 4)
            .GroupBy(o => o.GoodsId)
            .Select(g => g.Key)
            .OrderBy(g => g)
            .ToListAsync();

        foreach (var goodsId in goodsGroups)
        {
            var goodsTitle = await GetGoodsTitleAsync(goodsId);

            var query = _dbContext.OrderItems
                .Where(o => o.GoodsId == goodsId
                    && o.UserId == userId
                    && o.Status == 0
                    && o.GoodslistType == 2
                    && o.InsuranceIs == 0
                    && o.OrderType != 4);

            if (!string.IsNullOrEmpty(request.Keyword))
            {
                query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
            }

            var orderListItems = await query
                .GroupBy(o => o.PrizeCode)
                .Select(g => new
                {
                    GoodslistTitle = g.First().GoodslistTitle,
                    GoodslistImgurl = g.First().GoodslistImgurl,
                    GoodslistMoney = g.First().GoodslistMoney,
                    GoodsId = g.First().GoodsId,
                    ShangId = g.First().ShangId,
                    PrizeCode = g.Key,
                    GoodslistSaleTime = g.First().GoodslistSaleTime,
                    PrizeNum = g.Count()
                })
                .OrderBy(o => o.ShangId)
                .ToListAsync();

            var orderListDtos = new List<WarehouseItemDto>();
            foreach (var item in orderListItems)
            {
                var shangTitle = await GetShangTitleAsync(item.ShangId);

                orderListDtos.Add(new WarehouseItemDto
                {
                    GoodsListTitle = item.GoodslistTitle ?? string.Empty,
                    GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
                    GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
                    GoodsId = item.GoodsId ?? 0,
                    ShangId = item.ShangId,
                    PrizeCode = item.PrizeCode,
                    PrizeNum = item.PrizeNum,
                    ShangTitle = shangTitle,
                    GoodsListSaleTime = item.GoodslistSaleTime > 0 
                        ? DateTimeOffset.FromUnixTimeSeconds(item.GoodslistSaleTime).ToString("yyyy-MM-dd") 
                        : null
                });
            }

            var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
            total += orderListTotal;

            response.Data.Add(new WarehouseGoodsGroupDto
            {
                GoodsId = goodsId ?? 0,
                GoodsTitle = goodsTitle,
                OrderList = orderListDtos,
                OrderListTotal = orderListTotal,
                OrderListLength = orderListDtos.Count
            });
        }

        response.Total = total;
        return response;
    }

    /// <summary>
    /// 获取卡册仓库（type=3）
    /// </summary>
    private async Task<WarehouseIndexResponseDto> GetCardAlbumWarehouseAsync(int userId, WarehouseIndexRequest request)
    {
        var response = new WarehouseIndexResponseDto();
        var pageSize = 30;

        var query = _dbContext.Orders
            .Where(o => o.UserId == userId && o.OrderType == 4);

        if (!string.IsNullOrEmpty(request.Keyword))
        {
            query = query.Where(o => o.GoodsTitle != null && o.GoodsTitle.Contains(request.Keyword));
        }

        if (request.CategoryId > 0)
        {
            var goodsIdsInCategory = await _dbContext.Goods
                .Where(g => g.CategoryId == request.CategoryId && g.DeletedAt == null)
                .Select(g => g.Id)
                .ToListAsync();
            query = query.Where(o => goodsIdsInCategory.Contains(o.GoodsId));
        }

        var groupedOrders = await query
            .GroupBy(o => o.GoodsId)
            .Select(g => new { GoodsId = g.Key, OrderId = g.Max(o => o.Id) })
            .OrderByDescending(g => g.OrderId)
            .Skip((request.Page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var totalGroups = await query.GroupBy(o => o.GoodsId).CountAsync();
        response.LastPage = (int)Math.Ceiling((double)totalGroups / pageSize);

        foreach (var group in groupedOrders)
        {
            var order = await _dbContext.Orders
                .Where(o => o.Id == group.OrderId)
                .Select(o => new { o.Id, o.GoodsId, o.GoodsTitle, o.GoodsImgurl })
                .FirstOrDefaultAsync();

            if (order == null) continue;

            var goods = await _dbContext.Goods
                .Where(g => g.Id == group.GoodsId && g.DeletedAt == null)
                .Select(g => new { g.Title, g.CardBanner })
                .FirstOrDefaultAsync();

            var goodsTitle = goods?.Title ?? order.GoodsTitle ?? string.Empty;
            var goodsImgUrl = FormatImageUrl(goods?.CardBanner ?? order.GoodsImgurl);

            var allCount = await _dbContext.GoodsItems
                .Where(g => g.GoodsId == group.GoodsId)
                .CountAsync();

            var buyCount = await _dbContext.OrderItems
                .Where(o => o.UserId == userId 
                    && o.GoodsId == group.GoodsId 
                    && o.Status == 0)
                .GroupBy(o => o.GoodslistId)
                .CountAsync();

            decimal gailv = 0;
            if (buyCount > 0 && allCount > 0)
            {
                gailv = Math.Round((decimal)buyCount / allCount * 100, 2);
            }

            response.Data.Add(new WarehouseGoodsGroupDto
            {
                GoodsId = group.GoodsId,
                GoodsTitle = goodsTitle,
                OrderList = new List<WarehouseItemDto>
                {
                    new WarehouseItemDto
                    {
                        Id = order.Id,
                        GoodsId = group.GoodsId,
                        GoodsTitle = goodsTitle,
                        GoodsListImgUrl = goodsImgUrl,
                        PrizeNum = buyCount
                    }
                },
                OrderListTotal = allCount,
                OrderListLength = buyCount
            });
        }

        return response;
    }

    /// <summary>
    /// 获取保险柜仓库（type=4）
    /// </summary>
    private async Task<WarehouseIndexResponseDto> GetSafeWarehouseAsync(int userId, WarehouseIndexRequest request)
    {
        var response = new WarehouseIndexResponseDto();
        var total = 0;

        var goodsGroups = await _dbContext.OrderItems
            .Where(o => o.UserId == userId 
                && o.Status == 0 
                && o.InsuranceIs == 1 
                && o.OrderType != 4)
            .GroupBy(o => o.GoodsId)
            .Select(g => g.Key)
            .OrderBy(g => g)
            .ToListAsync();

        foreach (var goodsId in goodsGroups)
        {
            var goodsTitle = await GetGoodsTitleAsync(goodsId);

            var query = _dbContext.OrderItems
                .Where(o => o.GoodsId == goodsId
                    && o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 1
                    && o.OrderType != 4);

            if (!string.IsNullOrEmpty(request.Keyword))
            {
                query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
            }

            var orderListItems = await query
                .GroupBy(o => o.PrizeCode)
                .Select(g => new
                {
                    GoodslistTitle = g.First().GoodslistTitle,
                    GoodslistImgurl = g.First().GoodslistImgurl,
                    GoodslistMoney = g.First().GoodslistMoney,
                    GoodsId = g.First().GoodsId,
                    ShangId = g.First().ShangId,
                    PrizeCode = g.Key,
                    PrizeNum = g.Count()
                })
                .OrderBy(o => o.ShangId)
                .ToListAsync();

            var orderListDtos = new List<WarehouseItemDto>();
            foreach (var item in orderListItems)
            {
                var shangTitle = await GetShangTitleAsync(item.ShangId);

                orderListDtos.Add(new WarehouseItemDto
                {
                    GoodsListTitle = item.GoodslistTitle ?? string.Empty,
                    GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
                    GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
                    GoodsId = item.GoodsId ?? 0,
                    ShangId = item.ShangId,
                    PrizeCode = item.PrizeCode,
                    PrizeNum = item.PrizeNum,
                    ShangTitle = shangTitle
                });
            }

            var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
            total += orderListTotal;

            response.Data.Add(new WarehouseGoodsGroupDto
            {
                GoodsId = goodsId ?? 0,
                GoodsTitle = goodsTitle,
                OrderList = orderListDtos,
                OrderListTotal = orderListTotal,
                OrderListLength = orderListDtos.Count
            });
        }

        response.Total = total;
        return response;
    }

    /// <summary>
    /// 获取无限赏仓库（type=5）
    /// </summary>
    private async Task<WarehouseIndexResponseDto> GetInfiniteWarehouseAsync(int userId, WarehouseIndexRequest request)
    {
        var response = new WarehouseIndexResponseDto();
        var total = 0;

        var goodsGroups = await _dbContext.OrderItems
            .Where(o => o.UserId == userId 
                && o.Status == 0 
                && o.GoodslistType == 1 
                && o.InsuranceIs == 0 
                && o.OrderType == 2)
            .GroupBy(o => o.GoodsId)
            .Select(g => g.Key)
            .OrderBy(g => g)
            .ToListAsync();

        foreach (var goodsId in goodsGroups)
        {
            var goodsTitle = await GetGoodsTitleAsync(goodsId);

            var query = _dbContext.OrderItems
                .Where(o => o.GoodsId == goodsId
                    && o.UserId == userId
                    && o.Status == 0
                    && o.GoodslistType == 1
                    && o.InsuranceIs == 0
                    && o.OrderType == 2);

            if (!string.IsNullOrEmpty(request.Keyword))
            {
                query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
            }

            var orderListItems = await query
                .GroupBy(o => o.PrizeCode)
                .Select(g => new
                {
                    Id = g.First().Id,
                    GoodslistTitle = g.First().GoodslistTitle,
                    GoodslistImgurl = g.First().GoodslistImgurl,
                    GoodslistMoney = g.First().GoodslistMoney,
                    GoodsId = g.First().GoodsId,
                    ShangId = g.First().ShangId,
                    PrizeCode = g.Key,
                    PrizeNum = g.Count()
                })
                .OrderBy(o => o.ShangId)
                .ToListAsync();

            var orderListDtos = new List<WarehouseItemDto>();
            foreach (var item in orderListItems)
            {
                var orderListIds = await _dbContext.OrderItems
                    .Where(o => o.GoodsId == item.GoodsId
                        && o.UserId == userId
                        && o.Status == 0
                        && o.GoodslistType == 1
                        && o.InsuranceIs == 0
                        && o.OrderType == 2
                        && o.PrizeCode == item.PrizeCode)
                    .OrderBy(o => o.ShangId)
                    .Select(o => o.Id)
                    .ToListAsync();

                var shangTitle = await GetShangTitleAsync(item.ShangId);

                orderListDtos.Add(new WarehouseItemDto
                {
                    Id = item.Id,
                    GoodsListTitle = item.GoodslistTitle ?? string.Empty,
                    GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
                    GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
                    GoodsId = item.GoodsId ?? 0,
                    ShangId = item.ShangId,
                    PrizeCode = item.PrizeCode,
                    PrizeNum = item.PrizeNum,
                    OrderListIds = orderListIds,
                    ShangTitle = shangTitle
                });
            }

            var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
            total += orderListTotal;

            response.Data.Add(new WarehouseGoodsGroupDto
            {
                GoodsId = goodsId ?? 0,
                GoodsTitle = goodsTitle,
                OrderList = orderListDtos,
                OrderListTotal = orderListTotal,
                OrderListLength = orderListDtos.Count
            });
        }

        response.Total = total;
        return response;
    }

    #endregion

    #region Helper Methods

    /// <summary>
    /// 获取商品标题
    /// </summary>
    private async Task<string> GetGoodsTitleAsync(int? goodsId)
    {
        if (goodsId == null) return "其他";
        if (goodsId == 0) return "无限令奖品";
        if (goodsId == -1) return "周榜奖品";
        if (goodsId == -2) return "月榜奖品";

        var title = await _dbContext.Goods
            .Where(g => g.Id == goodsId && g.DeletedAt == null)
            .Select(g => g.Title)
            .FirstOrDefaultAsync();

        return title ?? "其他";
    }

    /// <summary>
    /// 获取赏品等级标题
    /// </summary>
    private async Task<string> GetShangTitleAsync(int shangId)
    {
        if (shangId <= 0) return string.Empty;

        var title = await _dbContext.PrizeLevels
            .Where(p => p.Id == shangId)
            .Select(p => p.Title)
            .FirstOrDefaultAsync();

        return title ?? string.Empty;
    }

    /// <summary>
    /// 检查是否显示达达卷
    /// </summary>
    private async Task<bool> CheckShowDadajuanAsync(int userId, bool hasData)
    {
        if (!hasData) return false;

        var config = await _dbContext.Configs
            .Where(c => c.ConfigKey == "app_setting")
            .Select(c => c.ConfigValue)
            .FirstOrDefaultAsync();

        if (string.IsNullOrEmpty(config)) return true;

        try
        {
            var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
            if (settings != null && settings.TryGetValue("show_dadajuan_limit", out var limitObj))
            {
                var limitStr = limitObj?.ToString();
                if (!string.IsNullOrEmpty(limitStr) && limitStr != "0" && int.TryParse(limitStr, out var limit))
                {
                    var totalConsumption = await _dbContext.Orders
                        .Where(o => o.UserId == userId && o.Status == 1)
                        .SumAsync(o => (decimal?)o.OrderTotal) ?? 0;

                    return totalConsumption >= limit;
                }
            }
        }
        catch
        {
            // 配置解析失败，默认显示
        }

        return true;
    }

    /// <summary>
    /// 获取运费配置
    /// </summary>
    private async Task<ShippingFeeDto> GetShippingFeeConfigAsync(int type)
    {
        var config = await _dbContext.Configs
            .Where(c => c.ConfigKey == "base")
            .Select(c => c.ConfigValue)
            .FirstOrDefaultAsync();

        var result = new ShippingFeeDto();

        if (string.IsNullOrEmpty(config)) return result;

        try
        {
            var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
            if (settings != null)
            {
                if (type == 3) // 卡册
                {
                    result.FreePost = settings.TryGetValue("card_free_post", out var fp) && int.TryParse(fp?.ToString(), out var fpVal) ? fpVal : 0;
                    result.PostMoney = settings.TryGetValue("card_post_money", out var pm) && int.TryParse(pm?.ToString(), out var pmVal) ? pmVal : 0;
                }
                else
                {
                    result.FreePost = settings.TryGetValue("free_post", out var fp) && int.TryParse(fp?.ToString(), out var fpVal) ? fpVal : 0;
                    result.PostMoney = settings.TryGetValue("post_money", out var pm) && int.TryParse(pm?.ToString(), out var pmVal) ? pmVal : 0;
                }
            }
        }
        catch
        {
            // 配置解析失败，返回默认值
        }

        return result;
    }

    /// <summary>
    /// 格式化图片URL
    /// </summary>
    private static string FormatImageUrl(string? imgUrl)
    {
        if (string.IsNullOrEmpty(imgUrl))
            return string.Empty;

        if (imgUrl.StartsWith("http://") || imgUrl.StartsWith("https://"))
            return imgUrl;

        return imgUrl;
    }

    #endregion

    #region 奖品回收

    /// <inheritdoc />
    public async Task<RecoveryResultDto> RecoveryPrizesAsync(int userId, RecoveryRequest request)
    {
        // 1. 验证回收信息
        if (string.IsNullOrEmpty(request.RecoveryInfo))
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 2. 检查达达卷消费限制
        await CheckDadajuanLimitAsync(userId);

        // 3. 检查每日兑换次数限制
        await CheckDailyExchangeLimitAsync(userId);

        // 4. 解析回收信息
        List<RecoveryInfoItem> recoveryItems;
        try
        {
            recoveryItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo) 
                ?? new List<RecoveryInfoItem>();
        }
        catch
        {
            throw new InvalidOperationException("回收信息格式错误");
        }

        if (!recoveryItems.Any())
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 5. 根据prize_code和number获取订单详情ID列表
        var orderListIds = new List<int>();
        foreach (var item in recoveryItems)
        {
            var ids = await _dbContext.OrderItems
                .Where(o => o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 0
                    && o.PrizeCode == item.PrizeCode)
                .OrderBy(o => o.Id)
                .Take(item.Number)
                .Select(o => o.Id)
                .ToListAsync();

            orderListIds.AddRange(ids);
        }

        if (!orderListIds.Any())
        {
            throw new InvalidOperationException("请刷新重新选择奖品");
        }

        // 6. 计算回收总金额
        var totalMoney = await _dbContext.OrderItems
            .Where(o => orderListIds.Contains(o.Id)
                && o.UserId == userId
                && o.Status == 0
                && o.InsuranceIs == 0)
            .SumAsync(o => o.GoodslistMoney);

        // 7. 生成回收单号
        var recoveryNum = GenerateRecoveryNum();

        // 8. 使用事务处理
        using var transaction = await _dbContext.Database.BeginTransactionAsync();
        try
        {
            var currentTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();

            // 8.1 创建回收记录
            var recoveryRecord = new OrderItemsRecovery
            {
                UserId = userId,
                RecoveryNum = recoveryNum,
                Money = totalMoney,
                Count = orderListIds.Count,
                Addtime = currentTime,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };
            _dbContext.OrderItemsRecoveries.Add(recoveryRecord);

            // 8.2 更新订单详情状态
            await _dbContext.OrderItems
                .Where(o => orderListIds.Contains(o.Id)
                    && o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 0)
                .ExecuteUpdateAsync(s => s
                    .SetProperty(o => o.RecoveryNum, recoveryNum)
                    .SetProperty(o => o.Status, (byte)1)
                    .SetProperty(o => o.ChoiceTime, currentTime)
                    .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

            // 8.3 增加用户哈尼券（money2），金额乘以100
            var money2Amount = totalMoney * 100;
            if (money2Amount > 0)
            {
                await ChangeMoney2Async(userId, money2Amount, 4, "兑换获得");
            }

            await _dbContext.SaveChangesAsync();
            await transaction.CommitAsync();

            // 9. 获取用户当前余额
            var userMoney2 = await _dbContext.Users
                .Where(u => u.Id == userId)
                .Select(u => u.Money2 ?? 0)
                .FirstOrDefaultAsync();

            return new RecoveryResultDto
            {
                TotalMoney = (money2Amount).ToString("0.00"),
                Count = orderListIds.Count,
                RecoveryNum = recoveryNum,
                UserMoney = userMoney2.ToString("0.00")
            };
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "奖品回收失败: UserId={UserId}", userId);
            throw new InvalidOperationException("打包失败");
        }
    }

    /// <summary>
    /// 检查达达卷消费限制
    /// </summary>
    private async Task CheckDadajuanLimitAsync(int userId)
    {
        var config = await _dbContext.Configs
            .Where(c => c.ConfigKey == "app_setting")
            .Select(c => c.ConfigValue)
            .FirstOrDefaultAsync();

        if (string.IsNullOrEmpty(config)) return;

        try
        {
            var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
            if (settings != null && settings.TryGetValue("show_dadajuan_limit", out var limitObj))
            {
                var limitStr = limitObj?.ToString();
                if (!string.IsNullOrEmpty(limitStr) && limitStr != "0" && int.TryParse(limitStr, out var limit))
                {
                    var totalConsumption = await _dbContext.Orders
                        .Where(o => o.UserId == userId && o.Status == 1)
                        .SumAsync(o => (decimal?)o.OrderTotal) ?? 0;

                    if (totalConsumption < limit)
                    {
                        throw new InvalidOperationException($"消费满{limit}才能兑换达达卷");
                    }
                }
            }
        }
        catch (InvalidOperationException)
        {
            throw;
        }
        catch
        {
            // 配置解析失败，忽略限制
        }
    }

    /// <summary>
    /// 检查每日兑换次数限制
    /// </summary>
    private async Task CheckDailyExchangeLimitAsync(int userId)
    {
        var config = await _dbContext.Configs
            .Where(c => c.ConfigKey == "app_setting")
            .Select(c => c.ConfigValue)
            .FirstOrDefaultAsync();

        if (string.IsNullOrEmpty(config)) return;

        try
        {
            var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
            if (settings != null && settings.TryGetValue("cabinet_exchange_limit", out var limitObj))
            {
                var limitStr = limitObj?.ToString();
                if (!string.IsNullOrEmpty(limitStr) && int.TryParse(limitStr, out var limit) && limit > 0)
                {
                    var todayStart = new DateTimeOffset(DateTime.UtcNow.Date).ToUnixTimeSeconds();
                    var todayEnd = todayStart + 86400 - 1;

                    var todayCount = await _dbContext.OrderItemsRecoveries
                        .Where(r => r.UserId == userId
                            && r.Addtime >= todayStart
                            && r.Addtime <= todayEnd)
                        .CountAsync();

                    if (todayCount >= limit)
                    {
                        throw new InvalidOperationException("今日兑换次数已达上限");
                    }
                }
            }
        }
        catch (InvalidOperationException)
        {
            throw;
        }
        catch
        {
            // 配置解析失败，忽略限制
        }
    }

    /// <summary>
    /// 生成回收单号
    /// </summary>
    private static string GenerateRecoveryNum()
    {
        return $"HS_{DateTime.UtcNow:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
    }

    /// <summary>
    /// 变更用户哈尼券（money2）
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="changeMoney">变动金额（正数增加，负数减少）</param>
    /// <param name="type">变动类型：1后台充值 2在线充值 3抽赏消费 4背包兑换 5推荐奖励</param>
    /// <param name="content">变动说明</param>
    private async Task ChangeMoney2Async(int userId, decimal changeMoney, byte type, string content)
    {
        if (changeMoney == 0) return;

        var user = await _dbContext.Users.FindAsync(userId);
        if (user == null) return;

        var currentMoney2 = user.Money2 ?? 0;
        var newMoney2 = currentMoney2 + changeMoney;

        // 更新用户余额
        user.Money2 = newMoney2;
        user.UpdatedAt = DateTime.UtcNow;

        // 记录变动明细
        var profitRecord = new ProfitMoney2
        {
            UserId = userId,
            ChangeMoney = changeMoney,
            Money = newMoney2,
            Type = type,
            Content = content,
            ShareUid = 0,
            Other = null,
            CreatedAt = DateTime.UtcNow
        };
        _dbContext.ProfitMoney2s.Add(profitRecord);
    }

    #endregion

    #region 奖品发货

    /// <inheritdoc />
    public async Task<SendResultDto> SendPrizesAsync(int userId, SendRequest request)
    {
        // 1. 验证类型参数
        if (request.Type != 1 && request.Type != 2)
        {
            throw new InvalidOperationException("请求参数错误");
        }

        // 2. 验证发货信息
        if (string.IsNullOrEmpty(request.RecoveryInfo))
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 3. 验证收货信息
        if (string.IsNullOrEmpty(request.Name) || string.IsNullOrEmpty(request.Mobile) || string.IsNullOrEmpty(request.Address))
        {
            throw new InvalidOperationException("缺少收货信息");
        }

        // 4. 解析发货信息
        List<RecoveryInfoItem> sendItems;
        try
        {
            sendItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
                ?? new List<RecoveryInfoItem>();
        }
        catch
        {
            throw new InvalidOperationException("发货信息格式错误");
        }

        if (!sendItems.Any())
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 5. 根据prize_code和number获取订单详情ID列表
        var orderListIds = new List<int>();
        foreach (var item in sendItems)
        {
            var lim = item.Number;
            var ids = await _dbContext.OrderItems
                .Where(o => o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 0
                    && o.GoodslistType == 1
                    && o.PrizeCode == item.PrizeCode.Trim())
                .OrderBy(o => o.Id)
                .Take(lim)
                .Select(o => o.Id)
                .ToListAsync();

            orderListIds.AddRange(ids);
        }

        if (!orderListIds.Any())
        {
            throw new InvalidOperationException("请刷新重新选择奖品");
        }

        // 6. 获取发货数量
        var count = orderListIds.Count;

        // 7. 获取运费配置
        var shippingConfig = await GetShippingFeeConfigAsync(request.Type);
        var freePost = shippingConfig.FreePost <= 0 ? 0 : shippingConfig.FreePost;
        var postMoney = shippingConfig.PostMoney <= 0 ? 0 : shippingConfig.PostMoney;

        // 8. 生成发货单号
        var sendNum = GenerateSendNum();
        var currentTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();

        // 9. 计算实际运费
        var actualFreight = postMoney;
        if (freePost <= count || postMoney == 0)
        {
            actualFreight = 0;
        }

        // 10. 使用事务处理
        using var transaction = await _dbContext.Database.BeginTransactionAsync();
        try
        {
            // 10.1 更新订单详情的发货单号
            await _dbContext.OrderItems
                .Where(o => orderListIds.Contains(o.Id)
                    && o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 0
                    && o.GoodslistType == 1)
                .ExecuteUpdateAsync(s => s
                    .SetProperty(o => o.SendNum, sendNum)
                    .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

            // 10.2 创建发货记录
            var sendRecord = new OrderItemsSend
            {
                UserId = userId,
                SendNum = sendNum,
                Freight = actualFreight,
                Status = 0, // 0=待支付
                Count = count,
                Name = request.Name,
                Mobile = request.Mobile,
                Address = request.Address,
                Message = request.Message,
                Addtime = currentTime,
                PayTime = 0,
                SendTime = 0,
                ShouTime = 0,
                CancelTime = 0,
                DeliveryStatus = -1,  // -1 表示未查询物流
                DeliveryTime = 0,
                AdminId = 0,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };
            _dbContext.OrderItemsSends.Add(sendRecord);
            await _dbContext.SaveChangesAsync();

            var sendRecordId = sendRecord.Id;

            // 10.3 判断是否需要支付运费
            SendResultDto result;
            if (freePost > count && postMoney > 0)
            {
                // 需要支付运费，调用微信支付服务生成支付参数
                // 获取用户信息
                var user = await _dbContext.Users.FindAsync(userId);
                if (user == null)
                {
                    throw new InvalidOperationException("用户不存在");
                }

                // 生成发货订单号
                var orderNo = $"FH_{DateTime.UtcNow:yyyyMMddHHmmssfff}{new Random().Next(1000, 9999)}";

                var payRequest = new WechatPayRequest
                {
                    OrderNo = orderNo,
                    UserId = userId,
                    OpenId = user.OpenId ?? string.Empty,
                    Amount = actualFreight,
                    Body = $"背包发货{count}件",
                    Attach = "order_list_send"
                };

                var payResult = await _wechatPayService.CreatePaymentAsync(payRequest);
                
                if (payResult.Status != 1)
                {
                    throw new InvalidOperationException(payResult.Msg ?? "创建支付订单失败");
                }

                // 更新发货记录的订单号为支付订单号
                sendRecord.SendNum = orderNo;
                await _dbContext.SaveChangesAsync();

                // 同时更新 OrderItems 的 SendNum
                await _dbContext.OrderItems
                    .Where(o => o.SendNum == sendNum && o.UserId == userId)
                    .ExecuteUpdateAsync(s => s
                        .SetProperty(o => o.SendNum, orderNo)
                        .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

                result = new SendResultDto
                {
                    Status = 1, // 需要支付
                    OrderNo = orderNo,
                    Res = payResult.Data != null ? new NativePayResultDto
                    {
                        AppId = payResult.Data.AppId,
                        TimeStamp = payResult.Data.TimeStamp,
                        NonceStr = payResult.Data.NonceStr,
                        Package = payResult.Data.Package,
                        SignType = payResult.Data.SignType,
                        PaySign = payResult.Data.PaySign
                    } : null
                };
            }
            else
            {
                // 免运费，直接处理发货
                sendRecord.Freight = 0;
                sendRecord.Status = 1; // 1=待发货
                sendRecord.PayTime = currentTime;

                // 更新订单详情状态为已发货
                await _dbContext.OrderItems
                    .Where(o => o.SendNum == sendNum && o.UserId == userId)
                    .ExecuteUpdateAsync(s => s
                        .SetProperty(o => o.Status, (byte)2)
                        .SetProperty(o => o.ChoiceTime, currentTime)
                        .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

                await _dbContext.SaveChangesAsync();

                result = new SendResultDto
                {
                    Status = 0, // 免运费
                    OrderNo = sendNum
                };
            }

            await transaction.CommitAsync();
            return result;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "奖品发货失败: UserId={UserId}", userId);
            throw new InvalidOperationException("发货失败");
        }
    }

    /// <inheritdoc />
    public async Task<bool> ConfirmSendAsync(int userId, int id)
    {
        // 1. 验证参数
        if (id <= 0)
        {
            throw new InvalidOperationException("非法请求");
        }

        // 2. 查找发货记录
        var sendRecord = await _dbContext.OrderItemsSends
            .Where(s => s.Id == id && s.UserId == userId)
            .FirstOrDefaultAsync();

        if (sendRecord == null)
        {
            throw new InvalidOperationException("请求参数错误");
        }

        // 3. 检查状态
        if (sendRecord.Status == 3)
        {
            throw new InvalidOperationException("请勿重复操作");
        }

        if (sendRecord.Status != 2)
        {
            throw new InvalidOperationException("该订单暂不能确认收货");
        }

        // 4. 更新状态为已签收
        var currentTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        sendRecord.Status = 3; // 3=已签收
        sendRecord.ShouTime = currentTime;
        sendRecord.UpdatedAt = DateTime.UtcNow;

        var result = await _dbContext.SaveChangesAsync();
        return result > 0;
    }

    /// <summary>
    /// 生成发货单号
    /// </summary>
    private static string GenerateSendNum()
    {
        return $"FH_{DateTime.UtcNow:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
    }

    #endregion

    #region 记录查询

    /// <inheritdoc />
    public async Task<PageResponse<SendRecordDto>> GetSendRecordsAsync(int userId, int page, int status = 1)
    {
        // 验证状态参数
        if (status != 1 && status != 2 && status != 3)
        {
            throw new InvalidOperationException("非法请求");
        }

        var pageSize = 10;
        var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

        // 自动收货：7天后自动签收
        var expireTime = currentTime - (7 * 86400);
        await _dbContext.OrderItemsSends
            .Where(s => s.Status == 2 && s.SendTime <= expireTime && s.SendTime > 0)
            .ExecuteUpdateAsync(s => s
                .SetProperty(o => o.Status, (byte)3)
                .SetProperty(o => o.ShouTime, (int)currentTime)
                .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

        // 查询发货记录
        var query = _dbContext.OrderItemsSends
            .Where(s => s.UserId == userId && s.Status == status)
            .OrderByDescending(s => s.Id);

        var totalCount = await query.CountAsync();
        var lastPage = (int)Math.Ceiling((double)totalCount / pageSize);

        var records = await query
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var result = new List<SendRecordDto>();
        foreach (var record in records)
        {
            // 获取奖品列表
            var orderList = await _dbContext.OrderItems
                .Where(o => o.SendNum == record.SendNum)
                .Select(o => new SendRecordItemDto
                {
                    Id = o.Id,
                    GoodsListTitle = o.GoodslistTitle ?? string.Empty,
                    GoodsListImgUrl = FormatImageUrl(o.GoodslistImgurl),
                    GoodsListMoney = o.GoodslistMoney.ToString("0.00"),
                    ShangId = o.ShangId,
                    PrizeNum = 1,
                    FhStatus = o.FhStatus
                })
                .ToListAsync();

            // 获取赏品等级标题
            foreach (var item in orderList)
            {
                item.ShangTitle = await GetShangTitleAsync(item.ShangId);
            }

            result.Add(new SendRecordDto
            {
                Id = record.Id,
                SendNum = record.SendNum ?? string.Empty,
                Name = record.Name ?? string.Empty,
                Mobile = MaskMobile(record.Mobile),
                Address = record.Address ?? string.Empty,
                Status = record.Status,
                StatusName = GetSendStatusName(record.Status),
                Count = record.Count,
                Freight = record.Freight.ToString("0.00"),
                AddTime = FormatTimestamp(record.Addtime),
                CourierNumber = record.CourierNumber,
                CourierName = record.CourierName,
                UserId = record.UserId,
                OrderList = orderList
            });
        }

        return new PageResponse<SendRecordDto>
        {
            Data = result,
            LastPage = lastPage > 0 ? lastPage : 1
        };
    }

    /// <inheritdoc />
    public async Task<SendRecordDetailDto> GetSendRecordDetailAsync(int userId, int id)
    {
        // 验证参数
        if (id <= 0)
        {
            throw new InvalidOperationException("非法请求");
        }

        // 查询发货记录
        var record = await _dbContext.OrderItemsSends
            .Where(s => s.Id == id && s.UserId == userId)
            .FirstOrDefaultAsync();

        if (record == null)
        {
            throw new InvalidOperationException("请求参数错误");
        }

        // 验证状态
        if (record.Status != 1 && record.Status != 2 && record.Status != 3)
        {
            throw new InvalidOperationException("请求参数错误");
        }

        // 获取奖品列表
        var goods = await _dbContext.OrderItems
            .Where(o => o.SendNum == record.SendNum)
            .OrderByDescending(o => o.GoodslistMoney)
            .Select(o => new SendRecordItemDto
            {
                Id = o.Id,
                GoodsListTitle = o.GoodslistTitle ?? string.Empty,
                GoodsListImgUrl = FormatImageUrl(o.GoodslistImgurl),
                GoodsListMoney = o.GoodslistMoney.ToString("0.00"),
                ShangId = o.ShangId,
                PrizeNum = 1,
                FhStatus = o.FhStatus
            })
            .ToListAsync();

        // 获取赏品等级标题
        foreach (var item in goods)
        {
            item.ShangTitle = await GetShangTitleAsync(item.ShangId);
        }

        return new SendRecordDetailDto
        {
            Id = record.Id,
            SendNum = record.SendNum ?? string.Empty,
            Name = record.Name ?? string.Empty,
            Mobile = record.Mobile ?? string.Empty,
            Address = record.Address ?? string.Empty,
            Message = record.Message,
            Status = record.Status,
            Count = record.Count,
            Freight = record.Freight.ToString("0.00"),
            AddTime = FormatTimestamp(record.Addtime),
            PayTime = FormatTimestamp(record.PayTime),
            SendTime = record.SendTime > 0 ? FormatTimestamp(record.SendTime) : "待发货",
            ShouTime = record.ShouTime > 0 ? FormatTimestamp(record.ShouTime) : "待收货",
            CourierNumber = record.CourierNumber,
            CourierName = record.CourierName,
            Goods = goods
        };
    }

    /// <inheritdoc />
    public async Task<PageResponse<RecoveryRecordDto>> GetRecoveryRecordsAsync(int userId, int page)
    {
        var pageSize = 10;

        var query = _dbContext.OrderItemsRecoveries
            .Where(r => r.UserId == userId)
            .OrderByDescending(r => r.Id);

        var totalCount = await query.CountAsync();
        var lastPage = (int)Math.Ceiling((double)totalCount / pageSize);

        var records = await query
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        var result = new List<RecoveryRecordDto>();
        foreach (var record in records)
        {
            // 获取奖品列表
            var orderList = await _dbContext.OrderItems
                .Where(o => o.RecoveryNum == record.RecoveryNum)
                .Select(o => new RecoveryRecordItemDto
                {
                    Id = o.Id,
                    GoodsListTitle = o.GoodslistTitle ?? string.Empty,
                    GoodsListImgUrl = FormatImageUrl(o.GoodslistImgurl),
                    GoodsListMoney = o.GoodslistMoney.ToString("0.00")
                })
                .ToListAsync();

            result.Add(new RecoveryRecordDto
            {
                Id = record.Id,
                RecoveryNum = record.RecoveryNum ?? string.Empty,
                Money = record.Money.ToString("0.00"),
                Count = record.Count,
                AddTime = FormatTimestamp(record.Addtime),
                OrderList = orderList
            });
        }

        return new PageResponse<RecoveryRecordDto>
        {
            Data = result,
            LastPage = lastPage > 0 ? lastPage : 1
        };
    }

    /// <summary>
    /// 获取发货状态名称
    /// </summary>
    private static string GetSendStatusName(int status)
    {
        return status switch
        {
            0 => "待支付",
            1 => "待发货",
            2 => "已发货",
            3 => "已签收",
            4 => "已取消",
            _ => "未知"
        };
    }

    /// <summary>
    /// 手机号脱敏
    /// </summary>
    private static string MaskMobile(string? mobile)
    {
        if (string.IsNullOrEmpty(mobile) || mobile.Length < 7)
            return mobile ?? string.Empty;

        return mobile.Substring(0, 3) + "****" + mobile.Substring(mobile.Length - 4);
    }

    /// <summary>
    /// 格式化时间戳为日期时间字符串
    /// </summary>
    private static string FormatTimestamp(int timestamp)
    {
        if (timestamp <= 0) return string.Empty;
        return DateTimeOffset.FromUnixTimeSeconds(timestamp).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
    }

    #endregion

    #region 物流查询

    /// <summary>
    /// 物流状态名称映射
    /// </summary>
    private static readonly string[] DeliveryStatusNames = 
    {
        "快递收件(揽件)", // 0
        "在途中",         // 1
        "正在派件",       // 2
        "已签收",         // 3
        "派送失败",       // 4
        "疑难件",         // 5
        "退件签收",       // 6
        "其他"            // 7
    };

    /// <inheritdoc />
    public async Task<LogisticsDto> GetLogisticsAsync(int userId, int id)
    {
        // 1. 验证参数
        if (id <= 0)
        {
            throw new InvalidOperationException("非法请求");
        }

        // 2. 查询发货记录
        var sendRecord = await _dbContext.OrderItemsSends
            .Where(s => s.Id == id && s.UserId == userId)
            .Select(s => new
            {
                s.Id,
                s.SendNum,
                s.CourierNumber,
                s.CourierName,
                s.CourierCode,
                s.DeliveryList,
                s.DeliveryStatus,
                s.DeliveryTime,
                s.Count,
                s.Mobile
            })
            .FirstOrDefaultAsync();

        if (sendRecord == null)
        {
            throw new InvalidOperationException("请求参数错误");
        }

        // 3. 获取奖品图片
        var goodsListImgUrl = await _dbContext.OrderItems
            .Where(o => o.SendNum == sendRecord.SendNum)
            .Select(o => o.GoodslistImgurl)
            .FirstOrDefaultAsync();

        // 4. 初始化响应
        var result = new LogisticsDto
        {
            CourierNumber = sendRecord.CourierNumber,
            CourierName = sendRecord.CourierName,
            CourierCode = sendRecord.CourierCode,
            Count = sendRecord.Count,
            SendNum = sendRecord.SendNum,
            GoodsListImgUrl = FormatImageUrl(goodsListImgUrl),
            DeliveryStatus = GetDeliveryStatusName(sendRecord.DeliveryStatus),
            DeliveryList = ParseDeliveryList(sendRecord.DeliveryList)
        };

        // 5. 检查是否需要刷新物流信息（每10分钟刷新一次）
        var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        var shouldRefresh = !string.IsNullOrEmpty(sendRecord.CourierNumber) 
            && (currentTime > sendRecord.DeliveryTime + 600);

        if (shouldRefresh)
        {
            // 6. 处理顺丰快递特殊逻辑（需要手机号后4位）
            var trackingNo = sendRecord.CourierNumber!;
            if (sendRecord.CourierCode?.ToUpper() == "SFEXPRESS" && !string.IsNullOrEmpty(sendRecord.Mobile))
            {
                var mobileSuffix = sendRecord.Mobile.Length >= 4 
                    ? sendRecord.Mobile.Substring(sendRecord.Mobile.Length - 4) 
                    : sendRecord.Mobile;
                trackingNo = $"{trackingNo}:{mobileSuffix}";
            }

            // 7. 调用物流查询API
            var queryResult = await _logisticsService.QueryLogisticsAsync(
                trackingNo, 
                sendRecord.CourierCode ?? string.Empty);

            if (queryResult.Success)
            {
                // 8. 更新物流信息到数据库
                var deliveryListJson = queryResult.TraceList != null 
                    ? System.Text.Json.JsonSerializer.Serialize(queryResult.TraceList) 
                    : null;

                await _dbContext.OrderItemsSends
                    .Where(s => s.Id == id)
                    .ExecuteUpdateAsync(s => s
                        .SetProperty(o => o.DeliveryList, deliveryListJson)
                        .SetProperty(o => o.DeliveryStatus, (byte)queryResult.DeliveryStatus)
                        .SetProperty(o => o.DeliveryTime, (int)currentTime)
                        .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

                // 9. 更新响应
                result.DeliveryStatus = GetDeliveryStatusName(queryResult.DeliveryStatus);
                result.DeliveryList = queryResult.TraceList;
            }
        }

        return result;
    }

    /// <summary>
    /// 获取物流状态名称
    /// </summary>
    private static string GetDeliveryStatusName(int status)
    {
        if (status >= 0 && status < DeliveryStatusNames.Length)
        {
            return DeliveryStatusNames[status];
        }
        return "暂无物流轨迹";
    }

    /// <summary>
    /// 解析物流轨迹JSON
    /// </summary>
    private static List<LogisticsTraceDto>? ParseDeliveryList(string? deliveryListJson)
    {
        if (string.IsNullOrEmpty(deliveryListJson))
        {
            return null;
        }

        try
        {
            return System.Text.Json.JsonSerializer.Deserialize<List<LogisticsTraceDto>>(deliveryListJson);
        }
        catch
        {
            return null;
        }
    }

    #endregion

    #region 保险柜操作

    /// <inheritdoc />
    public async Task<bool> MoveIntoSafeAsync(int userId, SafeOperationRequest request)
    {
        // 1. 验证操作信息
        if (string.IsNullOrEmpty(request.RecoveryInfo))
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 2. 解析操作信息
        List<RecoveryInfoItem> operationItems;
        try
        {
            operationItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
                ?? new List<RecoveryInfoItem>();
        }
        catch
        {
            throw new InvalidOperationException("操作信息格式错误");
        }

        if (!operationItems.Any())
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 3. 根据prize_code和number获取订单详情ID列表
        var orderListIds = new List<int>();
        foreach (var item in operationItems)
        {
            var ids = await _dbContext.OrderItems
                .Where(o => o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 0
                    && o.PrizeCode == item.PrizeCode)
                .OrderBy(o => o.Id)
                .Take(item.Number)
                .Select(o => o.Id)
                .ToListAsync();

            orderListIds.AddRange(ids);
        }

        if (!orderListIds.Any())
        {
            throw new InvalidOperationException("请刷新重新选择奖品");
        }

        // 4. 更新订单详情的保险柜状态
        var result = await _dbContext.OrderItems
            .Where(o => orderListIds.Contains(o.Id)
                && o.UserId == userId
                && o.Status == 0
                && o.InsuranceIs == 0)
            .ExecuteUpdateAsync(s => s
                .SetProperty(o => o.InsuranceIs, (byte)1)
                .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

        return result > 0;
    }

    /// <inheritdoc />
    public async Task<bool> RemoveFromSafeAsync(int userId, SafeOperationRequest request)
    {
        // 1. 验证操作信息
        if (string.IsNullOrEmpty(request.RecoveryInfo))
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 2. 解析操作信息
        List<RecoveryInfoItem> operationItems;
        try
        {
            operationItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
                ?? new List<RecoveryInfoItem>();
        }
        catch
        {
            throw new InvalidOperationException("操作信息格式错误");
        }

        if (!operationItems.Any())
        {
            throw new InvalidOperationException("请选择兑换的赏品");
        }

        // 3. 根据prize_code和number获取订单详情ID列表（从保险柜中）
        var orderListIds = new List<int>();
        foreach (var item in operationItems)
        {
            var ids = await _dbContext.OrderItems
                .Where(o => o.UserId == userId
                    && o.Status == 0
                    && o.InsuranceIs == 1
                    && o.PrizeCode == item.PrizeCode)
                .OrderBy(o => o.Id)
                .Take(item.Number)
                .Select(o => o.Id)
                .ToListAsync();

            orderListIds.AddRange(ids);
        }

        if (!orderListIds.Any())
        {
            throw new InvalidOperationException("请刷新重新选择奖品");
        }

        // 4. 更新订单详情的保险柜状态
        var result = await _dbContext.OrderItems
            .Where(o => orderListIds.Contains(o.Id)
                && o.UserId == userId
                && o.Status == 0
                && o.InsuranceIs == 1)
            .ExecuteUpdateAsync(s => s
                .SetProperty(o => o.InsuranceIs, (byte)0)
                .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));

        return result > 0;
    }

    #endregion
}
