using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// EF 租户通知仓储。
/// </summary>
public sealed class EfTenantNotificationRepository(TakeoutAppDbContext context) : ITenantNotificationRepository
{
    /// <inheritdoc />
    public Task<IReadOnlyList<TenantNotification>> SearchAsync(
        long tenantId,
        TenantNotificationSeverity? severity,
        bool? unreadOnly,
        DateTime? from,
        DateTime? to,
        CancellationToken cancellationToken = default)
    {
        var query = context.TenantNotifications.AsNoTracking()
            .Where(x => x.TenantId == tenantId);

        if (severity.HasValue)
        {
            query = query.Where(x => x.Severity == severity.Value);
        }

        if (unreadOnly == true)
        {
            query = query.Where(x => x.ReadAt == null);
        }

        if (from.HasValue)
        {
            query = query.Where(x => x.SentAt >= from.Value);
        }

        if (to.HasValue)
        {
            query = query.Where(x => x.SentAt <= to.Value);
        }

        return query
            .OrderByDescending(x => x.SentAt)
            .ToListAsync(cancellationToken)
            .ContinueWith(t => (IReadOnlyList<TenantNotification>)t.Result, cancellationToken);
    }

    /// <inheritdoc />
    public Task<TenantNotification?> FindByIdAsync(long tenantId, long notificationId, CancellationToken cancellationToken = default)
    {
        return context.TenantNotifications
            .FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Id == notificationId, cancellationToken);
    }

    /// <inheritdoc />
    public Task<bool> ExistsByMetadataAsync(
        long tenantId,
        string title,
        string metadataJson,
        DateTime sentAfter,
        CancellationToken cancellationToken = default)
    {
        return context.TenantNotifications.AsNoTracking()
            .AnyAsync(
                x => x.TenantId == tenantId
                     && x.Title == title
                     && x.MetadataJson == metadataJson
                     && x.SentAt >= sentAfter,
                cancellationToken);
    }

    /// <inheritdoc />
    public Task AddAsync(TenantNotification notification, CancellationToken cancellationToken = default)
    {
        return context.TenantNotifications.AddAsync(notification, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task UpdateAsync(TenantNotification notification, CancellationToken cancellationToken = default)
    {
        context.TenantNotifications.Update(notification);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        return context.SaveChangesAsync(cancellationToken);
    }
}
