using Meezi.API.Models.Notifications;
using Meezi.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace Meezi.API.Services;

public interface INotificationInboxService
{
    Task<NotificationListDto> ListAsync(
        string cafeId,
        bool unreadOnly,
        int limit,
        CancellationToken ct = default);

    Task<int> GetUnreadCountAsync(string cafeId, CancellationToken ct = default);

    Task MarkReadAsync(string cafeId, MarkNotificationsReadRequest request, CancellationToken ct = default);
}

public class NotificationInboxService : INotificationInboxService
{
    private readonly AppDbContext _db;

    public NotificationInboxService(AppDbContext db)
    {
        _db = db;
    }

    public async Task<NotificationListDto> ListAsync(
        string cafeId,
        bool unreadOnly,
        int limit,
        CancellationToken ct = default)
    {
        limit = Math.Clamp(limit, 1, 100);
        var q = _db.CafeNotifications.AsNoTracking().Where(n => n.CafeId == cafeId);
        if (unreadOnly)
            q = q.Where(n => !n.IsRead);

        var unread = await q.CountAsync(n => !n.IsRead, ct);
        var items = await q
            .OrderByDescending(n => n.CreatedAt)
            .Take(limit)
            .Select(n => new CafeNotificationDto(
                n.Id,
                n.Type,
                n.Title,
                n.Body,
                n.ReferenceId,
                n.TableNumber,
                n.IsRead,
                n.CreatedAt))
            .ToListAsync(ct);

        return new NotificationListDto(items, unread);
    }

    public Task<int> GetUnreadCountAsync(string cafeId, CancellationToken ct = default) =>
        _db.CafeNotifications.CountAsync(n => n.CafeId == cafeId && !n.IsRead, ct);

    public async Task MarkReadAsync(
        string cafeId,
        MarkNotificationsReadRequest request,
        CancellationToken ct = default)
    {
        var q = _db.CafeNotifications.Where(n => n.CafeId == cafeId && !n.IsRead);
        if (!request.All && request.Ids is { Count: > 0 })
            q = q.Where(n => request.Ids.Contains(n.Id));

        var rows = await q.ToListAsync(ct);
        var now = DateTime.UtcNow;
        foreach (var row in rows)
        {
            row.IsRead = true;
            row.ReadAt = now;
        }

        await _db.SaveChangesAsync(ct);
    }
}
