namespace KArtSell.Modules.ModelOperations.ShadowRun;

/// <summary>
/// Calculates metrics for a single market phase.
/// Deterministic, stateless, PIT-safe (uses only provided returns).
/// </summary>
public sealed class PhaseMetricsCalculator
{
    private const decimal AnnualizationFactor = 252m; // Trading days per year

    /// <summary>
    /// Calculate Sharpe, Calmar, Max DD, Win Rate for a phase's daily returns.
    /// </summary>
    public static PhaseMetricsDto Calculate(List<decimal> dailyReturns)
    {
        if (dailyReturns.Count == 0)
            return new PhaseMetricsDto(
                TradingDays: 0,
                Return: 0m,
                Sharpe: 0m,
                WinRate: 0m,
                MaxDrawdown: 0m);

        var totalReturn = CalculateTotalReturn(dailyReturns);
        var (sharpe, _) = CalculateSharpeAndStdDev(dailyReturns);
        var winRate = CalculateWinRate(dailyReturns);
        var maxDD = CalculateMaxDrawdown(dailyReturns);

        return new PhaseMetricsDto(
            TradingDays: dailyReturns.Count,
            Return: totalReturn,
            Sharpe: sharpe,
            WinRate: winRate,
            MaxDrawdown: maxDD);
    }

    private static decimal CalculateTotalReturn(List<decimal> returns)
    {
        return (decimal)(returns.Aggregate(1.0, (acc, r) => acc * (double)(1 + r)) - 1);
    }

    private static (decimal Sharpe, decimal StdDev) CalculateSharpeAndStdDev(List<decimal> returns)
    {
        var mean = returns.Average();
        var variance = returns.Average(r => (r - mean) * (r - mean));
        var stdDev = (decimal)Math.Sqrt((double)variance);

        if (stdDev == 0m)
            return (0m, 0m);

        var sharpe = (mean / stdDev) * (decimal)Math.Sqrt((double)AnnualizationFactor);
        return (sharpe, stdDev);
    }

    private static decimal CalculateWinRate(List<decimal> returns)
    {
        if (returns.Count == 0)
            return 0m;

        var winDays = returns.Count(r => r > 0);
        return (decimal)winDays / returns.Count;
    }

    private static decimal CalculateMaxDrawdown(List<decimal> returns)
    {
        if (returns.Count == 0)
            return 0m;

        var cumulative = 1m;
        var peak = 1m;
        var maxDD = 0m;

        foreach (var r in returns)
        {
            cumulative *= (1 + r);
            if (cumulative > peak)
                peak = cumulative;

            var drawdown = (cumulative - peak) / peak;
            if (drawdown < maxDD)
                maxDD = drawdown;
        }

        return Math.Abs(maxDD);
    }
}

/// <summary>
/// Metrics for a single market phase.
/// </summary>
public record PhaseMetricsDto(
    int TradingDays,
    decimal Return,
    decimal Sharpe,
    decimal WinRate,
    decimal MaxDrawdown);
