using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Grains;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;

namespace Managing.Application.Bots.Grains;

/// <summary>
/// Orleans grain for LiveBotRegistry operations.
/// This grain acts as a central, durable directory for all LiveTradingBot grains.
/// It maintains a persistent, up-to-date list of all known bot IDs and their status.
/// </summary>
public class LiveBotRegistryGrain : Grain, ILiveBotRegistryGrain
{
    private readonly IPersistentState<BotRegistryState> _state;
    private readonly ILogger<LiveBotRegistryGrain> _logger;
    private readonly IBotService _botService;

    public LiveBotRegistryGrain(
        [PersistentState("bot-registry", "registry-store")]
        IPersistentState<BotRegistryState> state,
        ILogger<LiveBotRegistryGrain> logger,
        IBotService botService)
    {
        _state = state;
        _logger = logger;
        _botService = botService;
    }

    public override async Task OnActivateAsync(CancellationToken cancellationToken)
    {
        await base.OnActivateAsync(cancellationToken);
        _logger.LogInformation("LiveBotRegistryGrain activated with {TotalBots} bots registered",
            _state.State.TotalBotsCount);
    }

    public override async Task OnDeactivateAsync(DeactivationReason reason, CancellationToken cancellationToken)
    {
        _logger.LogInformation("LiveBotRegistryGrain deactivating. Reason: {Reason}. Total bots: {TotalBots}",
            reason.Description, _state.State.TotalBotsCount);
        await base.OnDeactivateAsync(reason, cancellationToken);
    }

    public async Task RegisterBot(Guid identifier, int userId)
    {
        try
        {
            if (_state.State.Bots.ContainsKey(identifier))
            {
                _logger.LogWarning("Bot {Identifier} is already registered in the registry", identifier);
                return;
            }

            var entry = new BotRegistryEntry(identifier, userId);
            _state.State.Bots[identifier] = entry;

            // O(1) FIX: Increment the counters
            _state.State.TotalBotsCount++;
            _state.State.ActiveBotsCount++;
            _state.State.LastUpdated = DateTime.UtcNow;

            await _state.WriteStateAsync();

            _logger.LogInformation(
                "Bot {Identifier} registered successfully for user {UserId}. Total bots: {TotalBots}, Active bots: {ActiveBots}",
                identifier, userId, _state.State.TotalBotsCount, _state.State.ActiveBotsCount);

            // Notify platform summary grain about strategy count change
            await NotifyPlatformSummaryAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to register bot {Identifier} for user {UserId}", identifier, userId);
            throw;
        }
    }

    public async Task UnregisterBot(Guid identifier)
    {
        try
        {
            if (!_state.State.Bots.TryGetValue(identifier, out var entryToRemove))
            {
                _logger.LogWarning("Bot {Identifier} is not registered in the registry", identifier);
                return;
            }

            _state.State.Bots.Remove(identifier);

            // O(1) FIX: Decrement the counters based on the removed entry's status
            _state.State.TotalBotsCount--;
            if (entryToRemove.Status == BotStatus.Running)
            {
                _state.State.ActiveBotsCount--;
            }

            _state.State.LastUpdated = DateTime.UtcNow;

            await _state.WriteStateAsync();

            _logger.LogInformation(
                "Bot {Identifier} unregistered successfully from user {UserId}. Total bots: {TotalBots}",
                identifier, entryToRemove.UserId, _state.State.TotalBotsCount);

            // Notify platform summary grain about strategy count change
            await NotifyPlatformSummaryAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to unregister bot {Identifier}", identifier);
            throw;
        }
    }

    public Task<List<BotRegistryEntry>> GetAllBots()
    {
        var bots = _state.State.Bots.Values.ToList();
        _logger.LogDebug("Retrieved {Count} bots from registry", bots.Count);
        return Task.FromResult(bots);
    }

    public Task<List<BotRegistryEntry>> GetBotsForUser(int userId)
    {
        var userBots = _state.State.Bots.Values
            .Where(b => b.UserId == userId)
            .ToList();

        _logger.LogDebug("Retrieved {Count} bots for user {UserId}", userBots.Count, userId);
        return Task.FromResult(userBots);
    }

    public async Task UpdateBotStatus(Guid identifier, BotStatus newStatus)
    {
        try
        {
            if (!_state.State.Bots.TryGetValue(identifier, out var entry))
            {
                _logger.LogWarning("Bot {Identifier} is not registered in the registry, cannot update status",
                    identifier);
                return;
            }

            var previousStatus = entry.Status;

            if (previousStatus == newStatus)
            {
                _logger.LogDebug("Bot {Identifier} status unchanged ({Status}), skipping state write", identifier,
                    newStatus);
                return;
            }

            // O(1) FIX: Conditionally adjust the counter
            if (newStatus == BotStatus.Running && previousStatus != BotStatus.Running)
            {
                _state.State.ActiveBotsCount++;
            }
            else if (newStatus != BotStatus.Running && previousStatus == BotStatus.Running)
            {
                _state.State.ActiveBotsCount--;
            }

            entry.Status = newStatus;
            entry.LastStatusUpdate = DateTime.UtcNow;
            _state.State.LastUpdated = DateTime.UtcNow;

            await _state.WriteStateAsync();

            _logger.LogInformation(
                "Bot {Identifier} status updated from {PreviousStatus} to {NewStatus}. Active bots: {ActiveBots}",
                identifier, previousStatus, newStatus, _state.State.ActiveBotsCount);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update status for bot {Identifier} to {Status}", identifier, newStatus);
            throw;
        }
    }

    public Task<BotStatus> GetBotStatus(Guid identifier)
    {
        if (!_state.State.Bots.TryGetValue(identifier, out var entry))
        {
            _logger.LogWarning("Bot {Identifier} is not registered in the registry, returning None", identifier);
            return Task.FromResult(BotStatus.Saved);
        }

        return Task.FromResult(entry.Status);
    }

    private async Task NotifyPlatformSummaryAsync()
    {
        try
        {
            var platformGrain = GrainFactory.GetGrain<IPlatformSummaryGrain>("platform-summary");
            await platformGrain.UpdateActiveStrategyCountAsync(_state.State.ActiveBotsCount);
            
            _logger.LogDebug("Notified platform summary about active strategy count change. New count: {ActiveCount}", 
                _state.State.ActiveBotsCount);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to notify platform summary about strategy count change");
        }
    }
}