using FluentAssertions; using Marathon.Application.Abstractions; using Marathon.Application.UseCases; using Marathon.Domain.Entities; using Marathon.Domain.Enums; using Marathon.Domain.ValueObjects; using Microsoft.Extensions.Logging.Abstractions; using NSubstitute; namespace Marathon.Application.Tests.UseCases; public sealed class SettlePaperBetsUseCaseTests { private static readonly TimeSpan Msk = TimeSpan.FromHours(3); private static readonly DateTimeOffset T0 = new(2026, 5, 20, 18, 0, 0, Msk); private readonly IPaperBetRepository _paperBets = Substitute.For(); private readonly IResultRepository _results = Substitute.For(); private SettlePaperBetsUseCase CreateSut() => new(_paperBets, _results, NullLogger.Instance); private static PaperBet Open(string eventCode, Side pick) => PaperBet.Open(Guid.NewGuid(), new EventId(eventCode), pick, 2.0m, 10m, T0); private static EventResult Result(string eventCode, Side winner) => new(new EventId(eventCode), 2, 1, winner, T0.AddHours(2)); private void HaveOpen(params PaperBet[] bets) => _paperBets.ListByOutcomeAsync(BetOutcome.Pending, Arg.Any()).Returns(bets); private void HaveResults(params EventResult[] results) => _results .GetManyAsync(Arg.Any>(), Arg.Any()) .Returns(results.ToDictionary(r => r.EventId)); [Fact] public async Task Settles_Won_When_PickMatchesWinner() { HaveOpen(Open("e1", Side.Side1)); HaveResults(Result("e1", Side.Side1)); var settled = await CreateSut().ExecuteAsync(); settled.Should().Be(1); await _paperBets.Received(1).UpdateAsync( Arg.Is(b => b.Outcome == BetOutcome.Won && b.Payout == 20m), Arg.Any()); await _paperBets.Received(1).SaveChangesAsync(Arg.Any()); } [Fact] public async Task Settles_Lost_When_PickMisses() { HaveOpen(Open("e1", Side.Side1)); HaveResults(Result("e1", Side.Side2)); await CreateSut().ExecuteAsync(); await _paperBets.Received(1).UpdateAsync( Arg.Is(b => b.Outcome == BetOutcome.Lost && b.Payout == 0m), Arg.Any()); } [Fact] public async Task LeavesOpen_When_EventNotGradedYet() { HaveOpen(Open("e1", Side.Side1)); HaveResults(); // none graded var settled = await CreateSut().ExecuteAsync(); settled.Should().Be(0); await _paperBets.DidNotReceive().UpdateAsync(Arg.Any(), Arg.Any()); await _paperBets.DidNotReceive().SaveChangesAsync(Arg.Any()); } [Fact] public async Task NoOp_When_NoOpenBets() { HaveOpen(); (await CreateSut().ExecuteAsync()).Should().Be(0); await _results.DidNotReceive().GetManyAsync(Arg.Any>(), Arg.Any()); } }