using DomainResults.Common;

using DataProviders.Collections;

using DomainObjects.Documents;

using WeatherForecast.Services.Abstractions;
using WeatherForecast.Models.Blog.Responses;
using WeatherForecast.Models.Blog.Requests;

namespace WeatherForecast.Services {

  /// <summary>
  /// 
  /// </summary>
  public interface IBlogItemService {

    /// <summary>
    /// 
    /// </summary>
    /// <param name="blogItem"></param>
    /// <returns></returns>
    (Guid?, IDomainResult) Post(BlogDocument blogItem);

    /// <summary>
    /// 
    /// </summary>
    /// <param name="blogItem"></param>
    /// <returns></returns>
    (BlogItemResponseModel?, IDomainResult) Get(BlogDocument blogItem);

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="slug"></param>
    /// <returns></returns>
    (BlogItemResponseModel?, IDomainResult) GetSlug(Guid siteId, string slug);

    /// <summary>
    /// 
    /// </summary>
    /// <param name="blogItem"></param>
    /// <param name="requestData"></param>
    /// <returns></returns>
    (Guid?, IDomainResult) Update(BlogDocument blogItem, BlogItemRequestModel requestData);
  }

  /// <summary>
  /// 
  /// </summary>
  public class BlogItemService : PostItemServiceBase<BlogItemService>, IBlogItemService {

    private readonly IBlogCatalogDataProvider _blogCatalogDataProvider;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="logger"></param>
    /// <param name="blogCatalogDataProvider"></param>
    /// <param name="categoryDataProvider"></param>
    public BlogItemService(
      ILogger<BlogItemService> logger,
      IBlogCatalogDataProvider blogCatalogDataProvider,
      ICategoryDataProvider categoryDataProvider
    ) : base(logger, categoryDataProvider) {
      _blogCatalogDataProvider = blogCatalogDataProvider;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="blogItem"></param>
    /// <returns></returns>
    public (Guid?, IDomainResult) Post(BlogDocument blogItem) {

      var (_, getResult) = _blogCatalogDataProvider.GetBySlugs(blogItem.SiteId, blogItem.L10n.Select(x => x.Slug).ToList());
      if (getResult.IsSuccess)
        return IDomainResult.Failed<Guid?>();

      // will create default category if no categories are specified blogItem.Categories
      var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(blogItem.SiteId, blogItem.Categories);
      if (!addCategoriesResult.IsSuccess || categories == null)
        return (null, addCategoriesResult);

      blogItem.Categories = categories;

      var (id, insertResult) = _blogCatalogDataProvider.Insert(blogItem);
      if (!insertResult.IsSuccess)
        return IDomainResult.Failed<Guid?>();

      return IDomainResult.Success(id);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public (BlogItemResponseModel?, IDomainResult) Get(BlogDocument item) {
      
      var (categories, getCategoryResult) = _categoryDataProvider.GetMany(item.SiteId, item.Categories);
      if (!getCategoryResult.IsSuccess || categories == null)
        return IDomainResult.Failed<BlogItemResponseModel?>();

      return IDomainResult.Success(new BlogItemResponseModel(item, categories));

    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="siteId"></param>
    /// <param name="slug"></param>
    /// <returns></returns>
    public (BlogItemResponseModel?, IDomainResult) GetSlug(Guid siteId, string slug) {

      var (blog, getBlogItemResult) = _blogCatalogDataProvider.GetBySlug(siteId, slug);
      if (!getBlogItemResult.IsSuccess || blog == null)
        return IDomainResult.Failed<BlogItemResponseModel?>();

      var (categories, getCategoryResult) = _categoryDataProvider.GetMany(blog.SiteId, blog.Categories);
      if (!getCategoryResult.IsSuccess || categories == null)
        return IDomainResult.Failed<BlogItemResponseModel?>();

      var locale = blog.L10n.Single(x => x.Slug == slug).Locale;

      return IDomainResult.Success(new BlogItemResponseModel(blog, categories, locale));
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="blogItem"></param>
    /// <param name="requestData"></param>
    /// <returns></returns>
    public (Guid?, IDomainResult) Update(BlogDocument blogItem, BlogItemRequestModel requestData) {

      // construct domain object from model
      var newItem = requestData.ToDomainObject();
      newItem.Id = blogItem.Id;
      newItem.SiteId = blogItem.SiteId;

      newItem.Created = blogItem.Created;
      newItem.Author = blogItem.Author;

      var (categories, addCategoriesResult) = AddCategoryIfNullOrEmpty(blogItem.SiteId, requestData.Categories);
      if (!addCategoriesResult.IsSuccess || categories == null)
        return (null, addCategoriesResult);

      blogItem.Categories = categories;

      if (!blogItem.Equals(newItem)) {
        var (id, updateResult) = _blogCatalogDataProvider.Update(newItem);
        if (!updateResult.IsSuccess || id == null)
          return (null, updateResult);
      }

      return IDomainResult.Success(blogItem.Id);
    }
  }
}
