using Microsoft.EntityFrameworkCore;

namespace NetinaShop.Repository.Handlers.Products;

public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProductsResponseDto>
{
    private readonly IRepositoryWrapper _repositoryWrapper;
    private readonly IMediator _mediator;

    public GetProductsQueryHandler(IRepositoryWrapper repositoryWrapper, IMediator mediator)
    {
        _repositoryWrapper = repositoryWrapper;
        _mediator = mediator;
    }
    public async Task<GetProductsResponseDto> Handle(GetProductsQuery request, CancellationToken cancellationToken)
    {
        var response = new GetProductsResponseDto();
        var products = _repositoryWrapper.SetRepository<Product>().TableNoTracking;
        if (request.IsActive != null)
            products = products.Where(p => p.IsEnable == request.IsActive);
        if (request.ProductName != null)
            products = products.Where(p => p.PersianName.ToLower().Trim().Contains(request.ProductName.ToLower().Trim()));
        if (request.CategoryId != default)
        {
            var cats = await _mediator.Send(new GetProductCategoryChildrenQuery(request.CategoryId), cancellationToken);
            products = products.Where(p => cats.Contains(p.CategoryId));
        }
        if (request.BrandIds is { Length: > 0 })
            products = products.Where(p => request.BrandIds.Contains(p.BrandId));
        if (request.MinPrice > -1)
            products = products.Where(p => p.Cost >= request.MinPrice);
        if (request.MaxPrice > 0)
            products = products.Where(p => p.Cost <= request.MaxPrice);
        if (request.SortBy != QuerySortBy.None)
        {
            products = request.SortBy switch
            {
                QuerySortBy.Cheapest => products.OrderBy(p => p.Cost),
                QuerySortBy.MostExpensive => products.OrderByDescending(p => p.Cost),
                QuerySortBy.MostPopular => products.OrderByDescending(p => p.Rate),
                QuerySortBy.MostViewed => products.OrderByDescending(p => p.Viewed),
                _ => products
            };
        }
        else
        {
            products = products.OrderByDescending(p => p.CreatedAt);
        }

        if (request.SpecialOffer != null)
        {
            if (request.SpecialOffer.Value)
            {
                var productDiscount = await _repositoryWrapper.SetRepository<ProductDiscount>()
                .TableNoTracking
                    .Where(d => d.HasCode == false && d.IsSpecialOffer && d.ExpireDate.Date >= DateTime.Today.Date)
                    .OrderByDescending(d => d.CreatedAt)
                .Select(d => d.ProductId)
                    .ToListAsync(cancellationToken);

                products = products.Where(p => productDiscount.Contains(p.Id));
            }
        }

        response.Pager.CurrentPage = request.Page;
        response.Pager.TotalItems = await products.CountAsync(cancellationToken);
        response.Pager.TotalPage = response.Pager.TotalItems % 20 == 0 ? response.Pager.TotalItems / 20 : (response.Pager.TotalItems / 20) + 1;

        List<ProductSDto> productSDtos = await products
            .Skip(request.Page * 20)
            .Take(20)
            .Select(ProductMapper.ProjectToSDto)
            .ToListAsync(cancellationToken);

        response.Filters.Price.MaximumValue = await products.MaxAsync(p => p.Cost,cancellationToken);
        response.Filters.Price.MinimumValue = await products.MinAsync(p => p.Cost,cancellationToken);



        foreach (var productSDto in productSDtos)
        {
            await _mediator.Send(new CalculateProductDiscountCommand(productSDto), cancellationToken);
        }

        response.Products = productSDtos;
        return response;
    }
}