using Managing.Application.Abstractions.Grains;
using Managing.Application.Abstractions.Services;
using Managing.Core;
using Managing.Domain.Bots;
using Managing.Domain.Candles;
using Managing.Domain.Indicators;
using Managing.Domain.Shared.Helpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Orleans.Concurrency;
using static Managing.Common.Enums;

namespace Managing.Application.Scenarios;

/// <summary>
/// Orleans grain for scenario execution and signal generation.
/// This stateless grain handles candle management and signal generation for live trading.
/// </summary>
[StatelessWorker]
public class ScenarioRunnerGrain : Grain, IScenarioRunnerGrain
{
    private readonly ILogger<ScenarioRunnerGrain> _logger;
    private readonly IServiceScopeFactory _scopeFactory;

    public ScenarioRunnerGrain(
        ILogger<ScenarioRunnerGrain> logger,
        IServiceScopeFactory scopeFactory)
    {
        _logger = logger;
        _scopeFactory = scopeFactory;
    }

    private async Task<HashSet<Candle>> GetCandlesAsync(TradingBotConfig config, DateTime startDate)
    {
        try
        {
            var newCandles = await ServiceScopeHelpers.WithScopedService<IExchangeService, HashSet<Candle>>(
                _scopeFactory, async exchangeService =>
                {
                    return await exchangeService.GetCandlesInflux(
                        TradingExchanges.Evm,
                        config.Ticker,
                        startDate,
                        config.Timeframe,
                        500);
                });

            _logger.LogInformation($"Updated {newCandles.Count} candles for {config.Ticker}");
            return newCandles;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update candles for {Ticker}", config.Ticker);
            throw;
        }
    }

    public async Task<LightSignal> GetSignals(TradingBotConfig config, Dictionary<string, LightSignal> previousSignals,
        DateTime startDate, Candle candle)
    {
        try
        {
            // return new LightSignal(config.Ticker, TradeDirection.Long, Confidence.High,
            //     candle, candle.Date, TradingExchanges.Evm, IndicatorType.Composite,
            //     SignalType.Signal, "Generated Signal");

            var candlesHashSet = await GetCandlesAsync(config, startDate);
            if (candlesHashSet.LastOrDefault()!.Date <= candle.Date)
            {
                return null; // No new candles, no need to generate a signal
            }

            var signal = TradingBox.GetSignal(
                candlesHashSet,
                config.Scenario,
                previousSignals,
                config.Scenario?.LoopbackPeriod ?? 1);

            if (signal != null && signal.Date >= candle.Date)
            {
                _logger.LogInformation(
                    $"Generated signal for {config.Ticker}: {signal.Direction} with confidence {signal.Confidence}");

                return new LightSignal(signal.Ticker, signal.Direction, Confidence.High,
                    candle, candle.Date, signal.Exchange, signal.IndicatorType,
                    signal.SignalType, signal.IndicatorName);
            }
            else
            {
                return null; // No signal generated
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update signals for {Ticker}", config.Ticker);
            throw;
        }
    }
}