using System;
using System.Linq;
using Predictalytics.Application.Services;
using Predictalytics.Domain.Entities;
using Xunit;

namespace Predictalytics.Application.Tests.Services;

public class FingerprintDriftCalculatorTests
{
    private static TraderFingerprintSnapshot Snap(
        decimal score = 70m, decimal conc = 0.5m, decimal? conv = 5m,
        decimal p50 = 100m, string? mix = null, string? traits = null, int daysAgo = 0)
        => new()
        {
            TraderId = 1,
            CapturedAt = DateTime.UtcNow.AddDays(-daysAgo),
            CopytradingScore = score,
            CategoryConcentration = conc,
            ConvictionEdgePct = conv,
            P50PositionSize = p50,
            CategoryMixJson = mix,
            TraitSetJson = traits
        };

    [Fact]
    public void IdenticalFingerprints_DoNotDrift()
    {
        var b = Snap(mix: "{\"Sports\":1.0}", traits: "[\"scalper\"]", daysAgo: 14);
        var c = Snap(mix: "{\"Sports\":1.0}", traits: "[\"scalper\"]");
        var r = FingerprintDriftCalculator.Compare(b, c);
        Assert.False(r.HasDrifted);
        Assert.Empty(r.Dimensions);
    }

    [Fact]
    public void ScoreDrop_IsFlagged_ButScoreGainIsNot()
    {
        var dropped = FingerprintDriftCalculator.Compare(Snap(score: 70m, daysAgo: 14), Snap(score: 50m));
        Assert.Contains(dropped.Dimensions, d => d.Dimension == "score");

        var gained = FingerprintDriftCalculator.Compare(Snap(score: 50m, daysAgo: 14), Snap(score: 70m));
        Assert.DoesNotContain(gained.Dimensions, d => d.Dimension == "score");
    }

    [Fact]
    public void CategoryMixReversal_FlagsCategoryMix()
    {
        var b = Snap(mix: "{\"Sports\":1.0}", daysAgo: 14);
        var c = Snap(mix: "{\"Politics\":1.0}");
        var r = FingerprintDriftCalculator.Compare(b, c);
        Assert.Contains(r.Dimensions, d => d.Dimension == "category_mix");
    }

    [Fact]
    public void TraitSetChange_And_SizingJump_And_ConvictionFlip_AreFlagged()
    {
        var b = Snap(conv: 6m, p50: 100m, traits: "[\"scalper\"]", daysAgo: 14);
        var c = Snap(conv: -4m, p50: 350m, traits: "[\"whale\",\"holds_to_resolution\"]");
        var r = FingerprintDriftCalculator.Compare(b, c);

        Assert.True(r.HasDrifted);
        Assert.Contains(r.Dimensions, d => d.Dimension == "trait_set");
        Assert.Contains(r.Dimensions, d => d.Dimension == "sizing");
        Assert.Contains(r.Dimensions, d => d.Dimension == "conviction");
    }
}
