using Microsoft.Extensions.Logging;
using PARR.Core.Common.Interfaces;

namespace PARR.Infrastructure.Interval
{
    internal class IntervalService : IIntervalService
    {
        private readonly ILogger<IntervalService> logger;

        public IntervalService(ILogger<IntervalService> logger)
        {
            this.logger = logger;
        }

        //public async Task IntervalInitAsync(IntervalHandlerDelegate intervalHandler, TimeSpan interval)
        public async Task IntervalInitAsync(Func<Task> handler, TimeSpan interval)
        {
            logger.LogInformation("Инициализация интервального сервиса с интервалом: {Interval}", interval);

            var nextStart = DateTimeOffset.UtcNow;

            while (true)
            {
                nextStart = DateTimeOffset.UtcNow;

                logger.LogInformation("Запуск по расписанию. Интервал: {interval}, дата: {nextStart}", interval, nextStart);

                try
                {
                    await handler.Invoke();
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "Ошибка при выполнении интервального обработчика");
                }

                nextStart = nextStart.Add(interval);

                logger.LogInformation("Следующая дата запуска: {NextStart}. Интервал: {Interval}.", nextStart, interval);

                var intervalOffset = nextStart - DateTimeOffset.UtcNow;
                if (intervalOffset < TimeSpan.Zero)
                {
                    intervalOffset = TimeSpan.Zero;
                    logger.LogWarning(
                        "Время следующего запуска изменено на текущее время. Рассчитанное время запуска ({NextStart}) меньше текущего времени ({Now}). " +
                        "Это произошло потому что время выполнения основного метода больше чем заданный интервал повторений.",
                        nextStart,
                        DateTimeOffset.UtcNow);
                }

                logger.LogDebug("Ожидание {Delay} перед следующим запуском", intervalOffset);

                await Task.Delay(intervalOffset);
            }
        }
    }
}