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

namespace HoneyBox.Core.Services;

/// <summary>
/// 抽奖服务实现
/// </summary>
public class LotteryService : ILotteryService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILotteryEngine _lotteryEngine;
    private readonly ILogger<LotteryService> _logger;

    public LotteryService(
        HoneyBoxDbContext dbContext, 
        ILotteryEngine lotteryEngine,
        ILogger<LotteryService> logger)
    {
        _dbContext = dbContext;
        _lotteryEngine = lotteryEngine;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<PrizeOrderLogResponseDto> GetPrizeOrderLogAsync(int userId, string orderNum)
    {
        var response = new PrizeOrderLogResponseDto();

        try
        {
            // 查询订单
            var order = await _dbContext.Orders
                .FirstOrDefaultAsync(o => o.OrderNum == orderNum && o.UserId == userId);

            if (order == null)
            {
                _logger.LogWarning("Order not found: {OrderNum} for user {UserId}", orderNum, userId);
                return response;
            }

            // 查询订单奖品
            var orderItems = await _dbContext.OrderItems
                .Where(oi => oi.OrderId == order.Id && oi.Source == PrizeSource.Lottery)
                .OrderByDescending(oi => oi.Addtime)
                .ToListAsync();

            // 获取赏品等级信息
            var shangIds = orderItems.Select(oi => oi.ShangId).Distinct().ToList();
            var prizeLevels = await _dbContext.PrizeLevels
                .Where(pl => shangIds.Contains(pl.Id))
                .ToDictionaryAsync(pl => pl.Id);

            // 转换为DTO
            response.Data = orderItems.Select(oi => MapToPrizeOrderLogDto(oi, prizeLevels)).ToList();
            response.PrizeNum = orderItems.Count;

            // 查询重抽卡数量（如果有相关表）
            response.ItemCardCount = 0; // TODO: 实现道具卡数量查询

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting prize order log for order {OrderNum}", orderNum);
        }

        return response;
    }

    /// <inheritdoc />
    public async Task<InfinitePrizeOrderLogResponseDto> GetInfinitePrizeOrderLogAsync(int userId, string orderNum)
    {
        var response = new InfinitePrizeOrderLogResponseDto();

        try
        {
            // 查询订单
            var order = await _dbContext.Orders
                .FirstOrDefaultAsync(o => o.OrderNum == orderNum && o.UserId == userId);

            if (order == null)
            {
                _logger.LogWarning("Infinite order not found: {OrderNum} for user {UserId}", orderNum, userId);
                return response;
            }

            // 查询用户信息
            var user = await _dbContext.Users.FindAsync(userId);
            if (user != null)
            {
                response.UserInfo = new UserBasicInfoDto
                {
                    Nickname = user.Nickname ?? string.Empty,
                    HeadImg = user.HeadImg ?? string.Empty
                };
            }

            // 查询订单奖品（无限赏类型）
            var orderItems = await _dbContext.OrderItems
                .Where(oi => oi.OrderId == order.Id && 
                             oi.OrderType == LotteryOrderType.WuXianShang &&
                             oi.Source == PrizeSource.Lottery)
                .OrderByDescending(oi => oi.Addtime)
                .ToListAsync();

            // 获取赏品等级信息
            var shangIds = orderItems.Select(oi => oi.ShangId).Distinct().ToList();
            var prizeLevels = await _dbContext.PrizeLevels
                .Where(pl => shangIds.Contains(pl.Id))
                .ToDictionaryAsync(pl => pl.Id);

            // 转换为DTO
            response.Data = orderItems.Select(oi => MapToPrizeOrderLogDto(oi, prizeLevels)).ToList();
            response.PrizeNum = orderItems.Count;
            response.ItemCardCount = 0; // TODO: 实现道具卡数量查询

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting infinite prize order log for order {OrderNum}", orderNum);
        }

        return response;
    }

    /// <inheritdoc />
    public async Task<InfiniteShangLogResponseDto> GetInfiniteShangLogAsync(int goodsId, int shangId, int isMibao, int page, int pageSize)
    {
        var response = new InfiniteShangLogResponseDto();

        try
        {
            // 1. 验证商品是否存在
            var goods = await _dbContext.Goods
                .Where(g => g.Id == goodsId && g.DeletedAt == null)
                .Select(g => new { g.Id, g.Status, g.Type })
                .FirstOrDefaultAsync();

            if (goods == null)
            {
                _logger.LogWarning("Goods not found: {GoodsId}", goodsId);
                return response;
            }

            if (goods.Status != 1)
            {
                _logger.LogWarning("Goods is not active: {GoodsId}", goodsId);
                return response;
            }

            // 2. 获取赏品分类列表
            var categoryQuery = _dbContext.GoodsItems
                .Where(gi => gi.GoodsId == goodsId && gi.Num == 0);

            // 如果是秘宝池，过滤连击类型
            if (isMibao == 1)
            {
                categoryQuery = categoryQuery.Where(gi => gi.LianJiType == 1);
            }

            var categoryShangIds = await categoryQuery
                .Where(gi => gi.ShangId.HasValue)
                .Select(gi => gi.ShangId!.Value)
                .Distinct()
                .ToListAsync();

            // 获取赏品等级信息
            var allPrizeLevels = await _dbContext.PrizeLevels
                .Where(pl => categoryShangIds.Contains(pl.Id))
                .OrderBy(pl => pl.Sort)
                .ThenBy(pl => pl.Id)
                .ToListAsync();

            // 构建分类列表，添加"全部"选项
            response.Category = new List<ShangCategoryDto>
            {
                new ShangCategoryDto { ShangId = 0, ShangTitle = "全部" }
            };
            response.Category.AddRange(allPrizeLevels.Select(pl => new ShangCategoryDto
            {
                ShangId = pl.Id,
                ShangTitle = pl.Title ?? string.Empty
            }));

            // 3. 查询中奖记录
            var query = _dbContext.OrderItems
                .Where(oi => oi.GoodsId == goodsId && 
                             oi.Num == 0 &&
                             oi.OrderType == goods.Type &&
                             oi.Source == PrizeSource.Lottery);

            // 如果指定了赏品等级，添加过滤条件
            if (shangId > 0)
            {
                query = query.Where(oi => oi.ShangId == shangId);
            }

            // 获取总数
            var total = await query.CountAsync();
            response.Total = total;
            response.LastPage = pageSize > 0 ? (int)Math.Ceiling((double)total / pageSize) : 1;

            // 分页查询
            var orderItems = await query
                .OrderByDescending(oi => oi.Id)
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .ToListAsync();

            // 获取用户信息
            var userIds = orderItems.Select(oi => oi.UserId).Distinct().ToList();
            var users = await _dbContext.Users
                .Where(u => userIds.Contains(u.Id))
                .ToDictionaryAsync(u => u.Id);

            // 获取赏品等级信息（用于记录显示）
            var recordShangIds = orderItems.Select(oi => oi.ShangId).Distinct().ToList();
            var prizeLevels = await _dbContext.PrizeLevels
                .Where(pl => recordShangIds.Contains(pl.Id))
                .ToDictionaryAsync(pl => pl.Id);

            // 转换为DTO
            response.Data = orderItems.Select(oi => MapToInfiniteShangLogItemDto(oi, users, prizeLevels)).ToList();

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting infinite shang log for goods {GoodsId}", goodsId);
        }

        return response;
    }

    /// <inheritdoc />
    public async Task<InfinitePrizeRecordsResponseDto> GetInfinitePrizeRecordsAsync(int userId, int goodsId, int page, int pageSize)
    {
        var response = new InfinitePrizeRecordsResponseDto
        {
            CurrentPage = page,
            PerPage = pageSize
        };

        try
        {
            // 查询用户的抽奖记录
            // PHP逻辑: goods_id, num=0, user_id, source=1
            var query = _dbContext.OrderItems
                .Where(oi => oi.GoodsId == goodsId && 
                             oi.Num == 0 &&
                             oi.UserId == userId &&
                             oi.Source == PrizeSource.Lottery);

            // 获取总数
            var total = await query.CountAsync();
            response.Total = total;
            response.LastPage = pageSize > 0 ? (int)Math.Ceiling((double)total / pageSize) : 1;

            // 分页查询，按id倒序
            var orderItems = await query
                .OrderByDescending(oi => oi.Id)
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .Select(oi => new InfinitePrizeRecordItemDto
                {
                    UserId = oi.UserId,
                    GoodslistTitle = oi.GoodslistTitle ?? string.Empty,
                    GoodslistImgurl = oi.GoodslistImgurl ?? string.Empty,
                    Addtime = DateTimeOffset.FromUnixTimeSeconds(oi.Addtime)
                        .ToLocalTime()
                        .ToString("yyyy-MM-dd HH:mm:ss")
                })
                .ToListAsync();

            response.Data = orderItems;

        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting infinite prize records for user {UserId}, goods {GoodsId}", userId, goodsId);
        }

        return response;
    }

    /// <inheritdoc />
    public async Task<ItemCardDrawResponseDto> DrawWithItemCardAsync(int userId, int goodsId, List<int> orderListIds)
    {
        var response = new ItemCardDrawResponseDto();

        try
        {
            // 1. 验证商品是否存在且有效
            var goods = await _dbContext.Goods
                .Where(g => g.Id == goodsId && g.DeletedAt == null)
                .Select(g => new { g.Id, g.Title, g.ImgUrlDetail, g.Type, g.Price, g.Status, g.ChoujiangXianzhi })
                .FirstOrDefaultAsync();

            if (goods == null)
            {
                throw new InvalidOperationException("盒子不存在");
            }

            if (goods.Status != 1)
            {
                throw new InvalidOperationException("盒子已下架");
            }

            // 2. 验证消费门槛（如果配置了）
            if (goods.ChoujiangXianzhi > 0)
            {
                var userTotalSpent = await _dbContext.Orders
                    .Where(o => o.UserId == userId && o.Status == 1)
                    .SumAsync(o => o.Price);

                if (userTotalSpent < goods.ChoujiangXianzhi)
                {
                    throw new InvalidOperationException($"消费满{goods.ChoujiangXianzhi}元可参与 已消费{userTotalSpent:F2}元");
                }
            }

            // 3. 验证用户道具卡数量
            var itemCardCount = await _dbContext.UserItemCards
                .Where(c => c.UserId == userId && c.Status == 1 && c.Deltime == null)
                .CountAsync();

            if (itemCardCount < 1)
            {
                throw new InvalidOperationException("重抽卡数量不足");
            }

            // 4. 验证要重抽的订单项
            if (orderListIds == null || !orderListIds.Any())
            {
                throw new InvalidOperationException("参数错误");
            }

            foreach (var orderListId in orderListIds)
            {
                var orderItem = await _dbContext.OrderItems
                    .Where(oi => oi.Id == orderListId && oi.Status == 0)
                    .FirstOrDefaultAsync();

                if (orderItem == null)
                {
                    throw new InvalidOperationException("数据错误");
                }
            }

            // 5. 开始事务
            using var transaction = await _dbContext.Database.BeginTransactionAsync();

            try
            {
                // 6. 生成订单号
                var orderNum = GenerateOrderNum("MH_");

                // 7. 创建订单
                var order = new Order
                {
                    UserId = userId,
                    OrderNum = orderNum,
                    OrderTotal = 0,
                    OrderZheTotal = 0,
                    Price = 0,
                    UseMoney = 0,
                    UseIntegral = 0,
                    UseScore = 0,
                    Zhe = 0,
                    GoodsId = goodsId,
                    Num = 0,
                    GoodsPrice = goods.Price,
                    GoodsTitle = goods.Title,
                    GoodsImgurl = goods.ImgUrlDetail,
                    PrizeNum = orderListIds.Count,
                    Status = 0,
                    PayType = 1,
                    OrderType = (byte)goods.Type,
                    Addtime = (int)DateTimeOffset.Now.ToUnixTimeSeconds(),
                    UseItemCard = 1,
                    CreatedAt = DateTime.Now,
                    UpdatedAt = DateTime.Now
                };

                _dbContext.Orders.Add(order);
                await _dbContext.SaveChangesAsync();

                // 8. 更新订单状态为已支付
                order.Status = 1;
                order.PayTime = (int)DateTimeOffset.Now.ToUnixTimeSeconds();
                await _dbContext.SaveChangesAsync();

                // 9. 扣除道具卡
                var itemCard = await _dbContext.UserItemCards
                    .Where(c => c.UserId == userId && c.Status == 1 && c.Deltime == null)
                    .OrderBy(c => c.Id)
                    .FirstOrDefaultAsync();

                if (itemCard != null)
                {
                    itemCard.Status = 2;
                    itemCard.OrderId = order.Id;
                    itemCard.Updatetime = (int)DateTimeOffset.Now.ToUnixTimeSeconds();
                    await _dbContext.SaveChangesAsync();
                }

                // 10. 执行抽奖
                var drawRequest = new LotteryDrawRequest
                {
                    UserId = userId,
                    GoodsId = goodsId,
                    Num = 0,
                    OrderId = order.Id,
                    OrderNum = orderNum,
                    OrderType = goods.Type,
                    Source = PrizeSource.Lottery
                };

                var drawResults = await _lotteryEngine.DrawMultipleAsync(drawRequest, orderListIds.Count);

                // 11. 标记原订单项为已重抽
                var currentTime = (int)DateTimeOffset.Now.ToUnixTimeSeconds();
                await _dbContext.OrderItems
                    .Where(oi => orderListIds.Contains(oi.Id) && oi.UserId == userId)
                    .ExecuteUpdateAsync(setters => setters
                        .SetProperty(oi => oi.IsChong, (byte)1)
                        .SetProperty(oi => oi.Deltime, currentTime));

                await transaction.CommitAsync();

                // 12. 构建响应
                response.Status = 0;
                response.OrderNum = orderNum;
                response.Prizes = drawResults
                    .Where(r => r.Success)
                    .Select(r => new ItemCardDrawPrizeDto
                    {
                        Id = r.OrderItemId,
                        Title = r.Title,
                        ImgUrl = r.ImgUrl,
                        ShangId = r.ShangId,
                        ShangTitle = r.ShangTitle,
                        ShangColor = r.ShangColor,
                        Price = r.Price.ToString("F2"),
                        ScMoney = r.ScMoney.ToString("F2"),
                        PrizeCode = r.PrizeCode,
                        LuckNo = r.LuckNo
                    })
                    .ToList();

                // 13. 获取剩余道具卡数量
                response.RemainingCards = await _dbContext.UserItemCards
                    .Where(c => c.UserId == userId && c.Status == 1 && c.Deltime == null)
                    .CountAsync();

                _logger.LogInformation("Item card draw successful: UserId={UserId}, GoodsId={GoodsId}, OrderNum={OrderNum}, PrizeCount={PrizeCount}",
                    userId, goodsId, orderNum, response.Prizes.Count);
            }
            catch (Exception)
            {
                await transaction.RollbackAsync();
                throw;
            }
        }
        catch (InvalidOperationException)
        {
            throw;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Item card draw failed: UserId={UserId}, GoodsId={GoodsId}", userId, goodsId);
            throw new InvalidOperationException("重抽失败,请刷新重试");
        }

        return response;
    }

    #region Private Helper Methods

    /// <summary>
    /// 生成订单号
    /// </summary>
    private string GenerateOrderNum(string prefix)
    {
        return $"{prefix}{DateTime.Now:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
    }

    /// <summary>
    /// 映射OrderItem到PrizeOrderLogDto
    /// </summary>
    private PrizeOrderLogDto MapToPrizeOrderLogDto(OrderItem orderItem, Dictionary<int, PrizeLevel> prizeLevels)
    {
        prizeLevels.TryGetValue(orderItem.ShangId, out var prizeLevel);

        return new PrizeOrderLogDto
        {
            Id = orderItem.Id,
            UserId = orderItem.UserId,
            GoodsListTitle = orderItem.GoodslistTitle ?? string.Empty,
            GoodsListImgUrl = orderItem.GoodslistImgurl ?? string.Empty,
            GoodsListPrice = orderItem.GoodslistPrice.ToString("F2"),
            GoodsListMoney = orderItem.GoodslistMoney.ToString("F2"),
            Status = orderItem.Status,
            LuckNo = orderItem.LuckNo,
            ShangId = orderItem.ShangId,
            ShangTitle = prizeLevel?.Title,
            ShangInfo = prizeLevel != null ? new ShangInfoDto
            {
                Id = prizeLevel.Id,
                Title = prizeLevel.Title ?? string.Empty,
                ImgUrl = prizeLevel.ImgUrl,
                Color = prizeLevel.Color
            } : null,
            Doubling = orderItem.Doubling,
            IsLingzhu = orderItem.IsLingzhu,
            GoodsListType = orderItem.GoodslistType,
            GoodsListId = orderItem.GoodslistId,
            ParentGoodsListId = orderItem.ParentGoodsListId,
            AddTime = orderItem.Addtime
        };
    }

    /// <summary>
    /// 映射OrderItem到InfiniteShangLogItemDto
    /// </summary>
    private InfiniteShangLogItemDto MapToInfiniteShangLogItemDto(
        OrderItem orderItem, 
        Dictionary<int, User> users, 
        Dictionary<int, PrizeLevel> prizeLevels)
    {
        users.TryGetValue(orderItem.UserId, out var user);
        prizeLevels.TryGetValue(orderItem.ShangId, out var prizeLevel);

        // 将Unix时间戳转换为日期时间字符串
        var addtimeStr = DateTimeOffset.FromUnixTimeSeconds(orderItem.Addtime)
            .ToLocalTime()
            .ToString("yyyy-MM-dd HH:mm:ss");

        return new InfiniteShangLogItemDto
        {
            Id = orderItem.Id,
            UserId = orderItem.UserId,
            GoodslistTitle = orderItem.GoodslistTitle ?? string.Empty,
            GoodslistImgurl = orderItem.GoodslistImgurl ?? string.Empty,
            GoodslistPrice = orderItem.GoodslistPrice.ToString("F2"),
            GoodslistMoney = orderItem.GoodslistMoney.ToString("F2"),
            ShangId = orderItem.ShangId,
            ShangTitle = prizeLevel?.Title,
            ShangColor = prizeLevel?.Color,
            Addtime = addtimeStr,
            LuckNo = orderItem.LuckNo,
            Doubling = orderItem.Doubling,
            IsLingzhu = orderItem.IsLingzhu,
            UserInfo = user != null ? new LotteryUserInfoDto
            {
                Nickname = MaskNickname(user.Nickname ?? string.Empty),
                HeadImg = user.HeadImg ?? string.Empty
            } : null,
            ShangInfo = prizeLevel != null ? new ShangInfoDto
            {
                Id = prizeLevel.Id,
                Title = prizeLevel.Title ?? string.Empty,
                ImgUrl = prizeLevel.ImgUrl,
                Color = prizeLevel.Color
            } : null
        };
    }

    /// <summary>
    /// 用户昵称脱敏处理
    /// </summary>
    private string MaskNickname(string nickname)
    {
        if (string.IsNullOrEmpty(nickname))
            return "***";

        if (nickname.Length <= 2)
            return nickname[0] + "***";

        return nickname[0] + "***" + nickname[^1];
    }

    #endregion
}
