using MiningService.Domain.AggregatesModel.MinerAggregate;
using Xunit;

namespace MiningService.UnitTests.Domain;

/// <summary>
/// EN: Unit tests for MiningStreak value object.
/// VI: Unit tests cho MiningStreak value object.
/// </summary>
public class MiningStreakTests
{
    [Fact]
    public void CreateNew_ShouldReturnZeroStreak()
    {
        // Act
        var streak = MiningStreak.CreateNew();

        // Assert
        Assert.Equal(0, streak.CurrentStreak);
        Assert.Equal(0, streak.LongestStreak);
        Assert.Equal(0, streak.FreezeTokens);
        Assert.False(streak.IsGracePeriod);
    }

    [Theory]
    [InlineData(0, 0)]      // Day 0: 0%
    [InlineData(1, 0)]      // Day 1: 0%
    [InlineData(2, 0)]      // Day 2: 0%
    [InlineData(3, 0.10)]   // Day 3: +10%
    [InlineData(6, 0.10)]   // Day 6: +10%
    [InlineData(7, 0.25)]   // Day 7: +25%
    [InlineData(13, 0.25)]  // Day 13: +25%
    [InlineData(14, 0.50)]  // Day 14: +50%
    [InlineData(29, 0.50)]  // Day 29: +50%
    [InlineData(30, 1.00)]  // Day 30: +100%
    [InlineData(59, 1.00)]  // Day 59: +100%
    [InlineData(60, 1.25)]  // Day 60: +125%
    [InlineData(89, 1.25)]  // Day 89: +125%
    [InlineData(90, 1.50)]  // Day 90: +150%
    [InlineData(100, 1.50)] // Day 100: +150%
    public void BonusMultiplier_ShouldMatchTier(int currentStreak, decimal expectedBonus)
    {
        // Arrange
        var streak = new MiningStreak
        {
            CurrentStreak = currentStreak,
            LongestStreak = currentStreak,
            LastMiningDate = DateTime.UtcNow,
            FreezeTokens = 0,
            IsGracePeriod = false
        };

        // Assert
        Assert.Equal(expectedBonus, streak.BonusMultiplier);
    }

    [Fact]
    public void IncrementStreak_ShouldIncreaseBoth()
    {
        // Arrange
        var streak = MiningStreak.CreateNew();

        // Act
        var newStreak = streak.IncrementStreak();

        // Assert
        Assert.Equal(1, newStreak.CurrentStreak);
        Assert.Equal(1, newStreak.LongestStreak);
        Assert.False(newStreak.IsGracePeriod);
    }

    [Fact]
    public void IncrementStreak_AtDay7_ShouldEarnFreezeToken()
    {
        // Arrange
        var streak = new MiningStreak
        {
            CurrentStreak = 6,
            LongestStreak = 6,
            LastMiningDate = DateTime.UtcNow.AddDays(-1),
            FreezeTokens = 0,
            IsGracePeriod = false
        };

        // Act
        var newStreak = streak.IncrementStreak();

        // Assert
        Assert.Equal(7, newStreak.CurrentStreak);
        Assert.Equal(1, newStreak.FreezeTokens);
    }

    [Fact]
    public void Reset_ShouldZeroCurrentStreak()
    {
        // Arrange
        var streak = new MiningStreak
        {
            CurrentStreak = 30,
            LongestStreak = 50,
            LastMiningDate = DateTime.UtcNow,
            FreezeTokens = 3,
            IsGracePeriod = false
        };

        // Act
        var resetStreak = streak.Reset();

        // Assert
        Assert.Equal(0, resetStreak.CurrentStreak);
        Assert.Equal(50, resetStreak.LongestStreak); // Longest preserved
        Assert.Equal(3, resetStreak.FreezeTokens);   // Tokens preserved
    }
}
