using Fengling.RiskControl.Domain.Aggregates.LotteryActivities; using Fengling.RiskControl.Domain.Events; using Fengling.RiskControl.Domain.Repositories; using MediatR; namespace Fengling.RiskControl.Application.Services; public class LotteryService : ILotteryService { private const double WIN_PROBABILITY = 0.3; private const int MIN_WIN_MULTIPLIER = 2; private const int MAX_WIN_MULTIPLIER = 10; private readonly ILotteryActivityRepository _activityRepository; private readonly IRiskEvaluationService _riskService; private readonly IMediator _mediator; public LotteryService( ILotteryActivityRepository activityRepository, IRiskEvaluationService riskService, IMediator mediator) { _activityRepository = activityRepository; _riskService = riskService; _mediator = mediator; } public async Task ParticipateAsync(LotteryParticipationRequest request) { var riskResult = await _riskService.EvaluateRiskAsync(new RiskEvaluationRequest { MemberId = request.MemberId, EntityType = "lottery", EntityId = request.ActivityType, ActionType = "execute", Context = new Dictionary { ["stakePoints"] = request.StakePoints, ["activityType"] = request.ActivityType } }); if (riskResult.Blocked) { return new LotteryParticipationResult { Status = LotteryParticipationStatus.Blocked, Message = riskResult.Message, RiskResult = riskResult }; } var activity = LotteryActivity.Create( request.MemberId, request.ActivityType, request.StakePoints, request.IpAddress, request.DeviceId); activity.MarkProcessing(); await _activityRepository.AddAsync(activity); var (winAmount, isWin) = SimulateLotteryOutcome(request.StakePoints); activity.Complete(winAmount, isWin); await _mediator.Publish(new LotteryCompletedEvent( activity.Id, request.MemberId, request.StakePoints, winAmount, isWin, riskResult.TotalScore)); return new LotteryParticipationResult { ActivityId = activity.Id, Status = LotteryParticipationStatus.Allowed, WinAmount = winAmount, Message = isWin ? $"恭喜中奖! 获得 {winAmount} 积分" : "未中奖", RiskResult = riskResult }; } private (int winAmount, bool isWin) SimulateLotteryOutcome(int stakePoints) { var random = new Random(); var isWin = random.NextDouble() < WIN_PROBABILITY; var winAmount = isWin ? stakePoints * random.Next(MIN_WIN_MULTIPLIER, MAX_WIN_MULTIPLIER + 1) : 0; return (winAmount, isWin); } public Task GetActivityAsync(long activityId) { return _activityRepository.GetByIdAsync(activityId); } public Task> GetMemberActivitiesAsync(long memberId) { return _activityRepository.GetByMemberIdAsync(memberId); } }