using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Bots.Grains;
using Managing.Application.Bots.Models;
using Managing.Domain.Bots;
using Managing.Domain.Statistics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;

namespace Managing.Application.Tests;

public class AgentGrainTests
{
    private readonly Mock<IPersistentState<AgentGrainState>> _mockState;
    private readonly Mock<ILogger<AgentGrain>> _mockLogger;
    private readonly Mock<IBotService> _mockBotService;
    private readonly Mock<IAgentService> _mockAgentService;
    private readonly Mock<IExchangeService> _mockExchangeService;
    private readonly Mock<IUserService> _mockUserService;
    private readonly Mock<IAccountService> _mockAccountService;
    private readonly Mock<ITradingService> _mockTradingService;
    private readonly Mock<IServiceScopeFactory> _mockScopeFactory;

    public AgentGrainTests()
    {
        _mockState = new Mock<IPersistentState<AgentGrainState>>();
        _mockLogger = new Mock<ILogger<AgentGrain>>();
        _mockBotService = new Mock<IBotService>();
        _mockAgentService = new Mock<IAgentService>();
        _mockExchangeService = new Mock<IExchangeService>();
        _mockUserService = new Mock<IUserService>();
        _mockAccountService = new Mock<IAccountService>();
        _mockTradingService = new Mock<ITradingService>();
        _mockScopeFactory = new Mock<IServiceScopeFactory>();

        // Setup default state
        _mockState.Setup(x => x.State).Returns(new AgentGrainState
        {
            AgentName = "TestAgent",
            BotIds = new HashSet<Guid> { Guid.NewGuid() }
        });
    }

    [Fact]
    public async Task RegisterBotAsync_ShouldUpdateSummary()
    {
        // Arrange
        var agentGrain = CreateAgentGrain();
        var newBotId = Guid.NewGuid();

        // Setup mocks
        _mockBotService.Setup(x => x.GetBotsByIdsAsync(It.IsAny<HashSet<Guid>>()))
            .ReturnsAsync(new List<Bot>());
        _mockAgentService.Setup(x => x.SaveOrUpdateAgentSummary(It.IsAny<AgentSummary>()))
            .Returns(Task.CompletedTask);

        // Act
        await agentGrain.RegisterBotAsync(newBotId);

        // Assert
        _mockAgentService.Verify(x => x.SaveOrUpdateAgentSummary(It.IsAny<AgentSummary>()), Times.Once);
    }

    [Fact]
    public async Task UnregisterBotAsync_ShouldUpdateSummary()
    {
        // Arrange
        var agentGrain = CreateAgentGrain();
        var botId = _mockState.Object.State.BotIds.First();

        // Setup mocks
        _mockBotService.Setup(x => x.GetBotsByIdsAsync(It.IsAny<HashSet<Guid>>()))
            .ReturnsAsync(new List<Bot>());
        _mockAgentService.Setup(x => x.SaveOrUpdateAgentSummary(It.IsAny<AgentSummary>()))
            .Returns(Task.CompletedTask);

        // Act
        await agentGrain.UnregisterBotAsync(botId);

        // Assert
        _mockAgentService.Verify(x => x.SaveOrUpdateAgentSummary(It.IsAny<AgentSummary>()), Times.Once);
    }

    private AgentGrain CreateAgentGrain()
    {
        return new AgentGrain(
            _mockState.Object,
            _mockLogger.Object,
            _mockBotService.Object,
            _mockAgentService.Object,
            _mockExchangeService.Object,
            _mockUserService.Object,
            _mockAccountService.Object,
            _mockTradingService.Object,
            _mockScopeFactory.Object);
    }
}