using System;
using System.Collections.Generic;
using System.Linq;

namespace QuantEngine.Core.Domain;

public enum MarketRegimeType
{
    BULL_LOW_VOL = 1,
    BULL_HIGH_VOL = 2,
    BEAR_LOW_VOL = 3,
    BEAR_HIGH_VOL = 4,
    SIDEWAYS = 5
}

public record MarketRegimeResult(
    string AsOfDate,
    MarketRegimeType Regime,
    decimal Sma200,
    decimal CurrentIndexPrice,
    decimal Volatility20d,
    string Provenance
);

/// <summary>
/// Market Regime Detector
/// SOLID Principle: Evaluates macro/index trend & volatility for dynamic regime labeling.
/// </summary>
public class MarketRegimeDetector
{
    private const decimal HighVolThreshold = 0.20m; // 20% annualized volatility

    public MarketRegimeResult DetectRegime(string asOfDate, List<decimal> indexPrices)
    {
        if (indexPrices == null || indexPrices.Count < 20)
        {
            return new MarketRegimeResult(asOfDate, MarketRegimeType.SIDEWAYS, 0m, 0m, 0m, "DATA_INSUFFICIENT");
        }

        decimal currentPrice = indexPrices.Last();
        decimal sma200 = indexPrices.Count >= 200 ? indexPrices.TakeLast(200).Average() : indexPrices.Average();

        // Calculate 20-day annualized volatility
        var last20 = indexPrices.TakeLast(20).ToList();
        var dailyReturns = new List<decimal>();
        for (int i = 1; i < last20.Count; i++)
        {
            var prev = last20[i - 1];
            var curr = last20[i];
            dailyReturns.Add(prev > 0 ? (curr - prev) / prev : 0m);
        }

        var avgRet = dailyReturns.Average();
        var sumSq = dailyReturns.Sum(r => (r - avgRet) * (r - avgRet));
        var variance = dailyReturns.Count > 1 ? sumSq / (dailyReturns.Count - 1) : 0m;
        var dailyVol = (decimal)Math.Sqrt((double)variance);
        var annualizedVol = dailyVol * (decimal)Math.Sqrt(252);

        bool isBull = currentPrice >= sma200;
        bool isHighVol = annualizedVol >= HighVolThreshold;

        MarketRegimeType regime;
        if (isBull && !isHighVol) regime = MarketRegimeType.BULL_LOW_VOL;
        else if (isBull && isHighVol) regime = MarketRegimeType.BULL_HIGH_VOL;
        else if (!isBull && !isHighVol) regime = MarketRegimeType.BEAR_LOW_VOL;
        else regime = MarketRegimeType.BEAR_HIGH_VOL;

        return new MarketRegimeResult(
            asOfDate,
            regime,
            Math.Round(sma200, 4),
            Math.Round(currentPrice, 4),
            Math.Round(annualizedVol, 4),
            $"regime_detector_v1:{asOfDate}"
        );
    }
}
