using Managing.Core.FixedSizedQueue;
using Managing.Domain.Candles;
using Managing.Domain.Strategies;
using Managing.Domain.Strategies.Context;
using Managing.Domain.Strategies.Signals;
using Managing.Domain.Strategies.Trends;
using static Managing.Common.Enums;

namespace Managing.Domain.Scenarios;

public static class ScenarioHelpers
{
    public static IEnumerable<IStrategy> GetStrategiesFromScenario(Scenario scenario)
    {
        var strategies = new List<IStrategy>();
        foreach (var strategy in scenario.Strategies)
        {
            var result = BuildStrategy(strategy);
            strategies.Add(result);
        }

        return strategies;
    }

    public static IStrategy BuildStrategy(Strategy strategy, int size = 600)
    {
        IStrategy result = strategy.Type switch
        {
            StrategyType.StDev => new StDevContext(strategy.Name, strategy.Period.Value),
            StrategyType.RsiDivergence => new RsiDivergenceStrategy(strategy.Name,
                strategy.Period.Value),
            StrategyType.RsiDivergenceConfirm => new RsiDivergenceConfirmStrategy(strategy.Name,
                strategy.Period.Value),
            StrategyType.MacdCross => new MacdCrossStrategy(strategy.Name,
                strategy.FastPeriods.Value, strategy.SlowPeriods.Value, strategy.SignalPeriods.Value),
            StrategyType.EmaCross => new EmaCrossStrategy(strategy.Name, strategy.Period.Value),
            StrategyType.DualEmaCross => new DualEmaCrossStrategy(strategy.Name,
                strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
            StrategyType.ThreeWhiteSoldiers => new ThreeWhiteSoldiersStrategy(strategy.Name,
                strategy.Period.Value),
            StrategyType.SuperTrend => new SuperTrendStrategy(strategy.Name,
                strategy.Period.Value, strategy.Multiplier.Value),
            StrategyType.ChandelierExit => new ChandelierExitStrategy(strategy.Name,
                strategy.Period.Value, strategy.Multiplier.Value),
            StrategyType.EmaTrend => new EmaTrendStrategy(strategy.Name, strategy.Period.Value),
            StrategyType.StochRsiTrend => new StochRsiTrendStrategy(strategy.Name,
                strategy.Period.Value, strategy.StochPeriods.Value, strategy.SignalPeriods.Value,
                strategy.SmoothPeriods.Value),
            StrategyType.Stc => new StcStrategy(strategy.Name, strategy.CyclePeriods.Value,
                strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
            StrategyType.LaggingStc => new LaggingSTC(strategy.Name, strategy.CyclePeriods.Value,
                strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
            StrategyType.SuperTrendCrossEma => new SuperTrendCrossEma(strategy.Name,
                strategy.Period.Value, strategy.Multiplier.Value),
            _ => throw new NotImplementedException(),
        };

        result.Candles = new FixedSizeQueue<Candle>(size);
        return result;
    }

    public static Strategy BuildStrategy(
        StrategyType 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)
    {
        var strategy = new Strategy(name, type);

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

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

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

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

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

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

                break;
            default:
                break;
        }

        return strategy;
    }

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