using System;
using System.Threading.Tasks;
using FinlyticEngine.Database;
using FinlyticEngine.Services.Trading;
using FinlyticEngine.Tests.TestSupport;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Xunit.Abstractions;
namespace FinlyticEngine.Tests._Verify;
///
/// ONE-OFF verification against a real, throwaway, locally-run PostgreSQL container (NOT the OmniDB
/// production database — a brand-new container started solely for this check, no compose.yaml/appsettings
/// connection strings involved) to settle whether the AddTradeFillAsync DbUpdateConcurrencyException
/// reproduced under EF InMemory/SQLite is a provider artifact or a genuine, provider-independent EF Core
/// change-tracking defect that would also occur in production. Deleted after the verdict is recorded.
///
public class PostgresVerificationTests
{
private readonly ITestOutputHelper _output;
public PostgresVerificationTests(ITestOutputHelper output) => _output = output;
private const string ConnString = "Host=localhost;Port=55987;Database=finlytic_verify;Username=postgres;Password=test";
[Fact]
public async Task RealPostgres_AddTradeFillAsync_ExactProductionCallPath_OwnerSucceeds()
{
var services = new ServiceCollection();
services.AddDbContext(o => o.UseNpgsql(ConnString));
await using var provider = services.BuildServiceProvider();
await using (var schemaDb = provider.GetRequiredService())
{
await schemaDb.Database.EnsureDeletedAsync();
await schemaDb.Database.EnsureCreatedAsync();
}
var scopeFactory = provider.GetRequiredService();
var owner = Guid.NewGuid();
var trade = TestData.ActiveTrade(owner);
using (var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService();
db.Trades.Add(trade);
await db.SaveChangesAsync();
}
var sut = new TradeLifecycleService(
scopeFactory,
new NeverInvokedCompositeOpportunityScorer(),
new NeverInvokedAiReasoningGateService(),
new NeverInvokedKnockOutDerivativeResolver(),
new FakeEngineRpcClient(),
new FakeSettingsService(),
new FakeFinlyticLogger());
// This calls the REAL, unmodified TradeLifecycleService.AddTradeFillAsync exactly as production code
// does, against a real PostgreSQL instance.
Exception? caught = null;
try
{
var dto = await sut.AddTradeFillAsync(owner, trade.Id, 105m, 1m);
_output.WriteLine($"SUCCEEDED. Trade {dto.TradeId} now has {dto.Fills.Count} fill(s).");
}
catch (Exception ex)
{
caught = ex;
_output.WriteLine($"THREW: {ex.GetType().FullName}: {ex.Message}");
}
Assert.Null(caught);
}
}