using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.ManageBot.Commands;
using Managing.Common;
using Managing.Domain.Bots;
using MediatR;
using static Managing.Common.Enums;

namespace Managing.Application.ManageBot
{
    public class StartBotCommandHandler : IRequestHandler<StartBotCommand, string>
    {
        private readonly IBotFactory _botFactory;
        private readonly IBotService _botService;
        private readonly IMoneyManagementService _moneyManagementService;
        private readonly IExchangeService _exchangeService;
        private readonly IAccountService _accountService;

        public StartBotCommandHandler(IBotFactory botFactory, IBotService botService,
            IMoneyManagementService moneyManagementService, IExchangeService exchangeService,
            IAccountService accountService)
        {
            _botFactory = botFactory;
            _botService = botService;
            _moneyManagementService = moneyManagementService;
            _exchangeService = exchangeService;
            _accountService = accountService;
        }

        public async Task<string> Handle(StartBotCommand request, CancellationToken cancellationToken)
        {
            BotStatus botStatus = BotStatus.Down;

            // Validate the configuration
            if (request.Config == null)
            {
                throw new ArgumentException("Bot configuration is required");
            }

            if (request.Config.BotTradingBalance <= Constants.GMX.Config.MinimumPositionAmount)
            {
                throw new ArgumentException(
                    $"Bot trading balance must be greater than {Constants.GMX.Config.MinimumPositionAmount}");
            }

            var account = await _accountService.GetAccount(request.Config.AccountName, true, true);

            if (account == null)
            {
                throw new Exception($"Account {request.Config.AccountName} not found");
            }

            var usdcBalance = account.Balances.FirstOrDefault(b => b.TokenName == Ticker.USDC.ToString());

            if (usdcBalance == null || usdcBalance.Value < request.Config.BotTradingBalance)
            {
                throw new Exception($"Account {request.Config.AccountName} has no USDC balance or not enough balance");
            }

            // Ensure essential configuration values are properly set
            var configToUse = new TradingBotConfig
            {
                AccountName = request.Config.AccountName,
                MoneyManagement = request.Config.MoneyManagement,
                Ticker = request.Config.Ticker,
                ScenarioName = request.Config.ScenarioName,
                Timeframe = request.Config.Timeframe,
                IsForWatchingOnly = request.Config.IsForWatchingOnly,
                BotTradingBalance = request.Config.BotTradingBalance,
                BotType = request.Config.BotType,
                IsForBacktest = request.Config.IsForBacktest,
                CooldownPeriod = request.Config.CooldownPeriod > 0 ? request.Config.CooldownPeriod : 1, // Default to 1 if not set
                MaxLossStreak = request.Config.MaxLossStreak,
                MaxPositionTimeHours = request.Config.MaxPositionTimeHours, // Properly handle nullable value
                FlipOnlyWhenInProfit = request.Config.FlipOnlyWhenInProfit,
                FlipPosition = request.Config.BotType == BotType.FlippingBot, // Set FlipPosition based on BotType
                Name = request.Config.Name ?? request.Name,
                CloseEarlyWhenProfitable = request.Config.CloseEarlyWhenProfitable
            };

            switch (configToUse.BotType)
            {
                case BotType.SimpleBot:
                    var bot = _botFactory.CreateSimpleBot(request.Name, null);
                    bot.User = request.User;
                    _botService.AddSimpleBotToCache(bot);
                    return bot.GetStatus();
                    
                case BotType.ScalpingBot:
                case BotType.FlippingBot:
                    var tradingBot = _botFactory.CreateTradingBot(configToUse);
                    tradingBot.User = request.User;
                    
                    // Log the configuration being used
                    await LogBotConfigurationAsync(tradingBot, $"{configToUse.BotType} created");
                    
                    _botService.AddTradingBotToCache(tradingBot);
                    return tradingBot.GetStatus();
            }

            return botStatus.ToString();
        }

        /// <summary>
        /// Logs the bot configuration for debugging and audit purposes
        /// </summary>
        /// <param name="bot">The trading bot instance</param>
        /// <param name="context">Context information for the log</param>
        private async Task LogBotConfigurationAsync(ITradingBot bot, string context)
        {
            try
            {
                var config = bot.GetConfiguration();
                var logMessage = $"{context} - Bot: {config.Name}, " +
                               $"Type: {config.BotType}, " +
                               $"Account: {config.AccountName}, " +
                               $"Ticker: {config.Ticker}, " +
                               $"Balance: {config.BotTradingBalance}, " +
                               $"MaxTime: {config.MaxPositionTimeHours?.ToString() ?? "Disabled"}, " +
                               $"FlipOnlyProfit: {config.FlipOnlyWhenInProfit}, " +
                               $"FlipPosition: {config.FlipPosition}, " +
                               $"Cooldown: {config.CooldownPeriod}, " +
                               $"MaxLoss: {config.MaxLossStreak}";
                
                // Log through the bot's logger (this will use the bot's logging mechanism)
                // For now, we'll just add a comment that this could be enhanced with actual logging
                // Console.WriteLine(logMessage); // Could be replaced with proper logging
            }
            catch (Exception)
            {
                // Ignore logging errors to not affect bot creation
            }
        }
    }
}