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

namespace Predictalytics.Application.Tests.Services;

public class CopyPortfolioBuilderTests
{
    private static readonly System.Func<int, int, double> NoCorrelation = (_, _) => 0.0;

    [Fact]
    public void PicksTopScoresFirst_WhenNoConstraintsBind()
    {
        var candidates = new List<PortfolioCandidate>
        {
            new(1, 90m, "Politics"),
            new(2, 80m, "Sports"),
            new(3, 70m, "Crypto"),
        };
        var r = CopyPortfolioBuilder.Build(candidates, NoCorrelation, size: 8, maxPerCategory: 2);
        Assert.Equal(new[] { 1, 2, 3 }, r.Picks.Select(p => p.TraderId).ToArray());
    }

    [Fact]
    public void EnforcesCategoryCap()
    {
        // Three Politics masters, cap 2 -> the third (lowest) is dropped for the cap.
        var candidates = new List<PortfolioCandidate>
        {
            new(1, 90m, "Politics"),
            new(2, 85m, "Politics"),
            new(3, 80m, "Politics"),
            new(4, 70m, "Sports"),
        };
        var r = CopyPortfolioBuilder.Build(candidates, NoCorrelation, size: 8, maxPerCategory: 2);

        Assert.Equal(new[] { 1, 2, 4 }, r.Picks.Select(p => p.TraderId).ToArray());
        Assert.Contains(3, r.DroppedForCategoryCap);
    }

    [Fact]
    public void DropsHighlyCorrelatedCandidate()
    {
        var candidates = new List<PortfolioCandidate>
        {
            new(1, 90m, "Politics"),
            new(2, 85m, "Sports"),   // highly correlated with #1 -> dropped
            new(3, 80m, "Crypto"),
        };
        // 1 and 2 move together; everyone else independent.
        double Sim(int a, int b) => (a == 1 && b == 2) || (a == 2 && b == 1) ? 0.9 : 0.0;

        var r = CopyPortfolioBuilder.Build(candidates, Sim, size: 8, maxPerCategory: 2, maxSimilarity: 0.6);

        Assert.Equal(new[] { 1, 3 }, r.Picks.Select(p => p.TraderId).ToArray());
        Assert.Contains(2, r.DroppedForCorrelation);
    }

    [Fact]
    public void RespectsSizeLimit()
    {
        var candidates = Enumerable.Range(1, 10)
            .Select(i => new PortfolioCandidate(i, 100m - i, $"Cat{i}")).ToList();
        var r = CopyPortfolioBuilder.Build(candidates, NoCorrelation, size: 3, maxPerCategory: 2);
        Assert.Equal(3, r.Picks.Count);
    }
}
