using Managing.Application.Abstractions.Services;
using Managing.Common;
using Managing.Domain.Backtests;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Managing.Domain.Users;

namespace Managing.Application.Shared;

public class MessengerService : IMessengerService
{
    private readonly IDiscordService _discordService;
    private readonly IWebhookService _webhookService;
    private readonly IUserService _userService;

    public MessengerService(IDiscordService discordService, IWebhookService webhookService, IUserService userService)
    {
        _discordService = discordService;
        _webhookService = webhookService;
        _userService = userService;
    }

    public async Task SendClosedPosition(string address, Trade oldTrade)
    {
        await _discordService.SendClosedPosition(address, oldTrade);
    }

    public async Task SendClosingPosition(Position position)
    {
        await _discordService.SendClosingPosition(position);
    }

    public async Task SendIncreasePosition(string address, Trade trade, string copyAccountName, Trade? oldTrade = null)
    {
        await _discordService.SendIncreasePosition(address, trade, copyAccountName, oldTrade);
    }

    public async Task SendDecreasePosition(string address, Trade newTrade, decimal decreaseAmount)
    {
        await _discordService.SendDecreasePosition(address, newTrade, decreaseAmount);
    }

    public async Task SendMessage(string message)
    {
        await _discordService.SendMessage(message);
    }

    public async Task SendPosition(Position position)
    {
        // Send to Discord with try-catch to not block
        try
        {
            await _discordService.SendPosition(position);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

        // Send to webhook (n8n/telegram)
        try
        {
            var message = BuildPositionMessage(position);
            await _webhookService.SendMessage(message, position.User?.TelegramChannel);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

    public async Task SendMessage(string message, string telegramChannel)
    {
        await _webhookService.SendMessage(message, telegramChannel);
    }

    private string BuildPositionMessage(Position position)
    {
        var direction = position.OriginDirection.ToString();
        var status = position.Status.ToString();

        var message = $"🎯 Position {status}\n" +
                      $"Symbol: {position.Ticker}\n" +
                      $"Direction: {direction}\n" +
                      $"Account: {position.AccountName}\n" +
                      $"Identifier: {position.Identifier}\n" +
                      $"Initiator: {position.Initiator}\n" +
                      $"Date: {position.Date:yyyy-MM-dd HH:mm:ss}";

        if (position.Open != null)
        {
            message += $"\nOpen Trade: {position.Open.Quantity} @ {position.Open.Price:F4}";
        }

        if (position.ProfitAndLoss != null)
        {
            var pnlEmoji = position.ProfitAndLoss.Realized >= 0 ? "✅" : "❌";
            message += $"\nPnL: {pnlEmoji} ${position.ProfitAndLoss.Realized:F2}";
        }

        if (!string.IsNullOrEmpty(position.SignalIdentifier))
        {
            message += $"\nSignal: {position.SignalIdentifier}";
        }

        return message;
    }

    public async Task SendSignal(string message, Enums.TradingExchanges exchange, Enums.Ticker ticker,
        Enums.TradeDirection direction, Enums.Timeframe timeframe)
    {
        await _discordService.SendSignal(message, exchange, ticker, direction, timeframe);
    }

    public async Task SendTradeMessage(string message, bool isBadBehavior = false, User user = null)
    {
        // Always send to Discord
        try
        {
            await _discordService.SendTradeMessage(message, isBadBehavior);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

        // If user is provided, also send to webhook
        if (user != null)
        {
            await _webhookService.SendTradeNotification(user, message, isBadBehavior);
        }
    }

    public async Task SendBestTraders(List<Trader> traders)
    {
        await _discordService.SendBestTraders(traders);
    }

    public async Task SendBadTraders(List<Trader> traders)
    {
        await _discordService.SendBadTraders(traders);
    }

    public async Task SendDowngradedFundingRate(FundingRate oldRate)
    {
        await _discordService.SendDowngradedFundingRate(oldRate);
    }

    public async Task SendNewTopFundingRate(FundingRate newRate)
    {
        await _discordService.SendNewTopFundingRate(newRate);
    }

    public async Task SendFundingRateUpdate(FundingRate oldRate, FundingRate newRate)
    {
        await _discordService.SendFundingRateUpdate(oldRate, newRate);
    }

    public async Task SendBacktestNotification(Backtest backtest)
    {
        try
        {
            var message = BuildBacktestMessage(backtest);
            await _webhookService.SendMessage(message, "2775292276");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Failed to send backtest notification: {e.Message}");
        }
    }

    public async Task SendGeneticAlgorithmNotification(GeneticRequest request, double bestFitness,
        object? bestChromosome)
    {
        try
        {
            var message = BuildGeneticAlgorithmMessage(request, bestFitness, bestChromosome);
            await _webhookService.SendMessage(message, "2775292276");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Failed to send genetic algorithm notification: {e.Message}");
        }
    }

    private string BuildBacktestConfigMessage(Backtest backtest)
    {
        var config = backtest.Config;

        // Get indicators list as comma-separated string
        var indicators = config.Scenario?.Indicators != null && config.Scenario.Indicators.Any()
            ? string.Join(", ", config.Scenario.Indicators.Select(i => i.Type.ToString()))
            : "N/A";

        // MoneyManagement summary
        var mmSl = config.MoneyManagement != null ? (config.MoneyManagement.StopLoss * 100).ToString("F2") : "N/A";
        var mmTp = config.MoneyManagement != null ? (config.MoneyManagement.TakeProfit * 100).ToString("F2") : "N/A";
        var mmLev = config.MoneyManagement != null ? config.MoneyManagement.Leverage.ToString("F2") : "N/A";

        return $"🚀 Excellent Backtest Results! 🚀\n\n" +
               $"🔹 {config.Ticker} | ⏱️ {config.Timeframe}\n" +
               $"💰 {config.BotTradingBalance:C}\n" +
               $"🛡️ SL: {mmSl}% | 🎯 TP: {mmTp}% | 📈 Lev: {mmLev}x\n" +
               $"🧩 {indicators}\n" +
               $"📅 {backtest.StartDate:yyyy-MM-dd} to {backtest.EndDate:yyyy-MM-dd}";
    }

    private string BuildBacktestResultsMessage(Backtest backtest)
    {
        var config = backtest.Config;
        var score = backtest.Score;
        var winRate = backtest.WinRate;
        var tradeCount = backtest.Positions?.Count ?? 0;
        var finalPnl = backtest.FinalPnl;
        var growthPercentage = backtest.GrowthPercentage;
        var maxDrawdown = backtest.Statistics?.MaxDrawdownPc ?? 0;
        var sharpeRatio = (backtest.Statistics?.SharpeRatio * 100) ?? 0;

        return $"📈 Performance Metrics:\n" +
               $"⭐ Score: {score:F1}/100 | 🏆 Win Rate: {winRate:F1}%\n" +
               $"📊 Trades: {tradeCount} | 💰 PnL: ${finalPnl:F2}\n" +
               $"📈 Growth: {growthPercentage:F1}% | 📉 DD: {maxDrawdown:F1}%\n" +
               $"📊 Sharpe: {sharpeRatio:F2}\n\n" +
               $"🆔 ID: {backtest.Id}";
    }

    private string BuildBacktestMessage(Backtest backtest)
    {
        var config = backtest.Config;
        var score = backtest.Score;
        var winRate = backtest.WinRate;
        var tradeCount = backtest.Positions?.Count ?? 0;
        var finalPnl = backtest.FinalPnl;
        var growthPercentage = backtest.GrowthPercentage;
        var maxDrawdown = backtest.Statistics?.MaxDrawdown ?? 0;
        var sharpeRatio = (backtest.Statistics?.SharpeRatio * 100) ?? 0;

        // Get indicators list as comma-separated string
        var indicators = config.Scenario?.Indicators != null && config.Scenario.Indicators.Any()
            ? string.Join(", ", config.Scenario.Indicators.Select(i => i.Name ?? i.Type.ToString()))
            : "N/A";

        // MoneyManagement summary
        var mmSl = config.MoneyManagement != null ? (config.MoneyManagement.StopLoss * 100).ToString("F2") : "N/A";
        var mmTp = config.MoneyManagement != null ? (config.MoneyManagement.TakeProfit * 100).ToString("F2") : "N/A";
        var mmLev = config.MoneyManagement != null ? config.MoneyManagement.Leverage.ToString("F2") : "N/A";

        var message = $"🚀 Excellent Backtest Results! 🚀\n\n" +
                      $"🔹 Symbol: {config.Ticker} | " +
                      $"⏱️ Timeframe: {config.Timeframe}\n" +
                      $"👤 Account: {config.AccountName}\n" +
                      $"💼 MM: 🛡️ SL: {mmSl}% | 🎯 TP: {mmTp}% | 📈 Lev: {mmLev}x\n" +
                      $"💰 Balance: {config.BotTradingBalance:C}\n" +
                      $"🧩 Indicators: {indicators}\n" +
                      $"📅 Period: {backtest.StartDate:yyyy-MM-dd} to {backtest.EndDate:yyyy-MM-dd}\n" +
                      $"⏳ Cooldown: {config.CooldownPeriod} | 🔥 Max Loss Streak: {config.MaxLossStreak}\n" +
                      $"🔄 Flipping: {(config.FlipPosition ? "Yes" : "No")} | 🔒 Flip Only When In Profit: {(config.FlipOnlyWhenInProfit ? "Yes" : "No")}\n" +
                      $"{(config.MaxPositionTimeHours.HasValue && config.MaxPositionTimeHours.Value > 0 ? $"⏰ Max Position Time (hrs): {config.MaxPositionTimeHours.Value} | " : "")}🏁 Close Early When Profitable: {(config.CloseEarlyWhenProfitable ? "Yes" : "No")}\n" +
                      $"\n📈 Performance Metrics:\n" +
                      $"⭐ Score: {score:F1}/100\n" +
                      $"🔍 Score Analysis: {backtest.ScoreMessage}\n" +
                      $"🏆 Win Rate: {winRate:F1}%\n" +
                      $"📊 Total Trades: {tradeCount}\n" +
                      $"💰 Final PnL: ${finalPnl:F2}\n" +
                      $"📈 Growth: {growthPercentage:F1}%\n" +
                      $"📉 Max Drawdown: ${maxDrawdown:N}\n" +
                      $"📊 Sharpe Ratio: {sharpeRatio:F2}\n\n" +
                      $"🆔 Backtest ID: {backtest.Id}";

        return message;
    }

    private string BuildGeneticAlgorithmMessage(GeneticRequest request, double bestFitness, object? bestChromosome)
    {
        var duration = request.CompletedAt.HasValue
            ? request.CompletedAt.Value - request.CreatedAt
            : TimeSpan.Zero;

        var indicators = request.EligibleIndicators.Any()
            ? string.Join(", ", request.EligibleIndicators.Select(i => i.ToString()))
            : "N/A";

        if (request.EligibleIndicators.Count > 5)
        {
            indicators += $" (+{request.EligibleIndicators.Count - 5} more)";
        }

        var message = $"🧬 Genetic Algorithm Completed! 🧬\n\n" +
                      $"🔹 Symbol: {request.Ticker}\n" +
                      $"⏱️ Timeframe: {request.Timeframe}\n" +
                      $"👥 Population: {request.PopulationSize}\n" +
                      $"🔄 Generations: {request.Generations}\n" +
                      $"🎯 Selection: {request.SelectionMethod}\n" +
                      $"🔀 Crossover: {request.CrossoverMethod}\n" +
                      $"🧬 Mutation: {request.MutationMethod}\n" +
                      $"🧩 Indicators: {indicators}\n" +
                      $"📅 Period: {request.StartDate:yyyy-MM-dd} to {request.EndDate:yyyy-MM-dd}\n" +
                      $"📈 Results:\n" +
                      $"⭐ Best Fitness: {bestFitness:F4}\n" +
                      $"⏱️ Duration: {duration.TotalMinutes:F1} minutes\n" +
                      $"🆔 Request ID: {request.RequestId[..8]}...";

        if (request.BestFitnessSoFar.HasValue && request.BestFitnessSoFar.Value > 0)
        {
            message += $"\n🏆 Best Fitness So Far: {request.BestFitnessSoFar.Value:F4}";
        }

        return message;
    }
}