using NetinaShop.Domain.Dtos.LargDtos;
using NetinaShop.Domain.Dtos.SmallDtos;

namespace NetinaShop.Core.EntityServices.DiscountHandlers;

public class CalculateProductDiscountCommandHandler : IRequestHandler<CalculateProductDiscountCommand, bool>
{
    private readonly IRepositoryWrapper _repositoryWrapper;

    public CalculateProductDiscountCommandHandler(IRepositoryWrapper repositoryWrapper)
    {
        _repositoryWrapper = repositoryWrapper;
    }


    public async Task<bool> Handle(CalculateProductDiscountCommand request, CancellationToken cancellationToken)
    {
        if (request.Product is ProductSDto product)
        {
            await CalculateAsync(product, cancellationToken);
        }else if (request.Product is ProductLDto productLDto)
        {
            await CalculateAsync(productLDto, cancellationToken);
        }
        else
            throw new AppException("Model is wrong , ProductSDto or ProductLDto");
        return true;
    }

    public async Task<ProductSDto> CalculateAsync(ProductSDto request, CancellationToken cancellationToken)
    {
        double discountPrice = 0;
        request.CostWithDiscount = request.Cost;
        double totalPrice = request.Cost;

        var allDiscount = await _repositoryWrapper.SetRepository<Discount>()
            .TableNoTracking
            .FirstOrDefaultAsync(d => d.Type == DiscountType.All && d.HasCode == false && d.ExpireDate.Date >= DateTime.Today.Date, cancellationToken);

        if (allDiscount != null && !allDiscount.IsExpired())
        {

            discountPrice = allDiscount.AmountType == DiscountAmountType.Amount ? totalPrice - allDiscount.DiscountAmount :
                totalPrice - totalPrice / 100 * allDiscount.DiscountPercent;
            request.HasDiscount = true;
        }

        var categoryDiscount = await _repositoryWrapper.SetRepository<CategoryDiscount>()
        .TableNoTracking
        .FirstOrDefaultAsync(d => d.CategoryId == request.CategoryId && d.HasCode == false && d.ExpireDate.Date >= DateTime.Today.Date, cancellationToken);

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

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

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

            request.HasDiscount = true;
            if (productDiscount.IsSpecialOffer)
                request.IsSpecial = true;
        }

        if (request.HasDiscount)
        {
            request.CostWithDiscount = discountPrice;
            request.DiscountPercent = request.Cost == 0 ? 0 : 100 - 100 * request.CostWithDiscount / request.Cost;
        }

        return request;
    }


    public async Task<ProductLDto> CalculateAsync(ProductLDto request, CancellationToken cancellationToken)
    {
        double discountPrice = 0;
        request.CostWithDiscount = request.Cost;
        double totalPrice = request.Cost;

        var allDiscount = await _repositoryWrapper.SetRepository<Discount>()
            .TableNoTracking
            .FirstOrDefaultAsync(d => d.Type == DiscountType.All && d.HasCode == false && d.ExpireDate.Date >= DateTime.Today.Date, cancellationToken);

        if (allDiscount != null && !allDiscount.IsExpired())
        {

            discountPrice = allDiscount.AmountType == DiscountAmountType.Amount ? totalPrice - allDiscount.DiscountAmount :
                totalPrice - totalPrice / 100 * allDiscount.DiscountPercent;
            request.HasDiscount = true;
        }

        var categoryDiscount = await _repositoryWrapper.SetRepository<CategoryDiscount>()
        .TableNoTracking
        .FirstOrDefaultAsync(d => d.CategoryId == request.CategoryId && d.HasCode == false && d.ExpireDate.Date >= DateTime.Today.Date, cancellationToken);

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

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

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

            request.HasDiscount = true;
            if (productDiscount.IsSpecialOffer)
            {
                request.IsSpecial = true;
                request.SpecialOffer = productDiscount.AdaptToSDto();
            }
        }

        if (request.HasDiscount)
        {
            request.CostWithDiscount = discountPrice;
            request.DiscountPercent = request.Cost == 0 ? 0 : 100 - 100 * request.CostWithDiscount / request.Cost;
        }

        return request;
    }
}