namespace KArtSell.Modules.ModelOperations.Domain;

/// <summary>
/// VS-08 DOMAIN: Dashboard aggregation policy
/// Pure business logic for combining portfolio, risk metrics, stress, alerts into unified snapshot
/// No I/O; time-dependent values are supplied by callers.
/// </summary>

// Note: This policy combines results from VS-04~07 components
// VS-08 uses simplified aggregation types (not the complex Domain entities)

public sealed record Portfolio(
    decimal TotalValue,
    List<PortfolioPosition> Positions);

public sealed record PortfolioPosition(
    string Symbol,
    decimal Quantity,
    decimal MarketPrice,
    decimal MarketValue,
    decimal WeightPercent);

public sealed record RiskMetricsSnapshot(
    decimal VAR95,
    decimal SharpeRatio,
    decimal SortinoRatio,
    decimal VolatilityPercent,
    decimal TopFivePercent,
    decimal MaxPositionPercent);

// Simplified stress scenario for dashboard display
public sealed record SimpleStressResult(
    string Scenario,
    decimal PortfolioLossPercent,
    decimal StressedVAR);

public sealed record ActiveAlert(
    Guid AlertId,
    string Threshold,
    decimal CurrentValue,
    string Severity,
    string Message);

public static class DashboardPolicy
{
    /// <summary>
    /// Aggregate portfolio positions into single view
    /// Calculates total value and weight percentages
    /// </summary>
    public static Portfolio AggregatePortfolio(List<PortfolioPosition> positions)
    {
        if (positions.Count == 0)
            return new Portfolio(0, new());

        var totalValue = positions.Sum(p => p.MarketValue);

        var weightsWithTotal = positions.Select(p => new PortfolioPosition(
            p.Symbol,
            p.Quantity,
            p.MarketPrice,
            p.MarketValue,
            totalValue > 0 ? (p.MarketValue / totalValue) * 100 : 0
        )).ToList();

        return new Portfolio(totalValue, weightsWithTotal);
    }

    /// <summary>
    /// Validate dashboard data quality
    /// Ensures totals and percentages are consistent
    /// </summary>
    public static (bool IsValid, List<string> Issues) ValidateDashboardData(
        Portfolio portfolio,
        RiskMetricsSnapshot riskMetrics,
        List<SimpleStressResult> stressResults,
        List<ActiveAlert> alerts)
    {
        var issues = new List<string>();

        // Portfolio validation
        if (portfolio.TotalValue < 0)
            issues.Add("Portfolio total value cannot be negative");

        if (portfolio.Positions.Count > 0)
        {
            var totalWeight = portfolio.Positions.Sum(p => p.WeightPercent);
            if (Math.Abs(totalWeight - 100) > 0.1m)
                issues.Add($"Portfolio weights must sum to 100% (actual: {totalWeight:F2}%)");
        }

        // Risk metrics validation
        if (riskMetrics.VAR95 < 0)
            issues.Add("VAR95 cannot be negative");

        if (riskMetrics.VolatilityPercent < 0)
            issues.Add("Volatility cannot be negative");

        if (riskMetrics.TopFivePercent < 0 || riskMetrics.TopFivePercent > 100)
            issues.Add("Top-5% concentration must be between 0-100");

        // Stress results validation
        foreach (var stress in stressResults)
        {
            if (!IsValidScenarioName(stress.Scenario))
                issues.Add($"Invalid scenario name: {stress.Scenario}");

            if (stress.StressedVAR < 0)
                issues.Add($"Stressed VAR for {stress.Scenario} cannot be negative");
        }

        return (issues.Count == 0, issues);
    }

    /// <summary>
    /// Calculate health score (0-100) based on risk metrics and alerts
    /// Higher score = healthier portfolio
    /// </summary>
    public static int CalculateHealthScore(
        RiskMetricsSnapshot riskMetrics,
        List<ActiveAlert> alerts)
    {
        var score = 100;

        // Deduct for concentration risk
        if (riskMetrics.TopFivePercent > 70)
            score -= 20;
        else if (riskMetrics.TopFivePercent > 50)
            score -= 10;

        // Deduct for volatility
        if (riskMetrics.VolatilityPercent > 25)
            score -= 15;
        else if (riskMetrics.VolatilityPercent > 15)
            score -= 5;

        // Deduct for active alerts
        var criticalAlerts = alerts.Count(a => a.Severity == "Critical");
        var warningAlerts = alerts.Count(a => a.Severity == "Warning");

        score -= criticalAlerts * 15;
        score -= warningAlerts * 5;

        return Math.Max(0, Math.Min(100, score));
    }

    /// <summary>
    /// Summarize key risk insights for display
    /// Returns human-readable summary of portfolio state
    /// </summary>
    public static List<string> SummarizeRiskInsights(
        RiskMetricsSnapshot riskMetrics,
        List<SimpleStressResult> stressResults,
        List<ActiveAlert> alerts)
    {
        var insights = new List<string>();

        // Concentration insight
        if (riskMetrics.TopFivePercent > 60)
            insights.Add($"High concentration risk: Top 5 holdings at {riskMetrics.TopFivePercent:F1}%");

        // Volatility insight
        if (riskMetrics.VolatilityPercent > 20)
            insights.Add($"Elevated volatility: {riskMetrics.VolatilityPercent:F1}% annualized");
        else if (riskMetrics.VolatilityPercent < 8)
            insights.Add($"Low volatility: {riskMetrics.VolatilityPercent:F1}% annualized");

        // Sharpe ratio insight
        if (riskMetrics.SharpeRatio < 0.5m)
            insights.Add("Low risk-adjusted returns (Sharpe < 0.5)");
        else if (riskMetrics.SharpeRatio > 2.0m)
            insights.Add("Excellent risk-adjusted returns (Sharpe > 2.0)");

        // Stress scenario insight
        var worstStress = stressResults.OrderBy(s => s.PortfolioLossPercent).FirstOrDefault();
        if (worstStress != null && worstStress.PortfolioLossPercent < -15)
            insights.Add($"Significant downside risk: {worstStress.Scenario} scenario = {worstStress.PortfolioLossPercent:F1}% loss");

        // Alert insight
        if (alerts.Any(a => a.Severity == "Critical"))
            insights.Add("⚠️ Critical alerts require immediate attention");

        if (insights.Count == 0)
            insights.Add("Portfolio is within safe parameters — no major risks detected");

        return insights;
    }

    /// <summary>
    /// Determine if stress scenario result is "severe" (>15% portfolio loss)
    /// </summary>
    public static bool IsStressSevere(SimpleStressResult stress)
        => stress.PortfolioLossPercent < -15;

    /// <summary>
    /// Rank alerts by severity (Critical > Warning > Initial)
    /// </summary>
    public static List<ActiveAlert> RankAlertsBySeverity(List<ActiveAlert> alerts)
    {
        var severityOrder = new Dictionary<string, int>
        {
            ["Critical"] = 3,
            ["Warning"] = 2,
            ["Initial"] = 1,
        };

        return alerts
            .OrderByDescending(a => severityOrder.GetValueOrDefault(a.Severity, 0))
            .ToList();
    }

    private static bool IsValidScenarioName(string name)
        => name is "bull" or "bear" or "rateShock" or "volSpike";
}
