📄 MatDenDagen/Services/NotificationBackgroundService.cs
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace MatDenDagen.Services;

public sealed class NotificationBackgroundService(
    IServiceProvider serviceProvider,
    ILogger<NotificationBackgroundService> logger,
    IOptions<NotificationServiceOptions> options
) : BackgroundService
{
    private readonly TimeSpan checkInterval = options.Value.CheckInterval;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        logger.LogInformation(
            "Notification background service started with {Interval} minute interval",
            checkInterval.TotalMinutes
        );

        using var timer = new PeriodicTimer(checkInterval);

        try
        {
            DateTimeOffset? lastCheck = null;
            do
            {
                lastCheck = await ExecuteNotificationCheckAsync(lastCheck, stoppingToken);
            } while (await timer.WaitForNextTickAsync(stoppingToken));
        }
        catch (OperationCanceledException)
        {
            logger.LogInformation("Notification background service is stopping");
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Notification background service failed");
        }
    }

    private async Task<DateTimeOffset?> ExecuteNotificationCheckAsync(
        DateTimeOffset? lastCheck,
        CancellationToken cancellationToken
    )
    {
        try
        {
            using var scope = serviceProvider.CreateScope();
            var notificationService = scope.ServiceProvider.GetRequiredService<NotificationService>();

            return await notificationService.CheckAndSendNotificationsAsync(lastCheck, cancellationToken);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error during notification check");
            return null;
        }
    }
}