using AyCode.Interfaces.Messages;
using Microsoft.EntityFrameworkCore;

namespace AyCode.Database.DbSets.Messages;

public static class AcEmailMessageDbSetExtension
{
    public static TEmailMessage? GetEmailMessageById<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid emailMessageId) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.FirstOrDefault(x => x.Id == emailMessageId);

    public static IQueryable<TEmailMessage> GetEmailMessagesByContextId<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid contextId) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.Where(x => x.ContextId == contextId);

    public static IQueryable<TEmailMessage> GetEmailMessagesBySenderEmailAddress<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, string senderEmailAddress) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.Where(x => x.EmailAddress == senderEmailAddress);

    public static IQueryable<TEmailMessage> GetEmailMessagesBySenderId<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid senderId) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.Where(x => x.SenderId == senderId);

    public static IQueryable<TEmailMessage> GetEmailMessagesByRecipientId<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid recipientId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.EmailMessages.Where(x => x.Recipients.Any(recipient => recipient.RecipientId == recipientId));
    }

    private static IQueryable<TEmailMessage> GetEmailMessagesBySenderIdOrRecipientId<TEmailMessage, TEmailRecipient>(this IQueryable<TEmailMessage> queryableEmails, Guid senderIdOrRecipientId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return queryableEmails.Where(x => x.SenderId == senderIdOrRecipientId || x.Recipients.Any(recipient => recipient.RecipientId == senderIdOrRecipientId));
    }

    public static IQueryable<TEmailMessage> GetEmailMessages<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid senderIdOrRecipientId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.EmailMessages.GetEmailMessagesBySenderIdOrRecipientId<TEmailMessage, TEmailRecipient>(senderIdOrRecipientId);
    }

    public static IQueryable<TEmailMessage> GetEmailMessages<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid contextId, Guid senderIdOrRecipientId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.EmailMessages.Where(x => x.ContextId == contextId).GetEmailMessagesBySenderIdOrRecipientId<TEmailMessage, TEmailRecipient>(senderIdOrRecipientId);
    }


    private static IQueryable<TEmailMessage> GetEmailMessagesByUserIdOrUpmId<TEmailMessage, TEmailRecipient>(this IQueryable<TEmailMessage> queryableEmails, Guid userId, Guid userProductMappingId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return queryableEmails.Where(x => x.SenderId == userId || x.SenderId == userProductMappingId || x.Recipients.Any(recipient => recipient.RecipientId == userId || recipient.RecipientId == userProductMappingId));
    }

    public static IQueryable<TEmailMessage> GetEmailMessagesByUserIdOrUpmId<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid userId, Guid userProductMappingId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.EmailMessages.GetEmailMessagesByUserIdOrUpmId<TEmailMessage, TEmailRecipient>(userId, userProductMappingId);
    }

    public static IQueryable<TEmailMessage> GetAllEmailMessages<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.EmailMessages;
    }

    public static IQueryable<TEmailMessage> GetEmailMessages<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid contextId, Guid userId, Guid userProductMappingId)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.GetEmailMessagesByContextId(contextId).GetEmailMessagesByUserIdOrUpmId<TEmailMessage, TEmailRecipient>(userId, userProductMappingId);
    }

    private static IQueryable<TEmailMessage> GetEmailMessagesByIds<TEmailMessage, TEmailRecipient>(this IQueryable<TEmailMessage> queryableEmails, IQueryable<Guid> ids)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return queryableEmails.Where(x => ids.Any(id => id == x.SenderId) || x.Recipients.Any(recipient => ids.Any(id => id == recipient.RecipientId)));
    }

    public static IQueryable<TEmailMessage> GetEmailMessagesByIds<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, IQueryable<Guid> ids)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.EmailMessages.GetEmailMessagesByIds<TEmailMessage, TEmailRecipient>(ids);
    }

    public static IQueryable<TEmailMessage> GetEmailMessagesByIds<TEmailMessage, TEmailRecipient>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid contextId, IQueryable<Guid> ids)
        where TEmailMessage : class, IAcEmailMessageBase, IAcEmailRecipientsRelation<TEmailRecipient>
        where TEmailRecipient : IAcEmailRecipientBase
    {
        return ctx.GetEmailMessagesByContextId(contextId).GetEmailMessagesByIds<TEmailMessage, TEmailRecipient>(ids);
    }

    #region Add, Update, Remove

    public static bool AddEmailMessage<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, TEmailMessage emailMessage) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.Add(emailMessage).State == EntityState.Added;

    public static bool UpdateEmailMessage<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, TEmailMessage emailMessage) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.Update(emailMessage).State == EntityState.Modified;

    public static bool RemoveEmailMessage<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, Guid emailMessageId) where TEmailMessage : class, IAcEmailMessageBase
    {
        var emailMessage = ctx.GetEmailMessageById(emailMessageId);

        return emailMessage == null || ctx.RemoveEmailMessage(emailMessage);
    }

    public static bool RemoveEmailMessage<TEmailMessage>(this IAcEmailMessageDbSet<TEmailMessage> ctx, TEmailMessage emailMessage) where TEmailMessage : class, IAcEmailMessageBase
        => ctx.EmailMessages.Remove(emailMessage).State == EntityState.Deleted;

    #endregion Add, Update, Remove

}