using Managing.Domain.Candles;
using Xunit;
using static Managing.Common.Enums;

namespace Managing.Application.Tests
{
    public class CandleHelpersTests
    {
        [Fact]
        public void GetDueTimeForTimeframe_FifteenMinutes_ShouldReturnCorrectTimeSpan()
        {
            // Arrange
            var timeframe = Timeframe.FifteenMinutes;
            var testTime = new DateTime(2024, 1, 1, 16, 42, 36, DateTimeKind.Utc); // 16:42:36

            // Act
            var dueTime = CandleHelpers.GetDueTimeForTimeframe(timeframe, testTime);

            // Assert
            Assert.True(dueTime.TotalMinutes > 0, "Due time should be positive");
            Assert.True(dueTime.TotalMinutes < 15, "Due time should be less than the timeframe interval");

            // Next 15-minute boundary is 16:45:00, so execution should be at 16:45:01
            // Time difference should be approximately 2 minutes and 25 seconds
            var expectedMinutes = 2;
            var expectedSeconds = 25;
            var expectedTotalSeconds = expectedMinutes * 60 + expectedSeconds;

            Assert.True(Math.Abs(dueTime.TotalSeconds - expectedTotalSeconds) <= 1,
                $"Expected approximately {expectedMinutes}m {expectedSeconds}s, but got {dueTime.TotalMinutes:F2}m {dueTime.Seconds}s");

            // Verify the next execution time
            var nextExecution = testTime.Add(dueTime);
            Assert.Equal(16, nextExecution.Hour);
            Assert.Equal(45, nextExecution.Minute);
            Assert.Equal(1, nextExecution.Second);
        }

        [Fact]
        public void GetDueTimeForTimeframe_FiveMinutes_ShouldAlignToFiveMinuteBoundaries()
        {
            // Arrange
            var timeframe = Timeframe.FiveMinutes;
            var testTime = new DateTime(2024, 1, 1, 10, 23, 45, DateTimeKind.Utc); // 10:23:45

            // Act
            var dueTime = CandleHelpers.GetDueTimeForTimeframe(timeframe, testTime);

            // Assert
            var nextExecution = testTime.Add(dueTime);
            // Should align to 10:25:01 (next 5-minute boundary + 1 second)
            Assert.Equal(10, nextExecution.Hour);
            Assert.Equal(25, nextExecution.Minute);
            Assert.Equal(1, nextExecution.Second);
        }

        [Fact]
        public void GetDueTimeForTimeframe_OneHour_ShouldAlignToHourBoundaries()
        {
            // Arrange
            var timeframe = Timeframe.OneHour;
            var testTime = new DateTime(2024, 1, 1, 14, 30, 15, DateTimeKind.Utc); // 14:30:15

            // Act
            var dueTime = CandleHelpers.GetDueTimeForTimeframe(timeframe, testTime);

            // Assert
            var nextExecution = testTime.Add(dueTime);
            // Should align to 15:00:01 (next hour boundary + 1 second)
            Assert.Equal(15, nextExecution.Hour);
            Assert.Equal(0, nextExecution.Minute);
            Assert.Equal(1, nextExecution.Second);
        }

        [Fact]
        public void GetNextExpectedCandleTime_FifteenMinutes_ShouldReturnCorrectBoundary()
        {
            // Arrange
            var timeframe = Timeframe.FifteenMinutes;
            var testTime = new DateTime(2024, 1, 1, 16, 42, 36, DateTimeKind.Utc); // 16:42:36

            // Act
            var nextCandleTime = CandleHelpers.GetNextExpectedCandleTime(timeframe, testTime);

            // Assert
            // Next 15-minute boundary should be 16:45:00
            Assert.Equal(16, nextCandleTime.Hour);
            Assert.Equal(44, nextCandleTime.Minute);
            Assert.Equal(59, nextCandleTime.Second);
        }

        [Fact]
        public void GetNextExpectedCandleTime_FiveMinutes_ShouldAlignToFiveMinuteBoundaries()
        {
            // Arrange
            var timeframe = Timeframe.FiveMinutes;
            var testTime = new DateTime(2024, 1, 1, 10, 23, 45, DateTimeKind.Utc); // 10:23:45

            // Act
            var nextCandleTime = CandleHelpers.GetNextExpectedCandleTime(timeframe, testTime);

            // Assert
            // Next 5-minute boundary should be 10:25:00
            Assert.Equal(10, nextCandleTime.Hour);
            Assert.Equal(24, nextCandleTime.Minute);
            Assert.Equal(59, nextCandleTime.Second);
        }

        [Fact]
        public void GetNextExpectedCandleTime_OneHour_ShouldAlignToHourBoundaries()
        {
            // Arrange
            var timeframe = Timeframe.OneHour;
            var testTime = new DateTime(2024, 1, 1, 14, 30, 15, DateTimeKind.Utc); // 14:30:15

            // Act
            var nextCandleTime = CandleHelpers.GetNextExpectedCandleTime(timeframe, testTime);

            // Assert
            // Next hour boundary should be 15:00:00
            Assert.Equal(14, nextCandleTime.Hour);
            Assert.Equal(59, nextCandleTime.Minute);
            Assert.Equal(59, nextCandleTime.Second);
        }
    }
}