using MediatR;
using MiningService.Domain.AggregatesModel.MinerAggregate;
namespace MiningService.API.Application.Queries;
///
/// EN: Query to get mining history for a user.
/// VI: Query để lấy lịch sử đào của người dùng.
///
public record GetMiningHistoryQuery(Guid UserId, int Page = 1, int PageSize = 20) : IRequest;
public record MiningHistoryDto(
List Items,
int TotalCount,
int Page,
int PageSize);
public record MiningHistoryItemDto(
Guid Id,
decimal Amount,
string Source,
decimal RateSnapshot,
DateTime CreatedAt);
public class GetMiningHistoryQueryHandler : IRequestHandler
{
private readonly IMinerRepository _minerRepository;
public GetMiningHistoryQueryHandler(IMinerRepository minerRepository)
{
_minerRepository = minerRepository;
}
public async Task Handle(GetMiningHistoryQuery request, CancellationToken cancellationToken)
{
var miner = await _minerRepository.GetByUserIdAsync(request.UserId, cancellationToken);
if (miner == null)
return new MiningHistoryDto(new List(), 0, request.Page, request.PageSize);
var history = miner.MiningHistories
.OrderByDescending(h => h.EarnedAt)
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.Select(h => new MiningHistoryItemDto(h.Id, h.PointsEarned, h.Source, h.HourlyRateSnapshot, h.EarnedAt))
.ToList();
return new MiningHistoryDto(history, miner.MiningHistories.Count, request.Page, request.PageSize);
}
}
///
/// EN: Query to get current mining rate breakdown.
/// VI: Query để lấy chi tiết tỷ lệ đào hiện tại.
///
public record GetMiningRateQuery(Guid UserId) : IRequest;
public record MiningRateDto(
decimal BaseRate,
decimal RoleMultiplier,
decimal CircleBonus,
decimal ReferralBonus,
decimal StreakBonus,
decimal TotalRate,
decimal HourlyPoints,
decimal DailyPoints);
public class GetMiningRateQueryHandler : IRequestHandler
{
private readonly IMinerRepository _minerRepository;
public GetMiningRateQueryHandler(IMinerRepository minerRepository)
{
_minerRepository = minerRepository;
}
public async Task Handle(GetMiningRateQuery request, CancellationToken cancellationToken)
{
var miner = await _minerRepository.GetByUserIdAsync(request.UserId, cancellationToken);
if (miner == null) return null;
var rate = miner.CurrentRate;
var baseRate = 0.25m;
var roleMultiplier = GetRoleMultiplier(miner.Role);
var circleBonus = miner.CircleId.HasValue ? 0.25m : 0m;
var referralBonus = 0m; // Would need to query repository for actual count
var streakBonus = miner.Streak.BonusMultiplier;
var totalRate = baseRate * (1 + roleMultiplier) * (1 + circleBonus) * (1 + referralBonus) * (1 + streakBonus);
return new MiningRateDto(
baseRate,
roleMultiplier,
circleBonus,
referralBonus,
streakBonus,
totalRate,
totalRate,
totalRate * 24);
}
private static decimal GetRoleMultiplier(MinerRole role) => role switch
{
MinerRole.Pioneer => 0m,
MinerRole.Contributor => 0.10m,
MinerRole.Ambassador => 0.25m,
MinerRole.NodeOperator => 0.50m,
_ => 0m
};
}
///
/// EN: Query to get top miners leaderboard.
/// VI: Query để lấy bảng xếp hạng thợ đào.
///
public record GetLeaderboardQuery(int Limit = 100) : IRequest;
public record LeaderboardDto(List Entries);
public record LeaderboardEntryDto(
int Rank,
Guid MinerId,
Guid UserId,
decimal TotalPoints,
int StreakDays,
MinerRole Role);
public class GetLeaderboardQueryHandler : IRequestHandler
{
private readonly IMinerRepository _minerRepository;
public GetLeaderboardQueryHandler(IMinerRepository minerRepository)
{
_minerRepository = minerRepository;
}
public async Task Handle(GetLeaderboardQuery request, CancellationToken cancellationToken)
{
var topMiners = await _minerRepository.GetTopMinersAsync(request.Limit, cancellationToken);
var entries = topMiners.Select((m, i) => new LeaderboardEntryDto(
i + 1,
m.Id,
m.UserId,
m.TotalMinedPoints,
m.Streak.CurrentStreak,
m.Role)).ToList();
return new LeaderboardDto(entries);
}
}