<?php
/**
 * @author Colinet Julien
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils;

use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\CartItem;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\Product\Model\ProductPrice;
use CpCreation\VitiCore\Product\Model\ProductType;
use CpCreation\VitiCore\Product\Repository\ProductPriceGroupRepository;
use CpCreation\VitiCore\Product\Repository\ProductTaxRepository;
use CpCreation\VitiCore\Product\Repository\ProductTypeRepository;
use CpCreation\VitiCore\Shop\Model\DeliveryMethod;
use CpCreation\VitiCore\Shop\Model\ShippingAdditional;
use CpCreation\VitiCore\Shop\Model\ShippingConfig;
use CpCreation\VitiCore\Shop\Model\ShippingCountry;
use CpCreation\VitiCore\Shop\Model\ShippingPrice;
use CpCreation\VitiCore\Shop\Model\ShopConfigMultiple;
use CpCreation\VitiCore\Shop\Repository\ShippingAdditionalManualRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingAdditionalRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingAutoRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingAutoSupRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingConfigRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingCountryRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingCountyRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingPriceRepository;
use CpCreation\VitiCore\Shop\Repository\ShippingZoneRepository;
use CpCreation\VitiCore\Shop\Repository\ShopConfigMultipleRepository;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Intl\Countries;
use Symfony\Contracts\Translation\TranslatorInterface;
use CpCreation\VitiCore\Product\Repository\ProductPriceCodeRepository;

class CalculShipping
{
    private $productPriceGroupRepository;
    private $productPriceCodeRepository;
    private $shippingConfigRepository;
    private $productTypeRepository;
    private $cartRepository;
    private $productTaxRepository;
    private $shippingCountryRepository;
    private $shippingCountyRepository;
    private $shippingPriceRepository;
    private $shippingAutoRepository;
    private $shippingAutoSupRepository;
    private $shippingAdditionalRepository;
    private $shippingAdditionalManualRepository;
    private $shippingZoneRepository;
    private $shopConfigMultipleRepository;
    private $translator;
    private $request;
    private $locale;
    private $session;

    public function __construct(
        ProductPriceGroupRepository        $productPriceGroupRepository,
        ProductPriceCodeRepository         $productPriceCodeRepository,
        ShippingConfigRepository           $shippingConfigRepository,
        ProductTypeRepository              $productTypeRepository,
        CartRepository                     $cartRepository,
        ProductTaxRepository               $productTaxRepository,
        ShippingCountryRepository          $shippingCountryRepository,
        ShippingCountyRepository           $shippingCountyRepository,
        ShippingPriceRepository            $shippingPriceRepository,
        ShippingAutoRepository             $shippingAutoRepository,
        ShippingAutoSupRepository          $shippingAutoSupRepository,
        ShippingAdditionalManualRepository $shippingAdditionalManualRepository,
        ShippingAdditionalRepository       $shippingAdditionalRepository,
        ShippingZoneRepository             $shippingZoneRepository,
        ShopConfigMultipleRepository       $shopConfigMultipleRepository,
        TranslatorInterface                $translator,
        RequestStack                       $request,
        SessionInterface                   $session
    )
    {
        $this->productPriceGroupRepository = $productPriceGroupRepository;
        $this->shippingConfigRepository = $shippingConfigRepository;
        $this->productTypeRepository = $productTypeRepository;
        $this->cartRepository = $cartRepository;
        $this->productTaxRepository = $productTaxRepository;
        $this->shippingCountryRepository = $shippingCountryRepository;
        $this->shippingCountyRepository = $shippingCountyRepository;
        $this->shippingPriceRepository = $shippingPriceRepository;
        $this->shippingAutoRepository = $shippingAutoRepository;
        $this->shippingAutoSupRepository = $shippingAutoSupRepository;
        $this->shippingAdditionalRepository = $shippingAdditionalRepository;
        $this->shippingAdditionalManualRepository = $shippingAdditionalManualRepository;
        $this->shippingZoneRepository = $shippingZoneRepository;
        $this->shopConfigMultipleRepository = $shopConfigMultipleRepository;
        $this->translator = $translator;
        $this->request = $request;
        $this->locale = $session->get('_locale');
        $this->session = $session;
        $this->productPriceCodeRepository = $productPriceCodeRepository;
    }

    /**
     * @param Cart $cart
     * @return array
     * @throws \Doctrine\ORM\NonUniqueResultException
     * @throws \Exception
     */
    public function shippingTotalPrice(Cart $cart)
    {
        $items = $cart->getItems();
        $totalAmount = 0;
        /** @var DeliveryMethod $deliveryMethod */
        $deliveryMethod = $cart->getDeliveryMethod();
        if ($cart->getDeliveryAddress()->isDifferentAddress()) {
            $codePostal = $cart->getDeliveryAddress()->getPostalCode();
            $city = $cart->getDeliveryAddress()->getCity();
            $countryCode = $cart->getDeliveryAddress()->getCountry();
        } else {
            $codePostal = $cart->getInvoiceAddress()->getPostalCode();
            $city = $cart->getInvoiceAddress()->getCity();
            $countryCode = $cart->getInvoiceAddress()->getCountry();
        }

        $priceGroupId = $this->session->get("groupPrice", null);
        $priceGroup  = $this->productPriceGroupRepository->find($priceGroupId);
        $codePriceId = $this->session->get("codePrice", null);
        if ($codePriceId !== null) {
            $codePrice = $this->productPriceCodeRepository->find($codePriceId);
        } else {
            $codePrice = null;
        }

        $types = [];
        //Calcul total for Shipping Free > Amount and QuantitMaxType by Cart
        /** @var CartItem $item */
        foreach ($items as $item) {
            /** @var ProductPrice $price */
            foreach ($item->getVariant()->getPrices() as $price) {
                if ($price->getGroup()->getId()->toString() === $priceGroupId) {
                    if ($price->getPriceDiscount()) {
                        $totalAmount = $totalAmount + ($price->getPriceDiscount() * $item->getQuantity());
                    } else {
                        $totalAmount = $totalAmount + ($price->getPrice() * $item->getQuantity());
                    }
                }
            }
            if (!in_array($item->getVariant()->getType(), $types, true)) {
                $types[] = $item->getVariant()->getType();
            }
            if ($item->getQuantity() > 0 && $item->getVariant()->getType()->getMaximumQuantityCart() > 0 && $item->getQuantity() > $item->getVariant()->getType()->getMaximumQuantityCart()) {
                $messages = $this->translator->trans(
                        'shop.error.quantity_type_override_max', [
                            '%quantity%' => $item->getVariant()->getType()->getMaximumQuantityCart(),
                            '%product%' => $item->getVariant()->getProduct()->getFullName(),
                            '%type%' => $item->getVariant()->getType()->getName(),
                        ]
                        , null, $this->locale
                    ) . '<br/>';
                throw new \Exception($messages);
            }
            $saleSinceStockAt = $this->cartRepository->stockSaleSinceStockAt($item->getVariant())[0]['quantitySale'];
            if ($saleSinceStockAt && (($item->getQuantity() + $saleSinceStockAt) > $item->getVariant()->getStock())) {
                $messages = $this->translator->trans(
                        'shop.error.quantity_type_sold_out', [
                            '%stock%' => $item->getVariant()->getStock() - $saleSinceStockAt,
                            '%quantity%' => $item->getQuantity(),
                            '%product%' => $item->getVariant()->getProduct()->getFullName(),
                            '%type%' => $item->getVariant()->getType()->getName(),
                        ]
                        , null, $this->locale
                    ) . '<br/>';
                throw new \Exception($messages);
            }
        }

        /** @var ShippingConfig $shippingConfig */
        $shippingConfig = $this->shippingConfigRepository->findOne();
        if ($shippingConfig && $shippingConfig->getAmountFreeShipping()) {
            if ($totalAmount >= $shippingConfig->getAmountFreeShipping()) {

                return ['amount' => 0, 'shippingName' => null];
            }
        }

        $amountMarginBank = 0;

        if ($shippingConfig->getAmountMarginBank()) {
            $amountMarginBank = $shippingConfig->getAmountMarginBank();
        }

        // Toujours indiquer un type par default pour le calcul des frais de ports offert par nombre de bouteille
        $typeDefault = $this->productTypeRepository->findDefaultType();
        $taxDefault = $this->productTaxRepository->findOneBy(['byDefault' => true]);
        $quantities = [];
        $quantitiesManu = [];
        $quantitiesMinCart = [];
        $quantitiesMinCart1 = [];
        $quantitiesFreeShipping = [];
        $typesFreeShipping = [];
        $freeShippingWithBottle = [];
        $minFreeShippingWithBottle = [];
        $zonesFreeShippingWithBottle = [];
        $fdpSupp = ceil(($totalAmount * $shippingConfig->getMarginBank()) + $amountMarginBank);
        $fdp = null;
        $fdpTypeMarge = 0;
        $fdpTypeMargeWithoutMarge = 0;
        $fdpPrivateMargePercent = 0;
        $fdpPrivateMarge = 0;
        $fdpTypeMargeTotal = 0;
        $fdpTypeMargeWithoutMargeTotal = 0;
        $fdpManu = 0;
        $quantityAllAbsolute = 0;
        $quantityEquivalenceOff = 0;
        $quantityEquivalenceDefault = 0;
        $equivalencies = '';
        $shippingName = '';
        $typeName = [];
        $equivalenceAuto = 0;
        /** @var ProductType $type */
        $quantitiesMinCart[$typeDefault->getSlug()] = 0;
        $quantitiesMinCart1[$typeDefault->getSlug()] = 0;
        $quantities[$typeDefault->getSlug()] = 0;
        $quantitiesManu[$typeDefault->getSlug()] = 0;
        $freeShippingWithBottle[$typeDefault->getSlug()] = false;
        $minFreeShippingWithBottle[$typeDefault->getSlug()] = null;
        $quantitiesFreeShipping[$typeDefault->getSlug()] = 0;
        $zonesFreeShippingWithBottle[$typeDefault->getSlug()] = [];
        $disabledShippingAuto[$typeDefault->getSlug()] = false;
        $disabledShippingManu[$typeDefault->getSlug()] = false;
        foreach ($types as $type) {
            $quantitiesMinCart[$type->getSlug()] = 0;
            $quantitiesMinCart1[$type->getSlug()] = 0;
            $zonesFreeShippingWithBottle[$type->getSlug()] = $type->getZonesFreeShippingId();
            if (!$type->isEquivalencyOnShipping()) {
                $quantities[$type->getSlug()] = 0;
                $quantitiesManu[$type->getSlug()] = 0;
                $equivalencies .= $type->getSlug() . ' = ' . $type->getEquivalency() . ' ' . $typeDefault->getSlug() . '<br/>';
            }
            if ($type->isEquivalencyOnFreeShipping()) {
                $typesFreeShipping[] = $type->getSlug();
            }
            if ($type->isFreeShippingWithBottle()) {
                $freeShippingWithBottle[$type->getSlug()] = true;
                $minFreeShippingWithBottle[$type->getSlug()] = $type->getMinFreeShippingWithBottle();
            } else {
                $freeShippingWithBottle[$type->getSlug()] = false;
                $minFreeShippingWithBottle[$type->getSlug()] = null;
            }
            if ($type->isDisabledShippingManu()) {
                $disabledShippingManu[$type->getSlug()] = true;
            } else {
                $disabledShippingManu[$type->getSlug()] = false;
            }
            if ($type->isDisabledShippingAuto()) {
                $disabledShippingAuto[$type->getSlug()] = true;
            } else {
                $disabledShippingAuto[$type->getSlug()] = false;
            }
        }


        /** @var CartItem $item */
        foreach ($items as $item) {
            // utile pour savoir la quantité d'un contenant pour vérifier la quantité minimum autorisé de ce contenant dans le panier
            //$quantitiesMinCart[$item->getVariant()->getType()->getSlug()] = $quantitiesMinCart[$item->getVariant()->getType()->getSlug()] + $item->getQuantity();
            if ($item->getVariant()->getType()->isEquivalencyOnFreeShipping()) {
                $quantitiesFreeShipping[$typeDefault->getSlug()] = $quantities[$typeDefault->getSlug()] + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalencyFreeShipping());
            }
            if ($item->getVariant()->getType()->isEquivalencyOnShipping()) {
                //Tout transformer en équivalence bouteille
                $quantities[$typeDefault->getSlug()] = $quantities[$typeDefault->getSlug()] + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalency());
                $quantitiesManu[$typeDefault->getSlug()] = $quantitiesManu[$typeDefault->getSlug()] + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalencyManu());
                $quantityEquivalenceDefault = $quantityEquivalenceDefault + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalencyManu());
            } else {
                $quantities[$item->getVariant()->getType()->getSlug()] = $quantities[$item->getVariant()->getType()->getSlug()] + $item->getQuantity();
                $quantitiesManu[$item->getVariant()->getType()->getSlug()] = $quantitiesManu[$item->getVariant()->getType()->getSlug()] + $item->getQuantity();
            }
            if ($item->getVariant()->getType()->isEquivalencyDefaultQuantity()) {
                $quantitiesMinCart[$typeDefault->getSlug()] = $quantitiesMinCart[$typeDefault->getSlug()] + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalency());
            } else {
                $quantitiesMinCart[$item->getVariant()->getType()->getSlug()] = $quantitiesMinCart[$item->getVariant()->getType()->getSlug()] + $item->getQuantity();
            }
            if ($item->getVariant()->getType()->isEquivalencyDefault()) {
                $quantityEquivalenceDefault = $quantityEquivalenceDefault + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalencyManu());
            }

            $quantityEquivalenceOff = $quantityEquivalenceOff + $item->getQuantity();

            if (!$disabledShippingAuto[$item->getVariant()->getType()->getSlug()] && !$item->getVariant()->getType()->isAccessory()) {
                $equivalenceAuto = $equivalenceAuto + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalency());
            }

            if (!$item->getVariant()->getType()->isAccessory()) {
                $quantityAllAbsolute = $quantityAllAbsolute + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalency());
            }
        }

        if ($shippingConfig->getQtyEquivalencyBottle()) {
            if ($quantityAllAbsolute > $shippingConfig->getQtyEquivalencyBottle()) {
                $quantities = [];
                $quantitiesManu = [];
                $quantities[$typeDefault->getSlug()] = $quantityAllAbsolute;
                $quantitiesManu[$typeDefault->getSlug()] = $quantityAllAbsolute;
            }
        }

        /** @var ShippingCountry $country */
        $country = $this->shippingCountryRepository->findOneByGroup($countryCode, $priceGroupId);
        $county = null;
        $zone = null;
        if ($country) {
            if ($country->isCounty()) {
                $department = substr($codePostal, 0, 2);
                $county = $this->shippingCountyRepository->findDepartmentByCountry($department, $country->getCode());
            }

            $zone = $this->shippingZoneRepository->findByCountryAndByCounty($country, $county);
        }

        //Validation de la quantité ( ex: vendu par 6 seulement )
        $messages = null;
        $shopConfigMultiple = null;

        if ((!$country && !$deliveryMethod) || (!$country && $deliveryMethod->getShippingPrices()->count() > 0)) {
            throw new \Exception($this->translator->trans('shop.error.error_country', [], null, $this->locale));
        }

        if (($country && !$deliveryMethod) || ($country && $deliveryMethod->getShippingPrices()->count() > 0)) {
            if ($country->isCounty()) {
                if (!$codePostal) {
                    throw new \Exception($this->translator->trans('shop.error.postal_code', [], null, $this->locale));
                }
            }
        }

        if ($items->count() < 1) {
            throw new \Exception($this->translator->trans('shop.empty_cart', [], null, $this->locale));
        }

        $typesbySlug = array_map(function (ProductType $type) {
            return $type->getSlug();
        }, $types);
        if (!in_array($typeDefault->getSlug(), $typesbySlug)) {
            $types[] = $typeDefault;
        }

        if (!$deliveryMethod || !$deliveryMethod->isMultipleVariant()) {
            /** @var ProductType $type */
            foreach ($types as $type) {
                $typeName[$type->getSlug()] = $type->getName();
                if (!$messages) {
                    $messages = '';
                }
                $typeMultipleQuantityCart = $type->getMultipleQuantityCart();
                if ($zone) {
                    /** @var ShopConfigMultiple $shopConfigMultiple */
                    $shopConfigMultiple = $this->shopConfigMultipleRepository->findByQuantityAndByTypeAndByZone($quantitiesMinCart[$type->getSlug()], $type->getSlug(), $zone);
                    if ($shopConfigMultiple) {
                        $typeMultipleQuantityCart = $shopConfigMultiple->getMultiple();
                    }
                }

                if ($type->getOrderWithaMinimumEquivalency() && ($type->getOrderWithaMinimumEquivalency() > $quantityAllAbsolute)) {
                    $messages .= $this->translator->trans(
                            'shop.error.quantity_type_min_equivalency', [
                                '%min%' => $type->getOrderWithaMinimumEquivalency(),
                                '%type%' => $type->getName(),
                            ]
                            , null, $this->locale
                        ) . '<br/>';
                }

                if (($quantitiesMinCart[$type->getSlug()] % $typeMultipleQuantityCart) > 0) {

                    if ($shopConfigMultiple) {
                        if ($shopConfigMultiple->isMinimum()) {
                            $messages .= $this->translator->trans(
                                    'shop.error.quantity_type_override_min', [
                                        '%quantity%' => $typeMultipleQuantityCart,
                                        '%type%' => $type->getName(),
                                    ]
                                    , null, $this->locale
                                ) . '<br/>';
                        } else {
                            $messages .= $this->translator->trans(
                                    'shop.error.quantity_type_override', [
                                        '%quantity%' => $typeMultipleQuantityCart,
                                        '%min%' => $shopConfigMultiple->getQtyOf(),
                                        '%max%' => $shopConfigMultiple->getQtyAt(),
                                        '%type%' => $type->getName(),
                                    ]
                                    , null, $this->locale
                                ) . '<br/>';
                        }

                    } else {
                        $messages .= $this->translator->trans(
                                'shop.error.quantity_type', [
                                    '%quantity%' => $typeMultipleQuantityCart,
                                    '%type%' => $type->getName(),
                                ]
                                , null, $this->locale
                            ) . '<br/>';
                    }

                }

            }

            if ($messages) {
                throw new \Exception($messages);
            }
        }

        $messages = '';
        $county = null;

        if ($country) {
            if ($country->isCounty()) {
                $department = substr($codePostal, 0, 2);
                $county = $this->shippingCountyRepository->findDepartmentByCountry($department, $country->getCode());
                if (!$county && !$deliveryMethod) {
                    throw new \Exception($this->translator->trans('shop.error.empty_shipping', [], null, $this->locale));
                }
            }

            if ($country->getMinQty() && $country->getMultiple() && !$deliveryMethod) {
                if ((($quantitiesMinCart[$typeDefault->getSlug()] % $country->getMultiple()) > 0) || ($quantitiesMinCart[$typeDefault->getSlug()] < $country->getMinQty())) {
                    $message = $this->translator->trans(
                            'shop.error.error_country_qty', [
                            '%multiple%' => $country->getMultiple(),
                            '%quantity%' => $country->getMinQty(),
                            '%type%' => $typeDefault->getName(),
                            '%country%' => Countries::getName($country->getCode()),
                        ], null, $this->locale
                        ) . '<br/>';
                    throw new \Exception($message);
                }
            }
        }

        // Autres modes de livraisons
        if ($deliveryMethod) {
            $errorProducts = [];
            $errorProductsMultiple = [];
            $errorQuantityType = [];
            /** @var CartItem $item */
            foreach ($items as $item) {
                if ($deliveryMethod->isMultipleVariant()) {
                    if ($item->getVariant()->getType()->getMultipleQuantityDepot() > 0) {
                        if (($item->getQuantity() % $item->getVariant()->getType()->getMultipleQuantityDepot()) > 0) {
                            $errorQuantityType[] = [
                                "type" => $item->getVariant()->getType()->getName(),
                                "quantity" => $item->getVariant()->getType()->getMultipleQuantityDepot(),
                            ];
                        }
                    }
                }
                if ($deliveryMethod->getProductVariants()->count() > 0) {
                    if (!$deliveryMethod->getProductVariants()->contains($item->getVariant())) {
                        $errorProducts[] = $item->getVariant()->getName();
                    }
                }
            }
            if (count($errorProducts) > 0) {
                $messages .= $this->translator->trans('shop.error.error_product_delivery_method', ['%products%' => implode(", ", $errorProducts)], null, $this->locale) . '<br/>';
            } else {
                if (count($errorQuantityType) > 0) {
                    foreach ($errorQuantityType as $errorQuantity) {
                        $messages .= $this->translator->trans(
                                'shop.error.error_product_delivery_method_quantity_variant', [
                                '%type%' => $errorQuantity['type'],
                                '%quantity%' => $errorQuantity['quantity'],
                            ], null, $this->locale
                            ) . '<br/>';
                    }
                }
            }
            if ($deliveryMethod->getShippingPrices()->count() === 0) {
                if ($deliveryMethod->getQtyAt() > $quantityAllAbsolute) {
                    $messages .= $this->translator->trans('shop.delivery_method.error_qty', [], null, $this->locale) . '<br/>';
                }
                if (!$deliveryMethod->getCounties()->contains($county) && $deliveryMethod->isViewCounties()) {
                    $messages .= $this->translator->trans('shop.delivery_method.error_county', [], null, $this->locale) . '<br/>';
                }
                if (!empty($messages)) {

                    throw new \Exception($messages);
                }
                if ($deliveryMethod->getPackagePrice() >= 0 && !is_null($deliveryMethod->getPackagePrice())) {

                    return ['amount' => $deliveryMethod->getPackagePrice(), 'shippingName' => null];
                }

                if ($deliveryMethod->getBottlePrice()) {
                    if ($deliveryMethod->isDisabledEquivalence()) {
                        return [
                            'amount' => $deliveryMethod->getBottlePrice() * $quantityEquivalenceOff,
                            'shippingName' => null,
                        ];
                    }

                    return [
                        'amount' => $deliveryMethod->getBottlePrice() * $quantityAllAbsolute,
                        'shippingName' => null,
                    ];
                }
            }
        }

        //Deprécié, à supprimer 
        /* $freesShipping = $this->shippingPriceRepository->findFreesShippingByGroup($priceGroupId, $type);
         if ($freesShipping) {
             if ($quantitiesFreeShipping[$typeDefault->getSlug()] > $freesShipping->getQtyOf()) {
                 foreach ($typesFreeShipping as $typeFreeShipping) {
                     unset($quantities[$typeFreeShipping]);
                 }
             }
         }*/

        $equivalence = 0;
        //Manual
        /** @var ShippingConfig $shippingConfig */
        $shippingConfig = $this->shippingConfigRepository->findOne();
        $i = 0;
        $zoneTest = null;
        $quantitiesManu = array_reverse($quantitiesManu);
        $errorTypes = [];
        if ($country->isCounty() && $equivalenceAuto > 0 && $shippingConfig->isForceEquivalencyForAuto()) {
            $equivalenceAutoShipping = $this->shippingPriceRepository->findByQuantityAndByTypeAndByZoneAndByGroup($equivalenceAuto, $typeDefault->getSlug(), $county->getZone(), $priceGroupId, $deliveryMethod, $codePrice);

            if (!$equivalenceAutoShipping) {
                foreach ($quantitiesManu as $type => $quantity) {
                    if (!$disabledShippingAuto[$type]) {
                        unset($quantitiesManu[$type]);
                    }
                }
                $equivalence = $equivalenceAuto;
            }
        }

        foreach ($quantitiesManu as $type => $quantity) {
            if ($quantity > 0 && $disabledShippingManu[$type] == false) {

                /** @var ShippingPrice $shippingPrice */
                if ($country->isCounty()) {
                    $shippingPrice = $this->shippingPriceRepository->findByQuantityAndByTypeAndByZoneAndByGroupAndByPriceCode($quantity, $type, $county->getZone(), $priceGroupId, $deliveryMethod, $codePrice);

                    if ($i === 0) {
                        $zoneTest = $county->getZone()->getId()->toString();
                    }

                } else {
                    foreach ($country->getZones() as $zone) {
                        $shippingPrice = $this->shippingPriceRepository->findByQuantityAndByTypeAndByZoneAndByGroupAndByPriceCode($quantity, $type, $zone, $priceGroupId, $deliveryMethod, $codePrice);

                        if ($shippingPrice) {
                            if ($i === 0) {
                                $zoneTest = $zone->getId()->toString();
                            }
                            break;
                        }
                    }
                }

                if ($shippingPrice) {
                    $shippingName = $shippingPrice->getNameCarrier();
                    //throw new \Exception($this->translator->trans('shop.error.missing_shipping'));
                    if ($freeShippingWithBottle[$type] && (!$minFreeShippingWithBottle || $quantityEquivalenceDefault >= $minFreeShippingWithBottle[$type]) && in_array($zoneTest, $zonesFreeShippingWithBottle[$type])) {
                        $fdpType = 0;
                    } else {
                        if ($shippingPrice->getBottlePrice()) {
                            $fdpType = $shippingPrice->getBottlePrice() * $quantity;
                        } else {
                            $fdpType = $shippingPrice->getPackagePrice();
                        }

                        if ($shippingPrice->getPrivateMargePercent() > 0) {
                            $fdpPrivateMargePercent = ceil($fdpType * $shippingPrice->getPrivateMargePercent());
                        }
                        if ($shippingPrice->getPrivateMarge() > 0) {
                            $fdpPrivateMarge = $shippingPrice->getPrivateMarge();
                        }
                    }

                    $fdpType = $fdpType + $fdpPrivateMargePercent + $fdpPrivateMarge;

                    if ($shippingPrice->isConfigGlobal()) {
                        $fdpTypeMarge = $fdpType;
                    } else {
                        $fdpTypeMargeWithoutMarge = $fdpType;
                    }

                    //Somme des transports incluant la marge global
                    $fdpTypeMargeTotal = $fdpTypeMargeTotal + $fdpTypeMarge;
                    // Somme des transports n'incluant pas la marge global
                    $fdpTypeMargeWithoutMargeTotal = $fdpTypeMargeWithoutMargeTotal + $fdpTypeMargeWithoutMarge;
                    unset($quantitiesManu[$type]);
                    unset($quantities[$type]);
                    $fdp = 0;
                } else {
                    if ($deliveryMethod) {

                        throw new \Exception($this->translator->trans('shop.error.missing_shipping_delivery_method', [], null, $this->locale));
                    }
                    if ($quantity > 0 && $disabledShippingAuto[$type] == true) {
                        $errorTypes[] = $typeName[$type] . ' x' . $quantity;
                    }
                    $productType = $this->productTypeRepository->findTypeBySlug($type);

                    // calcul de l'équivalence restant pour calcul Auto
                    $equivalence = $equivalence + ($quantity * $productType->getEquivalency());
                    unset($quantitiesManu[$type]);
                    if ($typeDefault->getSlug() !== $type) {
                        unset($quantities[$type]);
                    }

                }
            } else {
                if ($quantity > 0 && $disabledShippingAuto[$type] == false) {
                    //rajouter à l'équivalence bouteille si pas de frais de port trouvé pour ce type
                    $productType = $this->productTypeRepository->findTypeBySlug($type);
                    if ($type != $typeDefault->getSlug()) {
                        $quantitiesManu[$typeDefault->getSlug()] = $quantitiesManu[$typeDefault->getSlug()] + ($quantity * $productType->getEquivalency());
                    }
                    // calcul de l'équivalence restant pour calcul Auto
                    $equivalence = $equivalence + ($quantity * $productType->getEquivalency());

                } else {
                    if ($quantity > 0 && $disabledShippingAuto[$type] == true) {
                        $errorTypes[] = $typeName[$type] . ' x' . $quantity;
                    }
                }
            }

            $i++;
        }

        if (count($errorTypes) > 0) {
            throw new \Exception($this->translator->trans('shop.error.error_product_delivery_method_standard', ['%types%' => implode(", ", $errorTypes)], null, $this->locale) . '<br/>');
        }

        if ($fdpTypeMargeTotal > 0) {
            if ($shippingConfig->getAmountFixedManu() > 0) {
                $fdpTypeMargeTotal = $fdpTypeMargeTotal + $shippingConfig->getAmountFixedManu();
            }

            if ($shippingConfig->getAmountMinVDManu() > 0 && $quantityAllAbsolute >= $shippingConfig->getQtyMinVDManu()) {
                $taxeVD = round(($fdpTypeMargeTotal + $totalAmount) * $shippingConfig->getMarginManu(), 2);
                if ($taxeVD < $shippingConfig->getAmountMinVDManu()) {
                    $taxeVD = $shippingConfig->getAmountMinVDManu();
                }
                $fdpTypeMargeTotal = $fdpTypeMargeTotal + $taxeVD;
            }
            if ($shippingConfig->getMarginClientManu() > 0) {
                $fdpTypeMargeTotal = $fdpTypeMargeTotal + round($fdpTypeMargeTotal * $shippingConfig->getMarginClientManu(), 2);
            }
        }

        if (!$priceGroup->isViewHT()) {
            if ($shippingConfig->getTvaManu() > 0) {
                $fdpManu = ($fdpTypeMargeTotal * (1 + $shippingConfig->getTvaManu())) + $fdpTypeMargeWithoutMargeTotal;
            } else {
                $fdpManu = $fdpTypeMargeTotal + $fdpTypeMargeWithoutMargeTotal;
            }
        } else {
            $fdpManu = $fdpTypeMargeTotal + $fdpTypeMargeWithoutMargeTotal;
        }

        if ($shippingConfig->getAmountByBottleTTC() > 0) {
            $fdpManu = $fdpManu + ($shippingConfig->getAmountByBottleTTC() * ($quantityAllAbsolute - $equivalence));
        }

        foreach ($quantitiesMinCart as $key => $quantityByType) {
            foreach ($country->getZones() as $zone) {
                $shippingAdditional = $this->shippingAdditionalManualRepository->findByQuantityAndByTypeAndByZoneAndByGroup($quantityByType, $key, $zone, $priceGroupId);
                if ($shippingAdditional) {
                    $fdpShippingAdditionnal = $shippingAdditional->getPackagePrice() ? $shippingAdditional->getPackagePrice() : $shippingAdditional->getBottlePrice() * $quantityByType;
                    if ($shippingConfig->getTvaManu() > 0 && $shippingAdditional->isHt()) {
                        $fdpManu = $fdpManu + ($fdpShippingAdditionnal * (1 + $shippingConfig->getTvaManu()));
                    } else {
                        $fdpManu = $fdpManu + $fdpShippingAdditionnal;
                    }

                    break;
                }
            }
        }

        //Auto
        $searchByHm = false;

        $shippingSup = $this->shippingAutoSupRepository->findOneBy(
            [
                'country' => $country->getCode(),
                'county' => $county ? $county->getCode() : null,
                'city' => $city,
            ]
        );
        if ($shippingSup) {
            $searchByHm = true;
        }

        if (count($quantities) > 0 && $equivalence > 0) {
            $fdp = 0;
            if ($country->isCounty()) {
                $shippingPrice = $this->shippingAutoRepository->findByQuantityAndByCountyAndByCountry($equivalence, $county->getCode(), $country->getCode(), $searchByHm);
                if (!$shippingPrice) {
                    $searchByHm = false;
                    $shippingPrice = $this->shippingAutoRepository->findByQuantityAndByCountyAndByCountry($equivalence, $county->getCode(), $country->getCode());
                }
            } else {
                $shippingPrice = $this->shippingAutoRepository->findByQuantityAndByCountry($equivalence, $country->getCode());
            }

            if (!$shippingPrice) {
                throw new \Exception($this->translator->trans('shop.error.missing_shipping', [], null, $this->locale));
            }

            if ($shippingPrice) {
                //throw new \Exception($this->translator->trans('shop.error.missing_shipping'));
                if ($shippingPrice->getBottlePrice()) {
                    $fdp = $fdp + ($shippingPrice->getBottlePrice() * $equivalence);
                } else {
                    $fdp = $fdp + $shippingPrice->getPackagePrice();
                }
                //Taxe VD
                if ($shippingConfig->getAmountPercentVDAuto() && $equivalence >= $shippingConfig->getQtyMinVDAuto()) {
                    $fdpVD = round(($totalAmount / (1 + $taxDefault->getValue())) * $shippingConfig->getAmountPercentVDAuto(), 2);

                    if ($shippingConfig->getAmountMinVDAuto() && $fdpVD < $shippingConfig->getAmountMinVDAuto()) {
                        $fdpVD = $shippingConfig->getAmountMinVDAuto();
                    }
                    $fdp = $fdp + $fdpVD;
                    if ($shippingConfig->getAmountVDAuto() > 0) {
                        $fdp = $fdp + $shippingConfig->getAmountVDAuto();
                    }

                }

                $fdp = $fdp + $shippingConfig->getAmountFixedBeforeMargeAuto();
                unset($quantities);
            }
            $shippingSup = $this->shippingAutoSupRepository->findOneBy(
                [
                    'country' => $country->getCode(),
                    'county' => $county ? $county->getCode() : null,
                    'city' => $city,
                ]
            );

            if ($shippingSup && !$searchByHm) {
                $fdp = $fdp + $shippingConfig->getHighMountainAmount();
            }
            //Taxe avant Gazole
            $fdp = ceil($fdp + ($fdp * $shippingConfig->getMarginAuto()));
            //Taxe Gazole
            $fdp = ceil($fdp + ($fdp * $shippingConfig->getMarginGazoleAuto()));
            //Taxe Après Gazole
            $fdp = ceil($fdp + ($fdp * $shippingConfig->getMarginClientAuto()));
            $fdp = $fdp + $shippingConfig->getAmountFixedAuto();

            $shippingName = $shippingConfig->getCarrier();
        }

        if (is_null($fdp)) {
            throw new \Exception($this->translator->trans('shop.error.calcul', [], null, $this->locale));
        }
        if ($country->isCounty()) {
            $shippingAdditionals = $this->shippingAdditionalRepository->findByQuantityAndByCountyAndByGroup($equivalence, $county->getCode(), $priceGroupId);
            /** @var ShippingAdditional $shippingAdditional */
            foreach ($shippingAdditionals as $shippingAdditional) {

                $fdp = $fdp + $shippingAdditional->getPrice();
            }
        }
        
        if($fdp + $fdpManu == 0){
            $fdpSupp = 0;
        }

        //fdpSupp = Marge banque
        if ($priceGroup->isViewHT()) {
            $shipping = $fdp + $fdpManu + $fdpSupp;

            return ['amount' => $shipping, 'shippingName' => $shippingName];
        }
        $fdpTVA = round($fdp * (1 + $taxDefault->getValue()), 2) + $fdpManu;
        $shipping = $fdpTVA + $fdpSupp;

        if ($shippingConfig->getAmountAutoByBottleTTC() > 0) {
            $shipping = $fdpTVA + $fdpSupp + ($shippingConfig->getAmountAutoByBottleTTC() * $equivalence);
        }

        return ['amount' => $shipping, 'shippingName' => $shippingName];
    }
}
