using Discord;
using Discord.Commands;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Trading.Commands;
using Managing.Common;
using Managing.Core;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Trades;
using Managing.Domain.Users;
using static Managing.Common.Enums;

namespace Managing.Infrastructure.Messengers.Discord
{
    public class DiscordCommands : ModuleBase
    {
        private readonly DiscordSettings _settings;
        private readonly IBacktester _backtester;
        private readonly string[] _separator = new[] { " " };
        private readonly string _messagePrefix = "Bro, ";
        private readonly ICommandHandler<OpenPositionRequest, Position> _openTradeCommandHandler;

        public DiscordCommands(DiscordSettings settings,
            IBacktester backtester,
            ICommandHandler<OpenPositionRequest, Position> openTradeCommandHandler)
        {
            _settings = settings;
            _backtester = backtester;
            _openTradeCommandHandler = openTradeCommandHandler;
        }


        [Command("openposition")]
        public async Task OpenPosition([Remainder] string rest)
        {
            Typing();

            var parameters = rest.Split(_separator, StringSplitOptions.None);

            var exchange = MiscExtensions.ParseEnum<TradingExchanges>(parameters[0]);
            var ticker = parameters[1];
            var direction = MiscExtensions.ParseEnum<TradeDirection>(parameters[2]);
            var timeframe = MiscExtensions.ParseEnum<Timeframe>(parameters[3]);
            var expirationDate = DateTime.Now.AddMinutes(_settings.ButtonExpirationMinutes).ToString("G");

            var builder = new ComponentBuilder().WithButton("Open Position",
                $"{Constants.DiscordButtonAction.OpenPosition}-{exchange}-{ticker}-{direction}-{timeframe}-{expirationDate}");
            await Context.Channel.SendMessageAsync(
                _messagePrefix + $"you can now click on this button to open a position on {ticker}"
                , components: builder.Build());
        }

        [Command("open")]
        public async Task Open([Remainder] string rest)
        {
            await Context.Channel.SendMessageAsync("Let met few seconds to open a position");

            Typing();
            try
            {
                var parameters = rest.Split(_separator, StringSplitOptions.None);
                var accountName = parameters[0];
                var ticker = MiscExtensions.ParseEnum<Ticker>(parameters[1]);
                var direction = MiscExtensions.ParseEnum<TradeDirection>(parameters[2]);
                var riskLevel = MiscExtensions.ParseEnum<RiskLevel>(parameters[3]);
                var timeframe = MiscExtensions.ParseEnum<Timeframe>(parameters[4]);
                decimal? stopLoss = parameters[5] != null ? Convert.ToDecimal(parameters[5]) : null;
                decimal? takeProfit = parameters[6] != null ? Convert.ToDecimal(parameters[6]) : null;

                var moneymanagement = new MoneyManagement
                {
                    StopLoss = stopLoss.GetValueOrDefault(),
                    TakeProfit = takeProfit.GetValueOrDefault(),
                };
                var tradeCommand = new OpenPositionRequest(accountName, moneymanagement, direction, ticker,
                    PositionInitiator.User, DateTime.UtcNow, new User(), 100m);
                var result = await _openTradeCommandHandler.Handle(tradeCommand);
                var builder = new ComponentBuilder().WithButton("Close Position",
                    $"{Constants.DiscordButtonAction.ClosePosition}|{result.Open.ExchangeOrderId}");
                await Context.Channel.SendMessageAsync(MessengerHelpers.GetPositionMessage(result),
                    components: builder.Build());
            }
            catch (Exception ex)
            {
                await Context.Channel.SendMessageAsync($"Something weird happen bro, {ex.Message}");
            }
        }

        [Command("bot")]
        public async Task Bot([Remainder] string rest)
        {
            Typing();

            if (string.Equals(rest, "enable", StringComparison.OrdinalIgnoreCase))
            {
                _settings.BotEnabled = true;
            }

            if (string.Equals(rest, "disable", StringComparison.OrdinalIgnoreCase))
            {
                _settings.BotEnabled = false;
            }

            await Context.Channel.SendMessageAsync("Bot is "
                                                   + (_settings.BotEnabled ? "enabled" : "disabled"));
        }

        //[Command("backtest")]
        //public async Task Backtest([Remainder] string rest)
        //{
        //    Typing();

        //    var parameters = rest.Split(_separator, StringSplitOptions.None);
        //    var ticker = MiscExtensions.ParseEnum<Ticker>(parameters[0]);
        //    var exchange = MiscExtensions.ParseEnum<TradingExchanges>(parameters[1]);
        //    var timeframe = MiscExtensions.ParseEnum<Timeframe>(parameters[2]);
        //    var days = parameters[3];
        //    var scenario = new Scenario("ScalpingScenario");
        //    var strategy = ScenarioHelpers.BuildStrategy(StrategyType.RsiDivergence, timeframe, "RsiDiv", period: 14);
        //    scenario.AddStrategy(strategy);
        //    var account = new Account() { Exchange = exchange };

        //    var backtestResult = _backtester.RunScalpingBotBacktest(account, ticker, scenario, timeframe, Convert.ToDouble(days), 1000);
        //    await Context.Channel.SendMessageAsync(backtestResult.GetStringReport());
        //}

        [Command("run")]
        public async Task Run([Remainder] string rest)
        {
            Typing();
            var parameters = rest.Split(_separator, StringSplitOptions.None);
            var botType = MiscExtensions.ParseEnum<BotType>(parameters[0]);
            var accountName = MiscExtensions.ParseEnum<string>(parameters[1]);
            var botName = parameters[2];
            var ticker = MiscExtensions.ParseEnum<Ticker>(parameters[3]);
            var timeframe = MiscExtensions.ParseEnum<Timeframe>(parameters[4]);

            var message = _messagePrefix;

            // TODO : Fix remove mediator
            //var result = await _mediator.Send(new StartBotCommand(botType,
            //    botName,
            //    ticker,
            //    "scenario",
            //    timeframe,
            //    accountName,
            //    true));

            var result = "down";
            message += $"I tried to start the bot called {botName}, his status is now {result}. ";

            if (result == "Up")
            {
                await Context.Message.AddReactionAsync(new Emoji("👌"));
                message += $"this bot gonna watch {ticker} on {timeframe} timeframe.";
            }
            else
            {
                await Context.Message.AddReactionAsync(new Emoji("😒"));
                message += $"something wrong happen, the bot status is down";
            }

            await Context.Channel.SendMessageAsync(message);
        }

        [Command("stop")]
        public async Task Stop([Remainder] string rest)
        {
            Typing();
            var parameters = rest.Split(_separator, StringSplitOptions.None);
            var botType = MiscExtensions.ParseEnum<BotType>(parameters[0]);
            var botName = parameters[1];
            var result = "down";
            //var result = await _mediator.Send(new StopBotCommand(botType, botName));

            await Context.Channel.SendMessageAsync(_messagePrefix + $"the {botType} called {botName} is now {result}");
        }

        [Command("hi")]
        public async Task Hi([Remainder] string rest)
        {
            Typing();
            await Context.Channel.SendMessageAsync("I don't understand yet : " + rest);
        }

        [Command("help")]
        public async Task Help([Remainder] string rest)
        {
            Typing();

            var message = _messagePrefix;
            switch (rest)
            {
                case "backtest":
                    message +=
                        "to run a backtest you should use this pattern : !trader backtest ticker exchange timeframe startFromDays";
                    break;
                case "run":
                    message +=
                        "to run a bot you should use this pattern : !trader run botType botName ticker timeframe";
                    break;
                case "stop":
                    message += "to stop a bot you should use this pattern : !trader stop botType botName";
                    break;
                case "botType":
                    message += $"the bot type available are : {BotType.FlippingBot}, {BotType.ScalpingBot}";
                    break;
                case "timeframe":
                    message += $"the bot can currently handle only those timeframes : " +
                               $"{Timeframe.FifteenMinutes}, {Timeframe.ThirtyMinutes}, {Timeframe.OneDay}";
                    break;
                case "risklevel":
                    message += $"the bot can currently handle only those riskLevel : " +
                               $"{RiskLevel.High}";
                    break;
                default:
                    message += "I don't no the command";
                    break;
            }

            await Context.Channel.SendMessageAsync(message);
        }

        private async void Typing()
        {
            await Context.Channel.TriggerTypingAsync();
        }
    }
}