using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Models.Rank;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace HoneyBox.Core.Services;

/// <summary>
/// 排行榜服务实现
/// </summary>
public class RankService : IRankService
{
    private readonly HoneyBoxDbContext _dbContext;
    private readonly ILogger<RankService> _logger;

    /// <summary>
    /// 有效的排行榜类型
    /// </summary>
    private static readonly HashSet<string> ValidRankTypes = new(StringComparer.OrdinalIgnoreCase)
    {
        "diamond", "integral", "dadajuan", "invite", "loss"
    };

    public RankService(HoneyBoxDbContext dbContext, ILogger<RankService> logger)
    {
        _dbContext = dbContext;
        _logger = logger;
    }

    /// <inheritdoc />
    public async Task<RankResponse> GetWeekRankAsync(int userId)
    {
        // 获取当前用户信息
        var user = await _dbContext.Users
            .Where(u => u.Id == userId)
            .Select(u => new { u.Nickname, u.HeadImg })
            .FirstOrDefaultAsync();

        if (user == null)
        {
            throw new InvalidOperationException("用户不存在");
        }

        // 计算本周时间范围（周一到周日）
        var (weekStart, weekEnd) = GetWeekRange(DateTime.Now);
        var weekStartTimestamp = ToUnixTimestamp(weekStart);
        var weekEndTimestamp = ToUnixTimestamp(weekEnd);

        // 查询当前用户本周消费总额
        var myOrderTotal = await _dbContext.Orders
            .Where(o => o.UserId == userId
                && o.Addtime >= weekStartTimestamp
                && o.Addtime <= weekEndTimestamp
                && o.Status == 1
                && o.OrderType < 5)
            .SumAsync(o => (decimal?)o.OrderTotal) ?? 0;

        // 查询排行榜前30名
        var rankData = await _dbContext.Orders
            .Where(o => o.Addtime >= weekStartTimestamp
                && o.Addtime <= weekEndTimestamp
                && o.Status == 1
                && o.OrderType < 5)
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                OrderTotal = g.Sum(o => o.OrderTotal)
            })
            .OrderByDescending(x => x.OrderTotal)
            .ThenBy(x => x.UserId)
            .Take(30)
            .ToListAsync();

        // 获取用户信息
        var userIds = rankData.Select(r => r.UserId).ToList();
        var users = await _dbContext.Users
            .Where(u => userIds.Contains(u.Id))
            .Select(u => new { u.Id, u.Nickname, u.HeadImg })
            .ToDictionaryAsync(u => u.Id);

        // 获取周榜奖品信息 (goods_id = -1 表示周榜奖品)
        var prizes = await _dbContext.GoodsItems
            .Where(g => g.GoodsId == -1 && g.Rank >= 1 && g.Rank <= 30)
            .Select(g => new { g.Rank, g.Title, g.ImgUrl })
            .ToDictionaryAsync(g => g.Rank);

        // 构建排行榜数据
        var data = new List<RankItemDto>();
        object myRank = "暂未上榜";
        object myPrizeTitle = 0;
        object myPrizeImgurl = 0;

        for (int i = 0; i < rankData.Count; i++)
        {
            var item = rankData[i];
            var rank = i + 1;
            var userInfo = users.GetValueOrDefault(item.UserId);
            var prizeInfo = prizes.GetValueOrDefault(rank);

            var rankItem = new RankItemDto
            {
                Rank = rank,
                UserId = item.UserId,
                Nickname = userInfo?.Nickname ?? "",
                Headimg = userInfo?.HeadImg ?? "",
                OrderTotal = item.OrderTotal,
                PrizeTitle = prizeInfo?.Title ?? "",
                PrizeImgurl = prizeInfo?.ImgUrl ?? ""
            };

            data.Add(rankItem);

            // 判断当前用户是否在排名中
            if (item.UserId == userId)
            {
                myRank = rank;
                myPrizeTitle = prizeInfo?.Title ?? "";
                myPrizeImgurl = prizeInfo?.ImgUrl ?? "";
            }
        }

        return new RankResponse
        {
            Date = $"{weekStart:MM月dd日}-{weekEnd:MM月dd日}",
            EndDate = weekEndTimestamp,
            MyRank = new MyRankDto
            {
                MyRank = myRank,
                MyPrizeTitle = myPrizeTitle,
                MyPrizeImgurl = myPrizeImgurl,
                MyOrderTotal = myOrderTotal,
                MyNickname = user.Nickname,
                MyHeadimg = user.HeadImg
            },
            Data = data
        };
    }

    /// <inheritdoc />
    public async Task<RankResponse> GetMonthRankAsync(int userId)
    {
        // 获取当前用户信息
        var user = await _dbContext.Users
            .Where(u => u.Id == userId)
            .Select(u => new { u.Nickname, u.HeadImg })
            .FirstOrDefaultAsync();

        if (user == null)
        {
            throw new InvalidOperationException("用户不存在");
        }

        // 计算本月时间范围
        var (monthStart, monthEnd) = GetMonthRange(DateTime.Now);
        var monthStartTimestamp = ToUnixTimestamp(monthStart);
        var monthEndTimestamp = ToUnixTimestamp(monthEnd);

        // 查询当前用户本月消费总额
        var myOrderTotal = await _dbContext.Orders
            .Where(o => o.UserId == userId
                && o.Addtime >= monthStartTimestamp
                && o.Addtime <= monthEndTimestamp
                && o.Status == 1
                && o.OrderType < 5)
            .SumAsync(o => (decimal?)o.OrderTotal) ?? 0;

        // 查询排行榜前30名
        var rankData = await _dbContext.Orders
            .Where(o => o.Addtime >= monthStartTimestamp
                && o.Addtime <= monthEndTimestamp
                && o.Status == 1
                && o.OrderType < 5)
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                OrderTotal = g.Sum(o => o.OrderTotal)
            })
            .OrderByDescending(x => x.OrderTotal)
            .ThenBy(x => x.UserId)
            .Take(30)
            .ToListAsync();

        // 获取用户信息
        var userIds = rankData.Select(r => r.UserId).ToList();
        var users = await _dbContext.Users
            .Where(u => userIds.Contains(u.Id))
            .Select(u => new { u.Id, u.Nickname, u.HeadImg })
            .ToDictionaryAsync(u => u.Id);

        // 获取月榜奖品信息 (goods_id = -2 表示月榜奖品)
        var prizes = await _dbContext.GoodsItems
            .Where(g => g.GoodsId == -2 && g.Rank >= 1 && g.Rank <= 30)
            .Select(g => new { g.Rank, g.Title, g.ImgUrl })
            .ToDictionaryAsync(g => g.Rank);

        // 构建排行榜数据
        var data = new List<RankItemDto>();
        object myRank = "暂未上榜";
        object myPrizeTitle = 0;
        object myPrizeImgurl = 0;

        for (int i = 0; i < rankData.Count; i++)
        {
            var item = rankData[i];
            var rank = i + 1;
            var userInfo = users.GetValueOrDefault(item.UserId);
            var prizeInfo = prizes.GetValueOrDefault(rank);

            var rankItem = new RankItemDto
            {
                Rank = rank,
                UserId = item.UserId,
                Nickname = userInfo?.Nickname ?? "",
                Headimg = userInfo?.HeadImg ?? "",
                OrderTotal = item.OrderTotal,
                PrizeTitle = prizeInfo?.Title ?? "",
                PrizeImgurl = prizeInfo?.ImgUrl ?? ""
            };

            data.Add(rankItem);

            // 判断当前用户是否在排名中
            if (item.UserId == userId)
            {
                myRank = rank;
                myPrizeTitle = prizeInfo?.Title ?? "";
                myPrizeImgurl = prizeInfo?.ImgUrl ?? "";
            }
        }

        return new RankResponse
        {
            Date = $"{monthStart:MM月dd日}-{monthEnd:MM月dd日}",
            EndDate = monthEndTimestamp,
            MyRank = new MyRankDto
            {
                MyRank = myRank,
                MyPrizeTitle = myPrizeTitle,
                MyPrizeImgurl = myPrizeImgurl,
                MyOrderTotal = myOrderTotal,
                MyNickname = user.Nickname,
                MyHeadimg = user.HeadImg
            },
            Data = data
        };
    }

    /// <summary>
    /// 获取本周时间范围（周一00:00:00到周日23:59:59）
    /// </summary>
    private static (DateTime start, DateTime end) GetWeekRange(DateTime date)
    {
        // 获取当前是周几 (0=周日, 1=周一, ..., 6=周六)
        var dayOfWeek = (int)date.DayOfWeek;
        
        // 计算到周一的天数差
        var daysToMonday = dayOfWeek == 0 ? 6 : dayOfWeek - 1;
        
        // 本周一00:00:00
        var weekStart = date.Date.AddDays(-daysToMonday);
        
        // 本周日23:59:59
        var weekEnd = weekStart.AddDays(6).AddHours(23).AddMinutes(59).AddSeconds(59);
        
        return (weekStart, weekEnd);
    }

    /// <summary>
    /// 获取本月时间范围（1号00:00:00到月末23:59:59）
    /// </summary>
    private static (DateTime start, DateTime end) GetMonthRange(DateTime date)
    {
        // 本月1号00:00:00
        var monthStart = new DateTime(date.Year, date.Month, 1, 0, 0, 0);
        
        // 本月最后一天23:59:59
        var daysInMonth = DateTime.DaysInMonth(date.Year, date.Month);
        var monthEnd = new DateTime(date.Year, date.Month, daysInMonth, 23, 59, 59);
        
        return (monthStart, monthEnd);
    }

    /// <summary>
    /// 将DateTime转换为Unix时间戳
    /// </summary>
    private static int ToUnixTimestamp(DateTime dateTime)
    {
        return (int)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
    }

    /// <inheritdoc />
    public async Task<List<GenericRankItemDto>> GetRankListAsync(string type, int page = 1, int limit = 10)
    {
        if (!ValidRankTypes.Contains(type))
        {
            throw new InvalidOperationException("无效的排行榜类型");
        }

        return type.ToLower() switch
        {
            "diamond" => await GetDiamondRankAsync(page, limit),
            "integral" => await GetIntegralRankAsync(page, limit),
            "dadajuan" => await GetDadajuanRankAsync(page, limit),
            "invite" => await GetInviteRankAsync(page, limit),
            "loss" => await GetLossRankAsync(page, limit),
            _ => new List<GenericRankItemDto>()
        };
    }

    /// <inheritdoc />
    public async Task<ConsumeRecordResponse> GetConsumeRecordAsync(int page = 1, int limit = 10)
    {
        // 获取本月时间范围
        var (monthStart, monthEnd) = GetMonthRange(DateTime.Now);
        var monthStartTimestamp = ToUnixTimestamp(monthStart);
        var monthEndTimestamp = ToUnixTimestamp(monthEnd);

        // 查询本月消费排行榜
        var rankData = await _dbContext.Orders
            .Where(o => o.Status == 1
                && o.Price > 0
                && o.Addtime >= monthStartTimestamp
                && o.Addtime <= monthEndTimestamp)
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                Price = g.Sum(o => o.Price)
            })
            .OrderByDescending(x => x.Price)
            .Skip((page - 1) * limit)
            .Take(limit)
            .ToListAsync();

        // 获取用户信息
        var userIds = rankData.Select(r => r.UserId).ToList();
        var users = await _dbContext.Users
            .Where(u => userIds.Contains(u.Id))
            .Select(u => new { u.Id, u.Nickname, u.HeadImg, u.Mobile })
            .ToDictionaryAsync(u => u.Id);

        // 构建响应数据
        var list = rankData.Select(item =>
        {
            var userInfo = users.GetValueOrDefault(item.UserId);
            return new ConsumeRecordItemDto
            {
                UserId = item.UserId,
                Nickname = userInfo?.Nickname ?? "",
                Headimg = userInfo?.HeadImg ?? "",
                Mobile = userInfo?.Mobile ?? "",
                Price = item.Price
            };
        }).ToList();

        return new ConsumeRecordResponse { List = list };
    }

    #region Private Rank Methods

    /// <summary>
    /// 获取钻石排行榜
    /// </summary>
    private async Task<List<GenericRankItemDto>> GetDiamondRankAsync(int page, int limit)
    {
        // 获取测试用户ID列表
        var testUserIds = await _dbContext.Users
            .Where(u => u.IsTest > 0 && u.Status == 1)
            .Select(u => u.Id)
            .ToListAsync();

        // 查询钻石消费排行
        var rankData = await _dbContext.Orders
            .Where(o => o.Status == 1
                && o.UseMoney > 0
                && !testUserIds.Contains(o.UserId))
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                Value = g.Sum(o => o.UseMoney)
            })
            .OrderByDescending(x => x.Value)
            .Skip((page - 1) * limit)
            .Take(limit)
            .ToListAsync();

        return await BuildRankListAsync(rankData, page, limit, "钻石");
    }

    /// <summary>
    /// 获取UU币排行榜
    /// </summary>
    private async Task<List<GenericRankItemDto>> GetIntegralRankAsync(int page, int limit)
    {
        // 获取测试用户ID列表
        var testUserIds = await _dbContext.Users
            .Where(u => u.IsTest > 0 && u.Status == 1)
            .Select(u => u.Id)
            .ToListAsync();

        // 查询积分消费排行
        var rankData = await _dbContext.Orders
            .Where(o => o.Status == 1
                && o.UseIntegral > 0
                && !testUserIds.Contains(o.UserId))
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                Value = g.Sum(o => o.UseIntegral)
            })
            .OrderByDescending(x => x.Value)
            .Skip((page - 1) * limit)
            .Take(limit)
            .ToListAsync();

        return await BuildRankListAsync(rankData, page, limit, "UU币");
    }

    /// <summary>
    /// 获取达达卷排行榜
    /// </summary>
    private async Task<List<GenericRankItemDto>> GetDadajuanRankAsync(int page, int limit)
    {
        // 达达卷排行榜默认显示更多数据
        var actualLimit = limit == 10 ? 200 : limit;

        // 获取测试用户ID列表
        var testUserIds = await _dbContext.Users
            .Where(u => u.IsTest > 0 && u.Status == 1)
            .Select(u => u.Id)
            .ToListAsync();

        // 查询达达卷回收排行
        var rankData = await _dbContext.OrderItemsRecoveries
            .Where(o => o.Money > 0
                && !testUserIds.Contains(o.UserId))
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                Value = g.Sum(o => o.Money) * 100 // 转换为达达卷单位
            })
            .OrderByDescending(x => x.Value)
            .Skip((page - 1) * actualLimit)
            .Take(actualLimit)
            .ToListAsync();

        return await BuildRankListAsync(rankData, page, actualLimit, "达达卷");
    }

    /// <summary>
    /// 获取邀请排行榜
    /// </summary>
    private async Task<List<GenericRankItemDto>> GetInviteRankAsync(int page, int limit)
    {
        // 邀请排行榜默认显示更多数据
        var actualLimit = limit == 10 ? 50 : limit;

        // 查询邀请排行
        var rankData = await _dbContext.Users
            .Where(u => u.Pid > 0 && u.IsTest == 0 && u.Status == 1)
            .GroupBy(u => u.Pid)
            .Select(g => new
            {
                UserId = g.Key,
                Value = (decimal)g.Count()
            })
            .Where(x => x.Value > 0)
            .OrderByDescending(x => x.Value)
            .Skip((page - 1) * actualLimit)
            .Take(actualLimit)
            .ToListAsync();

        return await BuildRankListAsync(rankData, page, actualLimit, "人");
    }

    /// <summary>
    /// 获取亏损排行榜
    /// </summary>
    private async Task<List<GenericRankItemDto>> GetLossRankAsync(int page, int limit)
    {
        // 获取测试用户ID列表
        var testUserIds = await _dbContext.Users
            .Where(u => u.IsTest > 0)
            .Select(u => u.Id)
            .ToListAsync();

        // 查询订单消费数据
        var orderData = await _dbContext.Orders
            .Where(o => o.Status == 1 && !testUserIds.Contains(o.UserId))
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                ConsumeMoney = g.Sum(o => o.Price)
            })
            .ToListAsync();

        // 获取所有相关用户ID
        var userIds = orderData.Select(o => o.UserId).ToList();

        // 查询出货金额
        var outputData = await _dbContext.OrderItems
            .Where(o => userIds.Contains(o.UserId))
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                OutputMoney = g.Sum(o => o.GoodslistMoney)
            })
            .ToDictionaryAsync(x => x.UserId, x => x.OutputMoney);

        // 查询达达卷金额
        var dadaData = await _dbContext.OrderItemsRecoveries
            .Where(o => userIds.Contains(o.UserId))
            .GroupBy(o => o.UserId)
            .Select(g => new
            {
                UserId = g.Key,
                DadaMoney = g.Sum(o => o.Money)
            })
            .ToDictionaryAsync(x => x.UserId, x => x.DadaMoney);

        // 计算亏损并排序
        var lossData = orderData
            .Select(o =>
            {
                var outputMoney = outputData.GetValueOrDefault(o.UserId, 0);
                var dadaMoney = dadaData.GetValueOrDefault(o.UserId, 0);
                var lossMoney = outputMoney - (o.ConsumeMoney + dadaMoney);
                return new { o.UserId, LossMoney = lossMoney };
            })
            .Where(x => x.LossMoney < 0) // 只显示亏损用户
            .OrderBy(x => x.LossMoney) // 亏损越多排名越前
            .Skip((page - 1) * limit)
            .Take(limit)
            .ToList();

        // 获取用户信息
        var lossUserIds = lossData.Select(x => x.UserId).ToList();
        var users = await _dbContext.Users
            .Where(u => lossUserIds.Contains(u.Id))
            .Select(u => new { u.Id, u.Nickname, u.HeadImg })
            .ToDictionaryAsync(u => u.Id);

        // 构建排行榜数据
        var result = new List<GenericRankItemDto>();
        var offset = (page - 1) * limit;
        for (int i = 0; i < lossData.Count; i++)
        {
            var item = lossData[i];
            var userInfo = users.GetValueOrDefault(item.UserId);
            if (userInfo != null)
            {
                result.Add(new GenericRankItemDto
                {
                    Rank = offset + i + 1,
                    UserId = item.UserId,
                    Nickname = userInfo.Nickname ?? "",
                    Headimg = userInfo.HeadImg ?? "",
                    Value = Math.Abs(item.LossMoney), // 显示亏损金额的绝对值
                    Unit = "元"
                });
            }
        }

        return result;
    }

    /// <summary>
    /// 构建排行榜列表
    /// </summary>
    private async Task<List<GenericRankItemDto>> BuildRankListAsync<T>(
        List<T> rankData,
        int page,
        int limit,
        string unit) where T : class
    {
        // 使用反射获取UserId和Value属性
        var userIdProp = typeof(T).GetProperty("UserId");
        var valueProp = typeof(T).GetProperty("Value");

        if (userIdProp == null || valueProp == null)
        {
            return new List<GenericRankItemDto>();
        }

        var userIds = rankData.Select(r => (int)userIdProp.GetValue(r)!).ToList();
        var users = await _dbContext.Users
            .Where(u => userIds.Contains(u.Id))
            .Select(u => new { u.Id, u.Nickname, u.HeadImg })
            .ToDictionaryAsync(u => u.Id);

        var result = new List<GenericRankItemDto>();
        var offset = (page - 1) * limit;

        for (int i = 0; i < rankData.Count; i++)
        {
            var item = rankData[i];
            var userId = (int)userIdProp.GetValue(item)!;
            var value = Convert.ToDecimal(valueProp.GetValue(item));
            var userInfo = users.GetValueOrDefault(userId);

            if (userInfo != null)
            {
                result.Add(new GenericRankItemDto
                {
                    Rank = offset + i + 1,
                    UserId = userId,
                    Nickname = userInfo.Nickname ?? "",
                    Headimg = userInfo.HeadImg ?? "",
                    Value = value,
                    Unit = unit
                });
            }
        }

        return result;
    }

    #endregion
}
