using Grand.Business.Core.Interfaces.Catalog.Products;
using Grand.Infrastructure.Extensions;
using Grand.Domain;
using Grand.Domain.Catalog;
using Grand.Data;
using MediatR;

namespace Grand.Business.Catalog.Services.Products
{
    /// <summary>
    /// Product review service
    /// </summary>
    public class ProductReviewService : IProductReviewService
    {

        #region Fields

        private readonly IRepository<ProductReview> _productReviewRepository;
        private readonly IMediator _mediator;

        #endregion

        #region Ctor

        public ProductReviewService(IRepository<ProductReview> productReviewRepository, IMediator mediator)
        {
            _productReviewRepository = productReviewRepository;
            _mediator = mediator;
        }

        #endregion

        /// <summary>
        /// Gets all product reviews
        /// </summary>
        /// <param name="customerId">Customer identifier; "" to load all records</param>
        /// <param name="approved">A value indicating whether to content is approved; null to load all records</param> 
        /// <param name="fromUtc">Item creation from; null to load all records</param>
        /// <param name="toUtc">Item item creation to; null to load all records</param>
        /// <param name="message">Search title or review text; null to load all records</param>
        /// <param name="storeId">Store ident</param>
        /// <param name="productId">Product ident</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <returns>Reviews</returns>
        public virtual async Task<IPagedList<ProductReview>> GetAllProductReviews(string customerId, bool? approved,
            DateTime? fromUtc = null, DateTime? toUtc = null,
            string message = null, string storeId = "", string productId = "", int pageIndex = 0, int pageSize = int.MaxValue)
        {
            var query = from p in _productReviewRepository.Table
                        select p;

            if (approved.HasValue)
                query = query.Where(c => c.IsApproved == approved.Value);
            if (!string.IsNullOrEmpty(customerId))
                query = query.Where(c => c.CustomerId == customerId);
            if (fromUtc.HasValue)
                query = query.Where(c => fromUtc.Value <= c.CreatedOnUtc);
            if (toUtc.HasValue)
                query = query.Where(c => toUtc.Value >= c.CreatedOnUtc);
            if (!string.IsNullOrEmpty(message))
                query = query.Where(c => c.Title.Contains(message) || c.ReviewText.Contains(message));
            if (!string.IsNullOrEmpty(storeId))
                query = query.Where(c => c.StoreId == storeId || c.StoreId == "");
            if (!string.IsNullOrEmpty(productId))
                query = query.Where(c => c.ProductId == productId);

            query = query.OrderByDescending(c => c.CreatedOnUtc);

            return await PagedList<ProductReview>.Create(query, pageIndex, pageSize);
        }

        /// <summary>
        /// Inserts a product review
        /// </summary>
        /// <param name="productReview">Product review</param>
        public virtual async Task InsertProductReview(ProductReview productReview)
        {
            ArgumentNullException.ThrowIfNull(productReview);

            await _productReviewRepository.InsertAsync(productReview);

            //event notification
            await _mediator.EntityInserted(productReview);
        }
        public virtual async Task UpdateProductReview(ProductReview productReview)
        {
            ArgumentNullException.ThrowIfNull(productReview);

            var update = UpdateBuilder<ProductReview>.Create()
                .Set(x => x.Title, productReview.Title)
                .Set(x => x.ReviewText, productReview.ReviewText)
                .Set(x => x.ReplyText, productReview.ReplyText)
                .Set(x => x.Signature, productReview.Signature)
                .Set(x => x.IsApproved, productReview.IsApproved)
                .Set(x => x.HelpfulNoTotal, productReview.HelpfulNoTotal)
                .Set(x => x.HelpfulYesTotal, productReview.HelpfulYesTotal)
                .Set(x => x.ProductReviewHelpfulnessEntries, productReview.ProductReviewHelpfulnessEntries);

            await _productReviewRepository.UpdateOneAsync(x => x.Id == productReview.Id, update);

            //event notification
            await _mediator.EntityUpdated(productReview);
        }

        /// <summary>
        /// Deletes a product review
        /// </summary>
        /// <param name="productReview">Product review</param>
        public virtual async Task DeleteProductReview(ProductReview productReview)
        {
            ArgumentNullException.ThrowIfNull(productReview);

            await _productReviewRepository.DeleteAsync(productReview);

            //event notification
            await _mediator.EntityDeleted(productReview);
        }


        /// <summary>
        /// Gets product review
        /// </summary>
        /// <param name="productReviewId">Product review identifier</param>
        /// <returns>Product review</returns>
        public virtual Task<ProductReview> GetProductReviewById(string productReviewId)
        {
            return _productReviewRepository.GetByIdAsync(productReviewId);
        }

    }
}
