using NetinaShop.Domain.Entities.Discounts;

namespace NetinaShop.Repository.Handlers.Products;

public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, List<ProductSDto>>
{
    private readonly IRepositoryWrapper _repositoryWrapper;

    public GetProductsQueryHandler(IRepositoryWrapper repositoryWrapper)
    {
        _repositoryWrapper = repositoryWrapper;
    }
    public async Task<List<ProductSDto>> Handle(GetProductsQuery request, CancellationToken cancellationToken)
    {
        var products = _repositoryWrapper.SetRepository<Product>().TableNoTracking;
        if (request.CategoryId != default)
            products = products.Where(p => p.CategoryId == request.CategoryId);
        if (request.BrandId != default)
            products = products.Where(p => p.BrandId == request.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
            };
        }

        var productSDtos = await products.Skip(request.Page * 10)
            .Take(10)
            .Select(ProductMapper.ProjectToSDto)
            .ToListAsync(cancellationToken);

        foreach (var productSDto in productSDtos)
        {
            double discountPrice = 0;
            productSDto.CostWithDiscount = productSDto.Cost;
            var categoryDiscount = await _repositoryWrapper.SetRepository<CategoryDiscount>()
                .TableNoTracking
                .FirstOrDefaultAsync(d => d.CategoryId == productSDto.CategoryId && d.HasCode == false && d.ExpireDate.Date > DateTime.Today.Date, cancellationToken);

            if (categoryDiscount != null && !categoryDiscount.IsExpired())
            {
                var totalPrice = productSDto.Cost;
                discountPrice = categoryDiscount.AmountType == DiscountAmountType.Amount
                ? totalPrice - categoryDiscount.DiscountAmount : totalPrice - ((totalPrice / 100) * categoryDiscount.DiscountAmount);
                productSDto.CostWithDiscount = productSDto.CostWithDiscount - discountPrice;
                productSDto.HasDiscount = true;
                productSDto.DiscountPercent = (100 * productSDto.CostWithDiscount) / productSDto.Cost;
            }

            var productDiscount = await _repositoryWrapper.SetRepository<ProductDiscount>()
                .TableNoTracking
                .FirstOrDefaultAsync(d => d.HasCode == false && d.ProductId == productSDto.Id && d.ExpireDate.Date > DateTime.Today.Date, cancellationToken);

            if (productDiscount != null && !productDiscount.IsExpired())
            {
                var totalPrice = productSDto.Cost;
                discountPrice = productDiscount.AmountType == DiscountAmountType.Amount
                ? totalPrice - productDiscount.DiscountAmount
                    : totalPrice - ((totalPrice / 100) * productDiscount.DiscountAmount);

                productSDto.CostWithDiscount = productSDto.CostWithDiscount - discountPrice;
                productSDto.HasDiscount = true;
                productSDto.DiscountPercent = (100 * productSDto.CostWithDiscount) / productSDto.Cost;
            }

        }

        return productSDtos;
    }
}