using e_suite.Database.Core.Tables.Sequences;
using e_suite.Modules.SequenceManager;
using e_suite.UnitTestCore;
using eSuite.Core.Sequences;
using NUnit.Framework;
using System.Globalization;

namespace SequenceManager.UnitTests;

[TestFixture]
public class SequenceNumberBuilderUnitTests : TestBase
{
    [SetUp]
    public override async Task Setup()
    {
        await base.Setup();
    }

    [TestCase("Order [0000]", $"Order 0001", 0, 1)]
    [TestCase("Order [0000]", $"Order 0100", 99, 1)]
    [TestCase("Order [0000]", $"Order 0000", 1, -1)]
    [TestCase("Order [0000]", $"Order -0001", 0, -1)]
    [TestCase("Order [0]", $"Order 999999999", 999999998, 1)]
    [TestCase("Order [0]", $"Order 1", 0, 1)]
    [TestCase("Order [0]", $"Order 10", 9, 1)]
    public void GetNextSequenceNumber_ValueSeededAndIncrementSet_GeneratesNextSequenceNumber(string pattern, string expectedResult, long seed, long increment)
    {
        _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero);

        // Arrange
        var sequence = new Sequence
        {
            Id = 555,
            Guid = Guid.NewGuid(),
            Increment = increment,
            Name = "Sequence name",
            Pattern = pattern,
            Rollover = Rollover.Continuous,
            Deleted = false,
            Seed = seed
        };

        // Act
        var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock);

        // Assert
        Assert.That(sequenceNumber, !Is.Null);
        Assert.That(sequenceNumber, Is.EqualTo(expectedResult));
    }


    [Test]
    public void GetNextSequenceNumber_PatternIncludesDate_DateIncludedInGeneratedSequence()
    {
        // Arrange
        _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero);

        var sequence = new Sequence
        {
            Id = 555,
            Guid = Guid.NewGuid(),
            Increment = 1,
            Name = "Sequence name",
            Pattern = "Order [0] from {DD}-{MM}-{YYYY}",
            Rollover = Rollover.Continuous,
            Deleted = false,
            Seed = 0
        };

        // Act
        var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock);

        // Assert
        Assert.That(sequenceNumber, !Is.Null);
        Assert.That(sequenceNumber, Is.EqualTo($"Order 1 from {_fakeClock.DateTime.Day}-{_fakeClock.DateTime.Month}-{_fakeClock.DateTime.Year}"));
    }

    [TestCase(Rollover.Day, "20/09/2022", "21/09/2022")]
    [TestCase(Rollover.Month, "05/01/2022", "01/02/2022")]
    [TestCase(Rollover.Year, "05/01/2020", "01/01/2021")]
    public void GetNextSequenceNumber_RollOverSet_ValueResetsToOneAtRollover(Rollover rolloverType, string lastIssueDate, string issueDate)
    {
        // Arrange
        var formats = new[]{ "dd/MM/yyyy" };
        _fakeClock.DateTime = DateTimeOffset.ParseExact(issueDate, formats, CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.None);

        var sequence = new Sequence
        {
            Id = 555,
            Guid = Guid.NewGuid(),
            Increment = 1,
            Name = "Sequence name",
            Pattern = "Order [0]",
            Rollover = rolloverType,
            Deleted = false,
            Seed = 0,
            LastIssueDate = DateTime.ParseExact(lastIssueDate, "dd/mm/yyyy", CultureInfo.InvariantCulture),
            LastIssueValue = 999
        };

        // Act
        var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock);

        // Assert
        Assert.That(sequenceNumber, !Is.Null);
        Assert.That(sequenceNumber, Is.EqualTo("Order 1"));
    }

    [TestCase(Rollover.Continuous)]
    [TestCase(Rollover.Day)]
    [TestCase(Rollover.Month)]
    [TestCase(Rollover.Year)]
    public void GetNextSequenceNumber_NotRollingOver_IssuesNextValueCorrectly(Rollover rolloverType)
    {
        // Arrange
        _fakeClock.DateTime = new DateTimeOffset(2022, 10, 15, 17, 23, 52, TimeSpan.Zero);

        var sequence = new Sequence
        {
            Id = 555,
            Guid = Guid.NewGuid(),
            Increment = 1,
            Name = "Sequence name",
            Pattern = "Order [0]",
            Rollover = rolloverType,
            Deleted = false,
            Seed = 0,
            LastIssueDate = _fakeClock.DateTime,
            LastIssueValue = 998
        };

        // Act
        var sequenceNumber = SequenceNumberBuilder.GetNextSequenceNumber(sequence, _fakeClock);

        // Assert
        Assert.That(sequenceNumber, !Is.Null);
        Assert.That(sequenceNumber, Is.EqualTo("Order 999"));
    }
}