using System;
using System.Collections.Generic;
using System.Linq;
using Predictalytics.Application.Services;
using Predictalytics.Domain.Entities;
using Predictalytics.Domain.Enums;
using Xunit;

namespace Predictalytics.Application.Tests.Services;

public class TradeAggregationTests
{
    private static Trade Raw(int outcomeId, TradeSide side, decimal price, decimal size, DateTime at)
        => new()
        {
            MarketOutcomeId = outcomeId, DbMarketId = 10, MarketId = "cond", AssetId = "asset",
            Outcome = "Yes", Side = side, Price = price, Size = size, Amount = price * size, ExecutedAt = at
        };

    [Fact]
    public void AggregateCompletedHours_SumsCompletedHourWithVwap()
    {
        var now = new DateTime(2026, 07, 13, 15, 30, 0, DateTimeKind.Utc);
        var completedHour = new DateTime(2026, 07, 13, 10, 0, 0, DateTimeKind.Utc);

        var trades = new List<Trade>
        {
            Raw(100, TradeSide.Buy, 0.40m, 50m, completedHour.AddMinutes(5)),
            Raw(100, TradeSide.Buy, 0.60m, 50m, completedHour.AddMinutes(45)),
        };

        var result = TradeAggregation.AggregateCompletedHours(trades, traderId: 7, nowUtc: now);

        var agg = Assert.Single(result);
        Assert.Equal("AGG_7_100_Buy_2026071310", agg.PlatformTradeId);
        Assert.Equal(100m, agg.Size);            // 50 + 50
        Assert.Equal(50m, agg.Amount);           // 0.40*50 + 0.60*50 = 20 + 30
        Assert.Equal(0.50m, agg.Price);          // VWAP = 50/100
        Assert.Equal(2, agg.AggregatedCount);
    }

    [Fact]
    public void AggregateCompletedHours_DefersCurrentHour()
    {
        // The bug this guards against: the current, still-growing hour must NOT be aggregated,
        // because its aggregate row is mutable-by-key while the PnL engine checkpoints by Id.
        var now = new DateTime(2026, 07, 13, 15, 30, 0, DateTimeKind.Utc);

        var trades = new List<Trade>
        {
            // completed hour -> aggregated
            Raw(100, TradeSide.Buy, 0.50m, 40m, new DateTime(2026, 07, 13, 14, 10, 0, DateTimeKind.Utc)),
            // current hour (15:xx) -> deferred
            Raw(100, TradeSide.Buy, 0.50m, 99m, new DateTime(2026, 07, 13, 15, 05, 0, DateTimeKind.Utc)),
        };

        var result = TradeAggregation.AggregateCompletedHours(trades, traderId: 7, nowUtc: now);

        Assert.Single(result);                                   // only the 14:00 bucket
        Assert.EndsWith("_2026071314", result[0].PlatformTradeId);
        Assert.Equal(40m, result[0].Size);                       // current-hour 99 shares NOT included
    }

    [Fact]
    public void AggregateCompletedHours_SeparatesOutcomeAndSide()
    {
        var now = new DateTime(2026, 07, 13, 15, 0, 0, DateTimeKind.Utc);
        var h = new DateTime(2026, 07, 13, 12, 0, 0, DateTimeKind.Utc);

        var trades = new List<Trade>
        {
            Raw(100, TradeSide.Buy,  0.50m, 10m, h),
            Raw(100, TradeSide.Sell, 0.50m, 10m, h),
            Raw(101, TradeSide.Buy,  0.50m, 10m, h),
        };

        var result = TradeAggregation.AggregateCompletedHours(trades, traderId: 7, nowUtc: now);

        Assert.Equal(3, result.Count); // (100,Buy), (100,Sell), (101,Buy) are distinct buckets
    }
}
