using System;
using System.Collections.Generic;
using System.Linq;
using PolyTrader.Core.Analytics;
using PolyTraderSharp.Models;
using Xunit;

namespace PolyTrader.Tests
{
    /// <summary>Sicherheitsnetz für die Dashboard-/Launcher-Auswertungen (KPIs, Equity-Kurve, Gruppierungen).</summary>
    public class TradeAnalyticsTests
    {
        private static TradeRecord Rec(decimal pnl, DateTime closedAt, string module = "M", int account = 1) =>
            new() { RealizedPnl = pnl, ClosedAt = closedAt, ModuleName = module, AccountId = account };

        private static readonly DateTime T0 = new(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc);

        [Fact]
        public void ComputeKpis_basic_set()
        {
            var k = TradeAnalytics.ComputeKpis(new[]
            {
                Rec(10m, T0), Rec(-4m, T0), Rec(6m, T0), Rec(-2m, T0)
            });

            Assert.Equal(4, k.TradeCount);
            Assert.Equal(10m, k.NetPnl);
            Assert.Equal(50m, k.WinRatePct);
            Assert.Equal(2.5m, k.AvgPnlPerTrade);
            Assert.Equal(2.6667m, Math.Round(k.ProfitFactor, 4)); // 16 / 6
        }

        [Fact]
        public void ComputeKpis_no_losses_uses_sentinel_profitfactor()
        {
            var k = TradeAnalytics.ComputeKpis(new[] { Rec(5m, T0), Rec(3m, T0) });
            Assert.Equal(100m, k.WinRatePct);
            Assert.Equal(TradeAnalytics.NoLossProfitFactor, k.ProfitFactor);
        }

        [Fact]
        public void ComputeKpis_empty_is_zero()
        {
            var k = TradeAnalytics.ComputeKpis(Array.Empty<TradeRecord>());
            Assert.Equal(0, k.TradeCount);
            Assert.Equal(0m, k.NetPnl);
            Assert.Equal(0m, k.ProfitFactor);
        }

        [Fact]
        public void EquityCurve_is_cumulative_and_time_ordered()
        {
            var curve = TradeAnalytics.EquityCurve(new[]
            {
                Rec(5m, T0.AddMinutes(2)),
                Rec(10m, T0.AddMinutes(1)),
                Rec(-3m, T0.AddMinutes(3))
            });

            Assert.Equal(3, curve.Count);
            Assert.Equal(10m, curve[0].Cumulative);   // frühester zuerst
            Assert.Equal(15m, curve[1].Cumulative);
            Assert.Equal(12m, curve[2].Cumulative);
        }

        [Fact]
        public void PnlByKey_groups_and_orders_desc()
        {
            var byModule = TradeAnalytics.PnlByKey(new[]
            {
                Rec(10m, T0, module: "A"), Rec(-2m, T0, module: "A"), Rec(5m, T0, module: "B")
            }, t => t.ModuleName);

            Assert.Equal(2, byModule.Count);
            Assert.Equal("A", byModule[0].Key);        // 8 vor 5
            Assert.Equal(8m, byModule[0].Pnl);
            Assert.Equal(2, byModule[0].Count);
            Assert.Equal("B", byModule[1].Key);
        }

        [Fact]
        public void PnlByDay_groups_by_calendar_day()
        {
            var byDay = TradeAnalytics.PnlByDay(new[]
            {
                Rec(4m, T0), Rec(6m, T0.AddHours(2)), Rec(-1m, T0.AddDays(1))
            });

            Assert.Equal(2, byDay.Count);
            Assert.Equal(10m, byDay[0].Pnl);   // Tag 1: 4+6
            Assert.Equal(-1m, byDay[1].Pnl);   // Tag 2
        }

        [Fact]
        public void WindowSummary_pnl_winrate_count()
        {
            var (pnl, winRate, count) = TradeAnalytics.WindowSummary(new[]
            {
                Rec(3m, T0), Rec(-1m, T0), Rec(2m, T0), Rec(-4m, T0)
            });

            Assert.Equal(0m, pnl);
            Assert.Equal(50m, winRate);
            Assert.Equal(4, count);
        }
    }
}
