using System.Collections.Generic;
using Predictalytics.Application.Services;
using Xunit;

namespace Predictalytics.Application.Tests.Services;

public class StrategyMetricsCalculatorTests
{
    // ── Concentration (Herfindahl) ────────────────────────────────────────────
    [Fact]
    public void Concentration_SingleCategory_IsOne()
    {
        Assert.Equal(1.0m, StrategyMetricsCalculator.ComputeConcentration(new[] { 500m }));
    }

    [Fact]
    public void Concentration_TwoEqualCategories_IsHalf()
    {
        // shares 0.5, 0.5 -> 0.25 + 0.25 = 0.5
        Assert.Equal(0.5m, StrategyMetricsCalculator.ComputeConcentration(new[] { 100m, 100m }));
    }

    [Fact]
    public void Concentration_SpecialistScoresHigherThanGeneralist()
    {
        var specialist = StrategyMetricsCalculator.ComputeConcentration(new[] { 900m, 50m, 50m });
        var generalist = StrategyMetricsCalculator.ComputeConcentration(new[] { 100m, 100m, 100m, 100m });
        Assert.True(specialist > generalist);
    }

    [Fact]
    public void Concentration_NoVolume_IsZero()
    {
        Assert.Equal(0m, StrategyMetricsCalculator.ComputeConcentration(new[] { 0m, 0m }));
    }

    // ── Conviction / sizing edge ──────────────────────────────────────────────
    [Fact]
    public void Conviction_TooFewMarkets_IsNull()
    {
        var markets = new List<(decimal, decimal)> { (10m, 5m), (20m, 5m), (30m, 5m) };
        Assert.Null(StrategyMetricsCalculator.ComputeConvictionEdge(markets));
    }

    [Fact]
    public void Conviction_BigBetsWinMore_IsPositive()
    {
        // small bets (invested 10-30) return ~0%, big bets (invested 100-120) return ~+40%
        var markets = new List<(decimal Invested, decimal ReturnPct)>
        {
            (10m, 0m), (20m, 2m), (30m, -2m),
            (50m, 5m), (60m, 3m), (70m, 4m),
            (100m, 40m), (110m, 38m), (120m, 42m),
        };
        var edge = StrategyMetricsCalculator.ComputeConvictionEdge(markets);
        Assert.NotNull(edge);
        Assert.True(edge > 30m); // big third avg ~40 minus small third avg ~0
    }

    [Fact]
    public void Conviction_OverbetsLosers_IsNegative()
    {
        // big bets LOSE, small bets win -> negative conviction (a red flag)
        var markets = new List<(decimal Invested, decimal ReturnPct)>
        {
            (10m, 20m), (20m, 25m), (30m, 22m),
            (50m, 5m), (60m, 3m), (70m, 4m),
            (100m, -30m), (110m, -35m), (120m, -28m),
        };
        var edge = StrategyMetricsCalculator.ComputeConvictionEdge(markets);
        Assert.NotNull(edge);
        Assert.True(edge < 0m);
    }
}
