using FluentAssertions;
using MiningService.API.Application.Queries;
using MiningService.Domain.AggregatesModel.MinerAggregate;
using NSubstitute;
using Xunit;

namespace MiningService.UnitTests.Application.Queries;

/// <summary>
/// EN: Unit tests for GetMinerStatusQueryHandler.
/// VI: Unit tests cho GetMinerStatusQueryHandler.
/// </summary>
public class GetMinerStatusQueryHandlerTests
{
    private readonly IMinerRepository _minerRepository;
    private readonly GetMinerStatusQueryHandler _handler;

    public GetMinerStatusQueryHandlerTests()
    {
        _minerRepository = Substitute.For<IMinerRepository>();
        _handler = new GetMinerStatusQueryHandler(_minerRepository);
    }

    [Fact]
    public async Task Handle_ExistingMiner_ReturnsMinerStatus()
    {
        // Arrange
        var userId = Guid.NewGuid();
        var miner = Miner.Create(userId);
        var query = new GetMinerStatusQuery(userId);

        _minerRepository.GetByUserIdAsync(userId, Arg.Any<CancellationToken>())
            .Returns(miner);

        // Act
        var result = await _handler.Handle(query, CancellationToken.None);

        // Assert
        result.Should().NotBeNull();
        result!.MinerId.Should().Be(miner.Id);
        result.Role.Should().Be("Pioneer");
        result.TotalMinedPoints.Should().Be(0);
        result.HourlyRate.Should().BeGreaterThan(0);
    }

    [Fact]
    public async Task Handle_MinerNotFound_ReturnsNull()
    {
        // Arrange
        var userId = Guid.NewGuid();
        var query = new GetMinerStatusQuery(userId);

        _minerRepository.GetByUserIdAsync(userId, Arg.Any<CancellationToken>())
            .Returns((Miner?)null);

        // Act
        var result = await _handler.Handle(query, CancellationToken.None);

        // Assert
        result.Should().BeNull();
    }

    [Fact]
    public async Task Handle_MinerWithActiveSession_ReturnsSessionInfo()
    {
        // Arrange
        var userId = Guid.NewGuid();
        var miner = Miner.Create(userId);
        miner.StartMiningSession();
        var query = new GetMinerStatusQuery(userId);

        _minerRepository.GetByUserIdAsync(userId, Arg.Any<CancellationToken>())
            .Returns(miner);

        // Act
        var result = await _handler.Handle(query, CancellationToken.None);

        // Assert
        result.Should().NotBeNull();
        result!.HasActiveSession.Should().BeTrue();
        result.SessionEndTime.Should().NotBeNull();
    }
}
