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

namespace Grand.Business.Catalog.Services.Products;

/// <summary>
///     Product reservation service
/// </summary>
public class ProductReservationService : IProductReservationService
{
    private readonly IRepository<CustomerReservationsHelper> _customerReservationsHelperRepository;
    private readonly IMediator _mediator;
    private readonly IRepository<ProductReservation> _productReservationRepository;

    public ProductReservationService(
        IRepository<ProductReservation> productReservationRepository,
        IRepository<CustomerReservationsHelper> customerReservationsHelperRepository,
        IMediator mediator)
    {
        _productReservationRepository = productReservationRepository;
        _customerReservationsHelperRepository = customerReservationsHelperRepository;
        _mediator = mediator;
    }


    /// <summary>
    ///     Gets product reservations for product Id
    /// </summary>
    /// <param name="productId">Product Id</param>
    /// <param name="showVacant">Show vacant</param>
    /// <param name="date">Date</param>
    /// <param name="pageIndex">Page index</param>
    /// <param name="pageSize">Page size</param>
    /// <returns>Product reservations</returns>
    public virtual async Task<IPagedList<ProductReservation>> GetProductReservationsByProductId(string productId,
        bool? showVacant, DateTime? date,
        int pageIndex = 0, int pageSize = int.MaxValue)
    {
        var query = _productReservationRepository.Table.Where(x => x.ProductId == productId);

        if (showVacant.HasValue)
            query = showVacant.Value
                ? query.Where(x => x.OrderId == "" || x.OrderId == null)
                : query.Where(x => x.OrderId != "" && x.OrderId != null);

        if (date.HasValue)
        {
            var min = new DateTime(date.Value.Year, date.Value.Month, date.Value.Day, 0, 0, 0, 0);
            var max = new DateTime(date.Value.Year, date.Value.Month, date.Value.Day, 23, 59, 59, 999);

            query = query.Where(x => x.Date >= min && x.Date <= max);
        }

        query = query.OrderBy(x => x.Date);
        return await PagedList<ProductReservation>.Create(query, pageIndex, pageSize);
    }

    /// <summary>
    ///     Adds product reservation
    /// </summary>
    /// <param name="productReservation">Product reservation</param>
    public virtual async Task InsertProductReservation(ProductReservation productReservation)
    {
        ArgumentNullException.ThrowIfNull(productReservation);

        await _productReservationRepository.InsertAsync(productReservation);

        //event
        await _mediator.EntityInserted(productReservation);
    }

    /// <summary>
    ///     Updates product reservation
    /// </summary>
    /// <param name="productReservation">Product reservation</param>
    public virtual async Task UpdateProductReservation(ProductReservation productReservation)
    {
        ArgumentNullException.ThrowIfNull(productReservation);

        await _productReservationRepository.UpdateAsync(productReservation);

        //event
        await _mediator.EntityUpdated(productReservation);
    }

    /// <summary>
    ///     Deletes a product reservation
    /// </summary>
    /// <param name="productReservation">Product reservation</param>
    public virtual async Task DeleteProductReservation(ProductReservation productReservation)
    {
        ArgumentNullException.ThrowIfNull(productReservation);

        await _productReservationRepository.DeleteAsync(productReservation);

        //event
        await _mediator.EntityDeleted(productReservation);
    }

    /// <summary>
    ///     Gets product reservation for specified Id
    /// </summary>
    /// <param name="id">Product ident</param>
    /// <returns>Product reservation</returns>
    public virtual Task<ProductReservation> GetProductReservation(string id)
    {
        return _productReservationRepository.GetByIdAsync(id);
    }

    /// <summary>
    ///     Adds customer reservations helper
    /// </summary>
    /// <param name="crh"></param>
    public virtual async Task InsertCustomerReservationsHelper(CustomerReservationsHelper crh)
    {
        ArgumentNullException.ThrowIfNull(crh);

        await _customerReservationsHelperRepository.InsertAsync(crh);

        //event
        await _mediator.EntityInserted(crh);
    }

    /// <summary>
    ///     Deletes customer reservations helper
    /// </summary>
    /// <param name="crh"></param>
    public virtual async Task DeleteCustomerReservationsHelper(CustomerReservationsHelper crh)
    {
        ArgumentNullException.ThrowIfNull(crh);

        await _customerReservationsHelperRepository.DeleteAsync(crh);

        //event
        await _mediator.EntityDeleted(crh);
    }


    /// <summary>
    ///     Cancel reservations by orderId
    /// </summary>
    /// <param name="orderId"></param>
    public virtual async Task CancelReservationsByOrderId(string orderId)
    {
        if (!string.IsNullOrEmpty(orderId))
            await _productReservationRepository.UpdateManyAsync(x => x.OrderId == orderId,
                UpdateBuilder<ProductReservation>.Create().Set(x => x.OrderId, ""));
    }

    /// <summary>
    ///     Gets customer reservations helper by id
    /// </summary>
    /// <param name="id"></param>
    /// <returns>CustomerReservationsHelper</returns>
    public virtual Task<CustomerReservationsHelper> GetCustomerReservationsHelperById(string id)
    {
        return _customerReservationsHelperRepository.GetByIdAsync(id);
    }

    /// <summary>
    ///     Gets customer reservations helpers
    /// </summary>
    /// <returns>
    ///     List<CustomerReservationsHelper />
    /// </returns>
    public virtual async Task<IList<CustomerReservationsHelper>> GetCustomerReservationsHelpers(string customerId)
    {
        return await Task.FromResult(_customerReservationsHelperRepository.Table.Where(x => x.CustomerId == customerId)
            .ToList());
    }

    /// <summary>
    ///     Gets customer reservations helper by Shopping Cart Item id
    /// </summary>
    /// <param name="sciId">sci ident</param>
    /// <returns>
    ///     IList<CustomerReservationsHelper />
    /// </returns>
    public virtual async Task<IList<CustomerReservationsHelper>> GetCustomerReservationsHelperBySciId(string sciId)
    {
        return await Task.FromResult(_customerReservationsHelperRepository.Table
            .Where(x => x.ShoppingCartItemId == sciId).ToList());
    }
}