using System;
using System.Linq;
using PolyTrader.Modules.ResolutionFarming.Models;
using PolyTrader.Modules.ResolutionFarming.Persistence.Ef;
using PolyTrader.Tests.TestSupport;
using Xunit;
namespace PolyTrader.Tests
{
/// EF-InMemory-Tests der ResolutionFarming-Repositories (rf_-Tabellen).
public class RfRepositoryTests
{
private static InMemoryContextFactory Factory() =>
new(o => new ResolutionFarmingDbContext(o));
// ----- Settings -----
[Fact]
public void Settings_upsert_inserts_then_updates()
{
var f = Factory();
var repo = new EfRfSettingsRepository(f);
repo.Upsert(new RfSettings { AccountId = 1, MaxPerMarketUsd = 25m });
repo.Upsert(new RfSettings { AccountId = 1, MaxPerMarketUsd = 50m });
Assert.Single(repo.GetAll());
Assert.Equal(50m, repo.Get(1)!.MaxPerMarketUsd);
Assert.Null(repo.Get(99));
}
// ----- Candidates -----
[Fact]
public void Candidates_getrecent_orders_desc_and_limits()
{
var f = Factory();
var repo = new EfRfCandidateRepository(f);
var t0 = new DateTime(2026, 7, 1, 0, 0, 0, DateTimeKind.Utc);
for (int i = 0; i < 5; i++)
repo.Insert(new RfCandidate { AccountId = 1, TokenId = "t" + i, ScannedAt = t0.AddMinutes(i) });
repo.Insert(new RfCandidate { AccountId = 2, TokenId = "other", ScannedAt = t0.AddMinutes(99) });
var recent = repo.GetRecent(1, 3);
Assert.Equal(3, recent.Count);
Assert.Equal("t4", recent[0].TokenId); // neuester zuerst
Assert.DoesNotContain(recent, c => c.AccountId == 2);
}
[Fact]
public void Candidate_id_is_db_generated()
{
var f = Factory();
var repo = new EfRfCandidateRepository(f);
repo.Insert(new RfCandidate { AccountId = 1, TokenId = "a" });
repo.Insert(new RfCandidate { AccountId = 1, TokenId = "b" });
var ids = repo.GetRecent(1, 10).Select(c => c.Id).ToList();
Assert.Equal(2, ids.Distinct().Count());
Assert.DoesNotContain(0L, ids); // Autoincrement, keine code-vergebene 0
}
// ----- Positions -----
[Fact]
public void Positions_upsert_find_delete_and_exposure()
{
var f = Factory();
var repo = new EfRfPositionRepository(f);
var now = DateTime.UtcNow;
repo.Upsert(new RfPosition { AccountId = 1, TokenId = "a", AmountUsd = 10m, OpenedAt = now });
repo.Upsert(new RfPosition { AccountId = 1, TokenId = "b", AmountUsd = 15m, OpenedAt = now });
repo.Upsert(new RfPosition { AccountId = 2, TokenId = "c", AmountUsd = 99m, OpenedAt = now });
Assert.Equal(2, repo.GetOpen(1).Count);
Assert.Equal(3, repo.GetAllOpen().Count);
Assert.Equal(15m, repo.Find(1, "b")!.AmountUsd);
// Update über denselben zusammengesetzten Schlüssel
repo.Upsert(new RfPosition { AccountId = 1, TokenId = "a", AmountUsd = 12m, OpenedAt = now });
Assert.Equal(12m, repo.Find(1, "a")!.AmountUsd);
Assert.Equal(2, repo.GetOpen(1).Count); // kein Duplikat
repo.Delete(1, "a");
Assert.Null(repo.Find(1, "a"));
}
[Fact]
public void Positions_countopenedsince_respects_account_and_time()
{
var f = Factory();
var repo = new EfRfPositionRepository(f);
var today = DateTime.UtcNow;
repo.Upsert(new RfPosition { AccountId = 1, TokenId = "a", OpenedAt = today });
repo.Upsert(new RfPosition { AccountId = 1, TokenId = "b", OpenedAt = today.AddDays(-2) });
repo.Upsert(new RfPosition { AccountId = 2, TokenId = "c", OpenedAt = today });
Assert.Equal(1, repo.CountOpenedSince(1, today.AddHours(-1)));
}
// ----- ClosedTrades -----
[Fact]
public void ClosedTrades_insert_find_and_pnl_sum()
{
var f = Factory();
var repo = new EfRfClosedTradeRepository(f);
var since = new DateTime(2026, 7, 9, 0, 0, 0, DateTimeKind.Utc);
repo.Insert(new RfClosedTrade { AccountId = 1, TokenId = "a", RealizedPnl = 5m, ClosedAt = since.AddHours(1) });
repo.Insert(new RfClosedTrade { AccountId = 1, TokenId = "b", RealizedPnl = -8m, ClosedAt = since.AddHours(2) });
repo.Insert(new RfClosedTrade { AccountId = 1, TokenId = "c", RealizedPnl = 100m, ClosedAt = since.AddDays(-1) }); // vor dem Fenster
repo.Insert(new RfClosedTrade { AccountId = 2, TokenId = "d", RealizedPnl = 50m, ClosedAt = since.AddHours(1) });
Assert.Equal(-3m, repo.RealizedPnlSince(1, since)); // 5 - 8, ohne 100 (zu alt), ohne Account 2
Assert.Equal(2, repo.Find(t => t.RealizedPnl > 0 && t.AccountId == 1).Count); // a (5) + c (100)
}
}
}