using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Context;
using Managing.Domain.Strategies.Signals;
using Managing.Domain.Strategies.Trends;
using Newtonsoft.Json;
using static Managing.Common.Enums;

namespace Managing.Domain.Scenarios;

public static class ScenarioHelpers
{
    /// <summary>
    /// Compares two lists of indicators and returns a list of changes (added, removed, modified).
    /// </summary>
    /// <param name="oldIndicators">The previous list of indicators</param>
    /// <param name="newIndicators">The new list of indicators</param>
    /// <returns>A list of change descriptions</returns>
    public static List<string> CompareIndicators(List<LightIndicator> oldIndicators, List<LightIndicator> newIndicators)
    {
        var changes = new List<string>();

        // Create dictionaries for easier comparison using Type as key
        var oldIndicatorDict = oldIndicators.ToDictionary(i => i.Type, i => i);
        var newIndicatorDict = newIndicators.ToDictionary(i => i.Type, i => i);

        // Find removed indicators
        var removedTypes = oldIndicatorDict.Keys.Except(newIndicatorDict.Keys);
        foreach (var removedType in removedTypes)
        {
            var indicator = oldIndicatorDict[removedType];
            changes.Add($"➖ **Removed Indicator:** {removedType} ({indicator.GetType().Name})");
        }

        // Find added indicators
        var addedTypes = newIndicatorDict.Keys.Except(oldIndicatorDict.Keys);
        foreach (var addedType in addedTypes)
        {
            var indicator = newIndicatorDict[addedType];
            changes.Add($"➕ **Added Indicator:** {addedType} ({indicator.GetType().Name})");
        }

        // Find modified indicators (same type but potentially different configuration)
        var commonTypes = oldIndicatorDict.Keys.Intersect(newIndicatorDict.Keys);
        foreach (var commonType in commonTypes)
        {
            var oldIndicator = oldIndicatorDict[commonType];
            var newIndicator = newIndicatorDict[commonType];

            // Compare indicators by serializing them (simple way to detect configuration changes)
            var oldSerialized = JsonConvert.SerializeObject(oldIndicator, Formatting.None);
            var newSerialized = JsonConvert.SerializeObject(newIndicator, Formatting.None);

            if (oldSerialized != newSerialized)
            {
                changes.Add($"🔄 **Modified Indicator:** {commonType} ({newIndicator.GetType().Name})");
            }
        }

        // Add summary if there are changes
        if (changes.Any())
        {
            var summary =
                $"📊 **Indicator Changes:** {addedTypes.Count()} added, {removedTypes.Count()} removed, {commonTypes.Count(c => JsonConvert.SerializeObject(oldIndicatorDict[c]) != JsonConvert.SerializeObject(newIndicatorDict[c]))} modified";
            changes.Insert(0, summary);
        }

        return changes;
    }

    public static IIndicator BuildIndicator(LightIndicator indicator)
    {
        IIndicator result = indicator.Type switch
        {
            IndicatorType.StDev => new StDevContext(indicator.Name, indicator.Period.Value),
            IndicatorType.RsiDivergence => new RsiDivergenceIndicatorBase(indicator.Name,
                indicator.Period.Value),
            IndicatorType.RsiDivergenceConfirm => new RsiDivergenceConfirmIndicatorBase(indicator.Name,
                indicator.Period.Value),
            IndicatorType.MacdCross => new MacdCrossIndicatorBase(indicator.Name,
                indicator.FastPeriods.Value, indicator.SlowPeriods.Value, indicator.SignalPeriods.Value),
            IndicatorType.EmaCross => new EmaCrossIndicatorBase(indicator.Name, indicator.Period.Value),
            IndicatorType.DualEmaCross => new DualEmaCrossIndicatorBase(indicator.Name,
                indicator.FastPeriods.Value, indicator.SlowPeriods.Value),
            IndicatorType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersIndicatorBase(indicator.Name,
                indicator.Period.Value),
            IndicatorType.SuperTrend => new SuperTrendIndicatorBase(indicator.Name,
                indicator.Period.Value, indicator.Multiplier.Value),
            IndicatorType.ChandelierExit => new ChandelierExitIndicatorBase(indicator.Name,
                indicator.Period.Value, indicator.Multiplier.Value),
            IndicatorType.EmaTrend => new EmaTrendIndicatorBase(indicator.Name, indicator.Period.Value),
            IndicatorType.StochRsiTrend => new StochRsiTrendIndicatorBase(indicator.Name,
                indicator.Period.Value, indicator.StochPeriods.Value, indicator.SignalPeriods.Value,
                indicator.SmoothPeriods.Value),
            IndicatorType.Stc => new StcIndicatorBase(indicator.Name, indicator.CyclePeriods.Value,
                indicator.FastPeriods.Value, indicator.SlowPeriods.Value),
            IndicatorType.LaggingStc => new LaggingSTC(indicator.Name, indicator.CyclePeriods.Value,
                indicator.FastPeriods.Value, indicator.SlowPeriods.Value),
            IndicatorType.SuperTrendCrossEma => new SuperTrendCrossEma(indicator.Name,
                indicator.Period.Value, indicator.Multiplier.Value),
            _ => throw new NotImplementedException(),
        };

        return result;
    }

    public static IIndicator BuildIndicator(
        IndicatorType type,
        string name,
        int? period = null,
        int? fastPeriods = null,
        int? slowPeriods = null,
        int? signalPeriods = null,
        double? multiplier = null,
        int? stochPeriods = null,
        int? smoothPeriods = null,
        int? cyclePeriods = null)
    {
        IIndicator indicator = null;

        switch (type)
        {
            case IndicatorType.RsiDivergence:
            case IndicatorType.RsiDivergenceConfirm:
            case IndicatorType.EmaTrend:
            case IndicatorType.EmaCross:
            case IndicatorType.StDev:
                if (!period.HasValue)
                {
                    throw new Exception($"Missing period for {indicator.Type} strategy type");
                }
                else
                {
                    indicator.Period = period.Value;
                }

                break;
            case IndicatorType.MacdCross:
                if (!fastPeriods.HasValue || !slowPeriods.HasValue || !signalPeriods.HasValue)
                {
                    throw new Exception(
                        $"Missing fastPeriods or slowPeriods or signalPeriods, for {indicator.Type} strategy type");
                }
                else
                {
                    indicator.FastPeriods = fastPeriods;
                    indicator.SlowPeriods = slowPeriods;
                    indicator.SignalPeriods = signalPeriods;
                }

                break;
            case IndicatorType.DualEmaCross:
                if (!fastPeriods.HasValue || !slowPeriods.HasValue)
                {
                    throw new Exception(
                        $"Missing fastPeriods or slowPeriods for {indicator.Type} strategy type");
                }
                else
                {
                    indicator.FastPeriods = fastPeriods;
                    indicator.SlowPeriods = slowPeriods;
                }

                break;
            case IndicatorType.ThreeWhiteSoldiers:
                break;
            case IndicatorType.SuperTrend:
            case IndicatorType.SuperTrendCrossEma:
            case IndicatorType.ChandelierExit:
                if (!period.HasValue || !multiplier.HasValue)
                {
                    throw new Exception($"Missing period or multiplier, for {indicator.Type} strategy type");
                }
                else
                {
                    indicator.Period = period;
                    indicator.Multiplier = multiplier;
                }

                break;
            case IndicatorType.StochRsiTrend:
                if (!period.HasValue
                    || !stochPeriods.HasValue
                    || !signalPeriods.HasValue
                    || !smoothPeriods.HasValue)
                {
                    throw new Exception(
                        $"Missing period, stochPeriods, signalPeriods, smoothPeriods for {indicator.Type} strategy type");
                }
                else
                {
                    indicator.Period = period;
                    indicator.StochPeriods = stochPeriods;
                    indicator.SignalPeriods = signalPeriods;
                    indicator.SmoothPeriods = smoothPeriods;
                }

                break;
            case IndicatorType.Stc:
            case IndicatorType.LaggingStc:
                if (!fastPeriods.HasValue || !slowPeriods.HasValue || !cyclePeriods.HasValue)
                {
                    throw new Exception(
                        $"Missing fastPeriods or slowPeriods or cyclePeriods, for {indicator.Type} strategy type");
                }
                else
                {
                    indicator.FastPeriods = fastPeriods;
                    indicator.SlowPeriods = slowPeriods;
                    indicator.CyclePeriods = cyclePeriods;
                }

                break;
            default:
                break;
        }

        return indicator;
    }

    public static SignalType GetSignalType(IndicatorType type)
    {
        return type switch
        {
            IndicatorType.RsiDivergence => SignalType.Signal,
            IndicatorType.RsiDivergenceConfirm => SignalType.Signal,
            IndicatorType.MacdCross => SignalType.Signal,
            IndicatorType.EmaCross => SignalType.Signal,
            IndicatorType.DualEmaCross => SignalType.Signal,
            IndicatorType.ThreeWhiteSoldiers => SignalType.Signal,
            IndicatorType.SuperTrend => SignalType.Trend,
            IndicatorType.ChandelierExit => SignalType.Signal,
            IndicatorType.EmaTrend => SignalType.Trend,
            IndicatorType.Composite => SignalType.Signal,
            IndicatorType.StochRsiTrend => SignalType.Trend,
            IndicatorType.Stc => SignalType.Signal,
            IndicatorType.StDev => SignalType.Context,
            IndicatorType.LaggingStc => SignalType.Signal,
            IndicatorType.SuperTrendCrossEma => SignalType.Signal,
            _ => throw new NotImplementedException(),
        };
    }
}