using Managing.Domain.Risk;
using static Managing.Common.Enums;

namespace Managing.Domain.Synth.Models;

/// <summary>
/// Result of Synth signal validation containing comprehensive analysis data
/// </summary>
public class SignalValidationResult
{
    /// <summary>
    /// Overall confidence level of the signal based on TP vs SL probability analysis
    /// </summary>
    public Confidence Confidence { get; set; }

    /// <summary>
    /// Raw stop loss probability (0.0 to 1.0)
    /// </summary>
    public decimal StopLossProbability { get; set; }

    /// <summary>
    /// Raw take profit probability (0.0 to 1.0)
    /// </summary>
    public decimal TakeProfitProbability { get; set; }

    /// <summary>
    /// Calculated ratio of Take Profit Probability / Stop Loss Probability
    /// Higher values indicate more favorable risk/reward
    /// </summary>
    public decimal TpSlRatio { get; set; }

    /// <summary>
    /// Indicates if the signal should be blocked based on risk analysis
    /// True when confidence is None or adverse probability is too high
    /// </summary>
    public bool IsBlocked { get; set; }

    /// <summary>
    /// Threshold used for adverse probability evaluation
    /// </summary>
    public decimal AdverseProbabilityThreshold { get; set; }

    /// <summary>
    /// Additional context information about the validation
    /// </summary>
    public string ValidationContext { get; set; } = string.Empty;

    /// <summary>
    /// Time horizon used for the probability calculations (in seconds)
    /// </summary>
    public int TimeHorizonSeconds { get; set; }

    /// <summary>
    /// Whether custom thresholds were used in the analysis
    /// </summary>
    public bool UsedCustomThresholds { get; set; }

    /// <summary>
    /// Monetary gain if take profit is reached (positive value)
    /// </summary>
    public decimal TakeProfitGain { get; set; }

    /// <summary>
    /// Monetary loss if stop loss is hit (positive value representing loss amount)
    /// </summary>
    public decimal StopLossLoss { get; set; }

    /// <summary>
    /// Expected Monetary Value: (TP_Gain * TP_Prob) - (SL_Loss * SL_Prob)
    /// Positive values indicate favorable expected outcomes
    /// </summary>
    public decimal ExpectedMonetaryValue { get; set; }

    /// <summary>
    /// Expected Utility using logarithmic utility function for risk-adjusted decision making
    /// Higher values indicate more desirable risk-adjusted outcomes
    /// </summary>
    public decimal ExpectedUtility { get; set; }

    /// <summary>
    /// Risk-adjusted return ratio (Expected Utility / Risk)
    /// Higher values indicate better risk-adjusted opportunities
    /// </summary>
    public decimal UtilityRiskRatio { get; set; }

    /// <summary>
    /// Kelly Criterion fraction - optimal percentage of capital to allocate (0.0 to 1.0)
    /// Based on Kelly formula: f* = (bp - q) / b, where b = payoff ratio, p = win probability, q = loss probability
    /// Values above 0.25 (25%) are typically capped for practical risk management
    /// </summary>
    public decimal KellyFraction { get; set; }

    /// <summary>
    /// Capped Kelly Fraction for practical risk management (typically max 25% of capital)
    /// </summary>
    public decimal KellyCappedFraction { get; set; }

    /// <summary>
    /// Win/Loss ratio used in Kelly calculation (TakeProfitGain / StopLossLoss)
    /// </summary>
    public decimal WinLossRatio { get; set; }

    /// <summary>
    /// Kelly Criterion assessment indicating the quality of the opportunity
    /// </summary>
    public string KellyAssessment { get; set; } = string.Empty;

    /// <summary>
    /// Risk tolerance level affecting overall risk calculations
    /// </summary>
    public RiskToleranceLevel RiskTolerance { get; set; } = RiskToleranceLevel.Moderate;

    /// <summary>
    /// Whether to use Expected Utility Theory for decision making
    /// </summary>
    public bool UseExpectedUtility { get; set; } = true;

    /// <summary>
    /// Whether to use Kelly Criterion for position sizing recommendations
    /// </summary>
    public bool UseKellyCriterion { get; set; } = true;

    /// <summary>
    /// Trading balance used for utility calculations (from TradingBotConfig.BotTradingBalance)
    /// Represents the actual capital allocated to this trading bot
    /// </summary>
    public decimal TradingBalance { get; private set; } = 10000m;

    /// <summary>
    /// Risk aversion parameter used for utility calculations (configured from RiskManagement)
    /// </summary>
    public decimal ConfiguredRiskAversion { get; private set; } = 1.0m;

    /// <summary>
    /// Calculates Expected Monetary Value and Expected Utility using configured risk parameters
    /// </summary>
    /// <param name="tradingBalance">Actual trading balance allocated to the bot</param>
    /// <param name="riskConfig">Complete risk management configuration</param>
    public void CalculateExpectedMetrics(decimal tradingBalance, RiskManagement riskConfig)
    {
        // Store configured values for reference
        TradingBalance = tradingBalance;
        ConfiguredRiskAversion = riskConfig.RiskAversion;

        // Calculate Expected Monetary Value
        // EMV = (TP_Gain * TP_Prob) - (SL_Loss * SL_Prob)
        ExpectedMonetaryValue = (TakeProfitGain * TakeProfitProbability) - (StopLossLoss * StopLossProbability);

        // Calculate Expected Utility using logarithmic utility function
        // This accounts for diminishing marginal utility and risk aversion
        ExpectedUtility = CalculateLogarithmicExpectedUtility();

        // Calculate utility-to-risk ratio for ranking opportunities
        var totalRisk = StopLossLoss > 0 ? StopLossLoss : 1m; // Avoid division by zero
        UtilityRiskRatio = ExpectedUtility / totalRisk;

        // Calculate Kelly Criterion for optimal position sizing using full risk config
        CalculateKellyCriterion(riskConfig);
    }

    /// <summary>
    /// Calculates Expected Utility using logarithmic utility function
    /// U(x) = ln(tradingBalance + x) for gains, ln(tradingBalance - x) for losses
    /// Uses the actual trading balance and configured risk aversion
    /// </summary>
    /// <returns>Expected utility value</returns>
    private decimal CalculateLogarithmicExpectedUtility()
    {
        try
        {
            // Use actual trading balance and configured risk aversion
            var baseCapital = TradingBalance > 0 ? TradingBalance : 10000m;
            var riskAversion = ConfiguredRiskAversion > 0 ? ConfiguredRiskAversion : 1.0m;

            // Calculate utility of TP outcome: U(tradingBalance + gain)
            var tpOutcome = baseCapital + TakeProfitGain;
            var tpUtility = tpOutcome > 0 ? (decimal)Math.Log((double)tpOutcome) / riskAversion : decimal.MinValue;

            // Calculate utility of SL outcome: U(tradingBalance - loss)  
            var slOutcome = baseCapital - StopLossLoss;
            var slUtility = slOutcome > 0 ? (decimal)Math.Log((double)slOutcome) / riskAversion : decimal.MinValue;

            // Calculate utility of no-change outcome (neither TP nor SL hit)
            var noChangeProb = Math.Max(0m, 1m - TakeProfitProbability - StopLossProbability);
            var noChangeUtility = (decimal)Math.Log((double)baseCapital) / riskAversion;

            // Expected Utility = Sum of (Utility * Probability) for all outcomes
            var expectedUtility = (tpUtility * TakeProfitProbability) + 
                                 (slUtility * StopLossProbability) + 
                                 (noChangeUtility * noChangeProb);

            return expectedUtility;
        }
        catch (Exception)
        {
            // Return conservative utility value on calculation errors
            return decimal.MinValue;
        }
    }

    /// <summary>
    /// Calculates Kelly Criterion for optimal position sizing
    /// Kelly Formula: f* = (bp - q) / b
    /// Where: b = payoff ratio (win/loss), p = win probability, q = loss probability
    /// </summary>
    /// <param name="riskConfig">Complete risk management configuration</param>
    private void CalculateKellyCriterion(RiskManagement riskConfig)
    {
        try
        {
            // Calculate Win/Loss Ratio (b in Kelly formula)
            WinLossRatio = StopLossLoss > 0 ? TakeProfitGain / StopLossLoss : 0m;

            // Handle edge cases
            if (WinLossRatio <= 0 || TakeProfitProbability <= 0)
            {
                KellyFraction = 0m;
                KellyCappedFraction = 0m;
                KellyAssessment = "No Position - Unfavorable risk/reward ratio";
                return;
            }

            // Kelly Formula: f* = (bp - q) / b
            // Where:
            // b = WinLossRatio (TakeProfitGain / StopLossLoss)
            // p = TakeProfitProbability 
            // q = StopLossProbability
            var numerator = (WinLossRatio * TakeProfitProbability) - StopLossProbability;
            var kellyFraction = numerator / WinLossRatio;

            // Ensure Kelly fraction is not negative (would indicate unfavorable bet)
            KellyFraction = Math.Max(0m, kellyFraction);

            // Apply fractional Kelly multiplier
            KellyFraction *= riskConfig.KellyFractionalMultiplier;

            // Apply practical cap for risk management
            KellyCappedFraction = Math.Min(KellyFraction, riskConfig.KellyMaximumCap);

            // Generate Kelly assessment using the configured threshold
            KellyAssessment = GenerateKellyAssessment(riskConfig);
        }
        catch (Exception)
        {
            // Safe defaults on calculation errors
            KellyFraction = 0m;
            KellyCappedFraction = 0m;
            WinLossRatio = 0m;
            KellyAssessment = "Calculation Error - No position recommended";
        }
    }

    /// <summary>
    /// Generates a descriptive assessment of the Kelly Criterion result
    /// </summary>
    /// <param name="riskConfig">Risk management configuration containing Kelly thresholds</param>
    /// <returns>Human-readable Kelly assessment</returns>
    private string GenerateKellyAssessment(RiskManagement riskConfig)
    {
        if (KellyFraction <= 0)
            return "No Position - Negative or zero Kelly fraction";

        if (KellyFraction < riskConfig.KellyMinimumThreshold)
            return $"Below Threshold - Kelly {KellyFraction:P2} < {riskConfig.KellyMinimumThreshold:P2} minimum";

        if (KellyFraction < 0.05m) // 1-5%
            return "Small Position - Low but positive edge";

        if (KellyFraction < 0.10m) // 5-10%
            return "Moderate Position - Reasonable edge";

        if (KellyFraction < 0.25m) // 10-25%
            return "Large Position - Strong edge detected";

        if (KellyFraction < 0.50m) // 25-50%
            return "Very Large Position - Exceptional edge (CAPPED for safety)";

        // Above 50%
        return "Extreme Position - Extraordinary edge (HEAVILY CAPPED for safety)";
    }

    /// <summary>
    /// Gets detailed Kelly Criterion analysis including fractional betting recommendations
    /// </summary>
    /// <param name="totalCapital">Total available capital for position sizing</param>
    /// <returns>Detailed Kelly analysis with dollar amounts</returns>
    public string GetDetailedKellyAnalysis(decimal totalCapital = 100000m)
    {
        var recommendedAmount = KellyCappedFraction * totalCapital;
        var uncappedAmount = KellyFraction * totalCapital;

        var analysis = $"Kelly Analysis:\n" +
                      $"• Win/Loss Ratio: {WinLossRatio:F2}:1\n" +
                      $"• Optimal Kelly %: {KellyFraction:P2}\n" +
                      $"• Capped Kelly %: {KellyCappedFraction:P2}\n" +
                      $"• Recommended Amount: ${recommendedAmount:N0}\n";

        if (KellyFraction > KellyCappedFraction)
        {
            analysis += $"• Uncapped Amount: ${uncappedAmount:N0} (RISK WARNING)\n";
        }

        analysis += $"• Assessment: {KellyAssessment}";

        return analysis;
    }

    /// <summary>
    /// Calculates fractional Kelly betting for more conservative position sizing
    /// </summary>
    /// <param name="fraction">Fraction of Kelly to use (e.g., 0.5 for half-Kelly)</param>
    /// <returns>Fractional Kelly allocation percentage</returns>
    public decimal GetFractionalKelly(decimal fraction = 0.5m)
    {
        if (fraction < 0 || fraction > 1) fraction = 0.5m; // Default to half-Kelly
        return KellyFraction * fraction;
    }

    /// <summary>
    /// Validates if the Kelly Criterion suggests this is a profitable opportunity
    /// </summary>
    /// <param name="riskConfig">Risk management configuration containing Kelly thresholds</param>
    /// <returns>True if Kelly fraction is above the configured threshold</returns>
    public bool IsKellyFavorable(RiskManagement riskConfig)
    {
        return KellyFraction > riskConfig.KellyMinimumThreshold;
    }

    /// <summary>
    /// Alternative utility calculation using square root utility (less risk-averse than logarithmic)
    /// Uses the actual trading balance from the bot configuration
    /// </summary>
    /// <returns>Expected utility using square root function</returns>
    public decimal CalculateSquareRootExpectedUtility()
    {
        try
        {
            var baseCapital = TradingBalance > 0 ? TradingBalance : 10000m;

            // Square root utility: U(x) = sqrt(x)
            var tpOutcome = baseCapital + TakeProfitGain;
            var tpUtility = tpOutcome > 0 ? (decimal)Math.Sqrt((double)tpOutcome) : 0m;

            var slOutcome = Math.Max(0m, baseCapital - StopLossLoss);
            var slUtility = (decimal)Math.Sqrt((double)slOutcome);

            var noChangeProb = Math.Max(0m, 1m - TakeProfitProbability - StopLossProbability);
            var noChangeUtility = (decimal)Math.Sqrt((double)baseCapital);

            return (tpUtility * TakeProfitProbability) + 
                   (slUtility * StopLossProbability) + 
                   (noChangeUtility * noChangeProb);
        }
        catch (Exception)
        {
            return 0m;
        }
    }

    /// <summary>
    /// Gets a risk assessment based on Expected Utility Theory
    /// </summary>
    /// <returns>Descriptive risk assessment</returns>
    public string GetUtilityRiskAssessment()
    {
        if (ExpectedMonetaryValue > 0 && ExpectedUtility > 0)
            return "Favorable - Positive expected value and utility";
        
        if (ExpectedMonetaryValue > 0 && ExpectedUtility <= 0)
            return "Cautious - Positive expected value but negative risk-adjusted utility";
        
        if (ExpectedMonetaryValue <= 0 && ExpectedUtility > 0)
            return "Risk-Seeking - Negative expected value but positive utility (unusual)";
        
        return "Unfavorable - Negative expected value and utility";
    }

    /// <summary>
    /// Creates a result indicating Synth is disabled
    /// </summary>
    public static SignalValidationResult CreateDisabledResult(Confidence originalConfidence)
    {
        return new SignalValidationResult
        {
            Confidence = originalConfidence,
            IsBlocked = false,
            ValidationContext = "Synth API disabled"
        };
    }

    /// <summary>
    /// Creates a result for error scenarios
    /// </summary>
    public static SignalValidationResult CreateErrorResult(Confidence fallbackConfidence, string errorContext)
    {
        return new SignalValidationResult
        {
            Confidence = fallbackConfidence,
            IsBlocked = false,
            ValidationContext = $"Error in validation: {errorContext}"
        };
    }
} 