namespace Predictalytics.Application.Services;

/// <summary>Risk/smoothness metrics derived from a trader's daily equity curve.</summary>
public readonly record struct RiskMetrics(
    decimal MaxDrawdownUsd,
    decimal PnlVolatilityUsd,
    int LongestLosingStreakDays);

/// <summary>
/// Computes how SMOOTH a trader's path to their PnL was — a core copyability signal.
/// Two traders with identical final PnL are very differently copyable if one got there
/// steadily and the other via a violent up-and-down ride: the copier who joins mid-drawdown
/// of the volatile trader may never recover. Pure function, no DB/API access.
/// </summary>
public static class RiskMetricsCalculator
{
    /// <param name="snapshotsAsc">Daily cumulative PnL points, ascending by date.</param>
    public static RiskMetrics Compute(IReadOnlyList<(DateTime Date, decimal TotalPnl)> snapshotsAsc)
    {
        if (snapshotsAsc is null || snapshotsAsc.Count == 0)
            return new RiskMetrics(0m, 0m, 0);

        // Max drawdown: largest peak-to-trough drop of the cumulative-PnL curve (in USD).
        decimal peak = snapshotsAsc[0].TotalPnl;
        decimal maxDrawdown = 0m;
        foreach (var s in snapshotsAsc)
        {
            if (s.TotalPnl > peak) peak = s.TotalPnl;
            var dd = peak - s.TotalPnl;
            if (dd > maxDrawdown) maxDrawdown = dd;
        }

        // Day-over-day PnL deltas -> volatility (population stddev) + longest losing streak.
        var deltas = new List<decimal>(snapshotsAsc.Count);
        int streak = 0, longestStreak = 0;
        for (int i = 1; i < snapshotsAsc.Count; i++)
        {
            var d = snapshotsAsc[i].TotalPnl - snapshotsAsc[i - 1].TotalPnl;
            deltas.Add(d);
            if (d < 0)
            {
                streak++;
                if (streak > longestStreak) longestStreak = streak;
            }
            else
            {
                streak = 0;
            }
        }

        decimal volatility = 0m;
        if (deltas.Count > 0)
        {
            var mean = deltas.Average();
            var variance = deltas.Sum(x => (x - mean) * (x - mean)) / deltas.Count;
            volatility = (decimal)System.Math.Sqrt((double)variance);
        }

        return new RiskMetrics(
            System.Math.Round(maxDrawdown, 2),
            System.Math.Round(volatility, 2),
            longestStreak);
    }
}
