using Managing.Domain.Backtests;

public class BacktestScorer
{
    // Updated weights without ProfitEfficiency
    private static readonly Dictionary<string, double> Weights = new Dictionary<string, double>
    {
        { "GrowthPercentage", 0.28 },
        { "SharpeRatio", 0.18 },
        { "MaxDrawdownPc", 0.15 },
        { "HodlComparison", 0.05 },
        { "WinRate", 0.18 },
        { "ProfitabilityBonus", 0.11 },
        { "TradeCount", 0.03 },
        { "RecoveryTime", 0.02 }
    };


    public static double CalculateTotalScore(BacktestScoringParams p)
    {
        try
        {
            var baseScore = CalculateBaseScore(p);
            var finalScore = ApplyProfitabilityRules(baseScore, p);

            return double.Clamp(finalScore, 0, 100);
        }
        catch
        {
            return 0;
        }
    }

    private static double CalculateBaseScore(BacktestScoringParams p)
    {
        var componentScores = new Dictionary<string, double>
        {
            { "GrowthPercentage", CalculateGrowthScore(p.GrowthPercentage) },
            { "SharpeRatio", CalculateSharpeScore(p.SharpeRatio) },
            { "MaxDrawdownPc", CalculateDrawdownScore(p.MaxDrawdownPc) },
            { "HodlComparison", CalculateHodlComparisonScore(p.GrowthPercentage, p.HodlPercentage) },
            { "WinRate", CalculateWinRateScore(p.WinRate, p.TradeCount) },
            { "ProfitabilityBonus", CalculateProfitabilityBonus(p.GrowthPercentage) },
            { "TradeCount", CalculateTradeCountScore(p.TradeCount) },
            { "RecoveryTime", CalculateRecoveryScore(p.MaxDrawdownRecoveryTime) }
        };

        return componentScores.Sum(kvp => kvp.Value * Weights[kvp.Key]);
    }

    private static double ApplyProfitabilityRules(double baseScore, BacktestScoringParams p)
    {
        // 1. Negative PnL Penalty (Core Rule)
        if (p.GrowthPercentage < 0)
        {
            baseScore = Math.Min(baseScore, 70) * GetNegativePnLMultiplier(p.GrowthPercentage);
        }

        // 2. Absolute PnL Validation (Additional Recommendation)
        if (p.TotalPnL <= 0)
        {
            baseScore = Math.Min(baseScore, 50);
        }

        // 3. Win Rate Validation (Additional Recommendation)
        if (p.WinRate < 0.3 && p.TradeCount > 10)
        {
            baseScore = Math.Min(baseScore, 60);
        }

        // 4. Minimum Profit Threshold (Additional Recommendation)
        if (p.GrowthPercentage < 2 && p.TradeCount > 5)
        {
            baseScore = Math.Min(baseScore, 80);
        }

        return baseScore;
    }

    private static double CalculateGrowthScore(double growthPercentage)
    {
        // More aggressive penalty for negative growth
        if (growthPercentage < 0)
        {
            return Math.Max(0, 40 + (growthPercentage * 2)); // -10% → 20, -20% → 0
        }

        // Require minimum 5% growth for full score
        return growthPercentage switch
        {
            < 5 => growthPercentage * 15, // 2% → 30, 4% → 60
            _ => 100
        };
    }

    // Existing multiplier calculation
    private static double GetNegativePnLMultiplier(double growthPercentage)
    {
        return growthPercentage switch
        {
            > -5 => 0.8,
            > -10 => 0.6,
            > -20 => 0.4,
            _ => 0.2
        };
    }

    private static double CalculateProfitabilityBonus(double growthPercentage)
    {
        return growthPercentage switch
        {
            > 0 => 100 * (1 - 1 / (1 + growthPercentage / 50)), // Diminishing returns
            _ => 0
        };
    }

    private static bool IsInactiveStrategy(BacktestScoringParams p)
    {
        // Detect strategies with no economic value
        return (p.GrowthPercentage <= p.HodlPercentage &&
                p.TotalPnL <= 0) ||
               p.TradeCount < 3;
    }

    private static double CalculateSharpeScore(double sharpeRatio)
    {
        return sharpeRatio switch
        {
            < 0 => 0,
            > 3 => 100,
            _ => (sharpeRatio / 3) * 100
        };
    }

    private static double CalculateDrawdownScore(double maxDrawdownPc)
    {
        return maxDrawdownPc switch
        {
            > 90 => 0,
            _ => 100 - Math.Pow(maxDrawdownPc / 90 * 100, 2) / 100
        };
    }

    private static double CalculateWinRateScore(double winRate, int tradeCount)
    {
        var baseScore = winRate * 100;
        var significanceFactor = Math.Min(1, tradeCount / 100.0);
        return baseScore * significanceFactor;
    }

    private static double CalculateHodlComparisonScore(double strategyGrowth, double hodlGrowth)
    {
        var difference = strategyGrowth - hodlGrowth;
        return difference switch
        {
            > 0 => 100 - (100 / (1 + difference / 5)),
            _ => Math.Max(0, 30 + difference * 3)
        };
    }

    private static double CalculateTradeCountScore(int tradeCount)
    {
        return Math.Min(100, Math.Max(0, (tradeCount - 10) * 0.5));
    }

    private static double CalculateRecoveryScore(TimeSpan recoveryTime)
    {
        var days = recoveryTime.TotalDays;
        return days switch
        {
            < 0 => 100,
            > 365 => 0,
            _ => 100 - (days / 365 * 100)
        };
    }

    private static double CalculateRiskAdjustedGrowthScore(double growth, double drawdown)
    {
        if (drawdown == 0) return 100;
        var ratio = growth / drawdown;
        return Math.Min(ratio * 10, 100);
    }
}