using Managing.Application.Abstractions.Grains;
using Managing.Application.Abstractions.Services;
using Managing.Application.Orleans;
using Managing.Core;
using Managing.Domain.Accounts;
using Managing.Domain.Backtests;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Orleans.Concurrency;

namespace Managing.Application.Grains;

/// <summary>
/// Stateless worker grain for processing genetic backtest requests.
/// Uses the genetic request ID (string) as the primary key.
/// Uses custom compute placement with random fallback.
/// </summary>
[StatelessWorker]
[TradingPlacement] // Use custom compute placement with random fallback
public class GeneticBacktestGrain : Grain, IGeneticBacktestGrain
{
    private readonly ILogger<GeneticBacktestGrain> _logger;
    private readonly IServiceScopeFactory _scopeFactory;

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

    public async Task ProcessGeneticRequestAsync()
    {
        var requestId = this.GetPrimaryKeyString();

        try
        {
            using var scope = _scopeFactory.CreateScope();
            var geneticService = scope.ServiceProvider.GetRequiredService<IGeneticService>();

            // Load the request by status lists and filter by ID (Pending first, then Failed for retries)
            var pending = await geneticService.GetGeneticRequestsAsync(GeneticRequestStatus.Pending);
            var failed = await geneticService.GetGeneticRequestsAsync(GeneticRequestStatus.Failed);
            var request = pending.Concat(failed).FirstOrDefault(r => r.RequestId == requestId);

            if (request == null)
            {
                _logger.LogWarning("[GeneticBacktestGrain] Request {RequestId} not found among pending/failed.",
                    requestId);
                return;
            }

            // Mark running
            request.Status = GeneticRequestStatus.Running;
            await geneticService.UpdateGeneticRequestAsync(request);

            request.User.Accounts = await ServiceScopeHelpers.WithScopedService<IAccountService, List<Account>>(
                _scopeFactory,
                async accountService => (await accountService.GetAccountsByUserAsync(request.User)).ToList());

            // Run GA
            var result = await geneticService.RunGeneticAlgorithm(request, CancellationToken.None);

            // Update final state
            request.Status = GeneticRequestStatus.Completed;
            request.CompletedAt = DateTime.UtcNow;
            request.BestFitness = result.BestFitness;
            request.BestIndividual = result.BestIndividual;
            request.ProgressInfo = result.ProgressInfo;
            await geneticService.UpdateGeneticRequestAsync(request);

            _logger.LogInformation("[GeneticBacktestGrain] Completed request {RequestId}", requestId);
        }
        catch (Exception ex)
        {
            SentrySdk.CaptureException(ex);

            try
            {
                using var scope = _scopeFactory.CreateScope();
                var geneticService = scope.ServiceProvider.GetRequiredService<IGeneticService>();
                var running = await geneticService.GetGeneticRequestsAsync(GeneticRequestStatus.Running);
                var req = running.FirstOrDefault(r => r.RequestId == requestId) ?? new GeneticRequest(requestId);
                req.Status = GeneticRequestStatus.Failed;
                req.ErrorMessage = ex.Message;
                req.CompletedAt = DateTime.UtcNow;
                await geneticService.UpdateGeneticRequestAsync(req);
            }
            catch
            {
            }
        }
    }
}