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

namespace Predictalytics.Application.Tests.Services;

public class RiskMetricsCalculatorTests
{
    private static List<(DateTime, decimal)> Curve(params decimal[] pnls)
    {
        var list = new List<(DateTime, decimal)>();
        var d = new DateTime(2026, 01, 01, 0, 0, 0, DateTimeKind.Utc);
        foreach (var p in pnls) { list.Add((d, p)); d = d.AddDays(1); }
        return list;
    }

    [Fact]
    public void Empty_ReturnsZeros()
    {
        var m = RiskMetricsCalculator.Compute(new List<(DateTime, decimal)>());
        Assert.Equal(0m, m.MaxDrawdownUsd);
        Assert.Equal(0m, m.PnlVolatilityUsd);
        Assert.Equal(0, m.LongestLosingStreakDays);
    }

    [Fact]
    public void MonotonicUp_HasNoDrawdownNoStreak()
    {
        // Steady climb 0 -> 10 -> 20 -> 30: the ideal, most-copyable curve.
        var m = RiskMetricsCalculator.Compute(Curve(0, 10, 20, 30));
        Assert.Equal(0m, m.MaxDrawdownUsd);
        Assert.Equal(0, m.LongestLosingStreakDays);
    }

    [Fact]
    public void DipFromPeak_MeasuresPeakToTroughDrawdown()
    {
        // Peak 100, trough 40 -> max drawdown 60. Ends back at 90.
        var m = RiskMetricsCalculator.Compute(Curve(0, 100, 70, 40, 90));
        Assert.Equal(60m, m.MaxDrawdownUsd);
    }

    [Fact]
    public void LongestLosingStreak_CountsConsecutiveDownDays()
    {
        // deltas: +100, -30, -30, -30, +50  -> 3 consecutive losing days
        var m = RiskMetricsCalculator.Compute(Curve(0, 100, 70, 40, 10, 60));
        Assert.Equal(3, m.LongestLosingStreakDays);
    }

    [Fact]
    public void Volatility_IsZeroForConstantDailyGain_PositiveForBumpyPath()
    {
        // Constant +10/day -> zero volatility of daily returns.
        var smooth = RiskMetricsCalculator.Compute(Curve(0, 10, 20, 30, 40));
        Assert.Equal(0m, smooth.PnlVolatilityUsd);

        // Same endpoint (+40) but a bumpy path -> positive volatility.
        var bumpy = RiskMetricsCalculator.Compute(Curve(0, 50, 10, 60, 40));
        Assert.True(bumpy.PnlVolatilityUsd > 0m);
    }
}
