using JobTrackerApi.Data;
using JobTrackerApi.Models;
using Microsoft.EntityFrameworkCore;

namespace JobTrackerApi.Services;

public sealed class UserNotificationStore(JobTrackerContext db, TimeProvider timeProvider)
{
    public Task<UserNotification?> GetAsync(Guid notificationId, CancellationToken cancellationToken)
    {
        EnsureOwnerScope();
        return db.UserNotifications.AsNoTracking().FirstOrDefaultAsync(notification => notification.Id == notificationId, cancellationToken);
    }

    public Task<List<UserNotification>> ListAsync(int limit, CancellationToken cancellationToken)
    {
        EnsureOwnerScope();
        if (limit is < 1 or > 100) throw new ArgumentOutOfRangeException(nameof(limit));
        return db.UserNotifications.AsNoTracking()
            .Where(notification => notification.DismissedAtUtc == null)
            .OrderByDescending(notification => notification.CreatedAtUtc)
            .Take(limit)
            .ToListAsync(cancellationToken);
    }

    public Task<int> UnreadCountAsync(CancellationToken cancellationToken)
    {
        EnsureOwnerScope();
        return db.UserNotifications.CountAsync(
            notification => notification.DismissedAtUtc == null && notification.ReadAtUtc == null,
            cancellationToken);
    }

    public Task<int> MarkReadAsync(Guid notificationId, CancellationToken cancellationToken)
    {
        EnsureOwnerScope();
        var now = timeProvider.GetUtcNow().UtcDateTime;
        return db.UserNotifications
            .Where(notification => notification.Id == notificationId && notification.ReadAtUtc == null)
            .ExecuteUpdateAsync(setters => setters.SetProperty(notification => notification.ReadAtUtc, now), cancellationToken);
    }

    public Task<int> DismissAsync(Guid notificationId, CancellationToken cancellationToken)
    {
        EnsureOwnerScope();
        var now = timeProvider.GetUtcNow().UtcDateTime;
        return db.UserNotifications
            .Where(notification => notification.Id == notificationId && notification.DismissedAtUtc == null)
            .ExecuteUpdateAsync(setters => setters.SetProperty(notification => notification.DismissedAtUtc, now), cancellationToken);
    }

    private void EnsureOwnerScope()
    {
        if (db.CurrentUserId is null) throw new InvalidOperationException("Notification access requires an authenticated owner scope.");
    }
}
