using Microsoft.Extensions.Logging;

using DomainResults.Common;

using MongoDB.Bson.Serialization;
using MongoDB.Driver;

using DataProviders.Abstractions;

using DomainObjects.Documents;

namespace DataProviders.Collections {
  public interface IBlogCatalogDataProvider {
    (Guid?, IDomainResult) Insert(BlogDocument blogItem);
    (BlogDocument?, IDomainResult) Get(Guid siteId, Guid blogId);
    (BlogDocument?, IDomainResult) GetBySlug(Guid siteId, string slug);
    (List<BlogDocument>?, IDomainResult) GetBySlugs(Guid siteId, List<string> slugs);
    (List<BlogDocument>?, IDomainResult) GetMany(Guid siteId, List<Guid> blogIds);
    (List<BlogDocument>?, IDomainResult) GetAll(Guid siteId, int skip, int take);
    (Guid?, IDomainResult) Update(BlogDocument blogItem);
    IDomainResult Delete(Guid id);
    IDomainResult DeleteMany(Guid siteId, List<Guid> blogIds);
    IDomainResult DeleteAll(Guid siteId);
  }

  public class BlogCatalogDataProvider : CollectionDataProviderBase<BlogDocument>, IBlogCatalogDataProvider {

    private const string _databaseName = "reactredux";
    private const string _collectionName = "blogcatalog";

    public BlogCatalogDataProvider(
      ILogger<CollectionDataProviderBase<BlogDocument>> logger,
      IMongoClient client,
      IIdGenerator idGenerator,
      ISessionService sessionService) : base(logger, client, idGenerator, sessionService, _databaseName, _collectionName) {
    }

    public (BlogDocument?, IDomainResult) Get(Guid siteId, Guid blogId) {
      var (list, result) = GetWithPredicate(x => x.SiteId == siteId && x.Id == blogId);

      if (!result.IsSuccess || list == null)
        return (null, result);

      return (list.First(), result);
    }

    public (BlogDocument?, IDomainResult) GetBySlug(Guid siteId, string slug) {
      var (list, result) = GetBySlugs(siteId, new List<string> { slug });

      if (!result.IsSuccess || list == null)
        return (null, result);

      return (list.First(), result);
    }

    public (List<BlogDocument>?, IDomainResult) GetBySlugs(Guid siteId, List<string> slugs) =>
      GetWithPredicate(x => x.SiteId == siteId && x.L10n.Any(y => slugs.Contains(y.Slug)));

    public (List<BlogDocument>?, IDomainResult) GetMany(Guid siteId, List<Guid> blogIds) =>
      GetWithPredicate(x => x.SiteId == siteId && blogIds.Contains(x.Id));

    public (List<BlogDocument>?, IDomainResult) GetAll(Guid siteId, int skip, int take) =>
      GetWithPredicate(x => x.SiteId == siteId);

    public (Guid?, IDomainResult) Update(BlogDocument blogItem) =>
      UpdateWithPredicate(blogItem, x => x.Id == blogItem.Id);

    public IDomainResult Delete(Guid id) =>
      DeleteWithPredicate(x => x.Id == id);

    public IDomainResult DeleteMany(Guid siteId, List<Guid> blogIds) =>
      DeleteWithPredicate(x => x.SiteId == siteId && blogIds.Contains(x.Id));

    public IDomainResult DeleteAll(Guid siteId) =>
      DeleteManyWithPredicate(x => x.SiteId == siteId);
  }
}
