<?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\Product\Model\Product;
use CpCreation\VitiCore\Product\Model\ProductDegressive;
use CpCreation\VitiCore\Product\Model\ProductPrice;
use CpCreation\VitiCore\Product\Model\ProductType;
use CpCreation\VitiCore\Product\Repository\ProductDegressiveRepository;
use CpCreation\VitiCore\Product\Repository\ProductTypeRepository;
use CpCreation\VitiCore\Shop\Model\ShopConfig;
use CpCreation\VitiCore\Shop\Repository\ShopConfigRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class CalculDegressive
{
    private $productDegressiveRepository;
    private $productTypeRepository;
    private $request;
    private $session;
    private $shopConfigRepository ;

    public function __construct(
        ProductDegressiveRepository $productDegressiveRepository,
        ProductTypeRepository $productTypeRepository,
        RequestStack $request,
        SessionInterface $session,
        ShopConfigRepository $shopConfigRepository
    ) {
        $this->productDegressiveRepository = $productDegressiveRepository;
        $this->productTypeRepository       = $productTypeRepository;
        $this->request                     = $request;
        $this->session                     = $session;
        $this->shopConfigRepository                = $shopConfigRepository;

    }

    /**
     * @param Cart $cart
     * @return float|int|null
     * @throws \Doctrine\ORM\NonUniqueResultException
     * @throws \Exception
     */
    public function calcul(Cart $cart)
    {
        $degressiveTotal  = 0;
        $totalAmount      = 0;
        $items            = $cart->getItems();
        $equivalencyQty   = 0;
        $allPricesVariant = [];
        $priceGroupId     = $this->session->get("groupPrice", null);
        $types            = [];

        /** @var CartItem $item */
        foreach ($items as $item) {
            $id = $item->getVariant()->getType()->getId()->toString();
            if (isset($types[$id])) {
                $types[$id] = $types[$id] + $item->getQuantity();
            } else {
                $types[$id] = $item->getQuantity();
            }

            $equivalencyQty = $equivalencyQty + ($item->getVariant()->getType()->getEquivalencyDegressive() * $item->getQuantity());
        }
        $shopConfig = $this->shopConfigRepository->findOne();
        if ($shopConfig->isDegrissivityByItem()) {
            foreach ($items as $item) {
                $degressiveByEquivalency = $this->productDegressiveRepository->findByQuantityAndByItemAndByGroup($equivalencyQty, $item, $priceGroupId);
                if ($degressiveByEquivalency) {
                    if ($degressiveByEquivalency->getBottlePrice() || $degressiveByEquivalency->getPackagePrice()) {
                        if ($degressiveByEquivalency->getBottlePrice()) {
                            $degressiveTotal = $degressiveTotal + $degressiveByEquivalency->getBottlePrice() * $item->getQuantity();
                        } else {
                            $degressiveTotal = $degressiveTotal + $degressiveByEquivalency->getPackagePrice();
                        }
                    }

                    if ($degressiveByEquivalency->getPackagePercent()) {
                        $degressiveTotal = $degressiveTotal + ($totalAmount * $degressiveByEquivalency->getPackagePercent());
                    }
                }
            }
        } else {
            $typeDefault = $this->productTypeRepository->findDefaultType();
            /** @var ProductDegressive $degressiveByEquivalency */
            $degressiveByEquivalency = $this->productDegressiveRepository->findByQuantityAndByTypeAndByGroupAndByEquivalency($equivalencyQty, $typeDefault->getId()->toString(), $cart, $priceGroupId);
            $maxQuantityInCart = 0;
            if ($degressiveByEquivalency) {

                $equivalencyQty = $cart->getQuantityByProducts($degressiveByEquivalency->getProducts());
                /** @var CartItem $item */
                foreach ($items as $item) {
                    //Calcul total
                    /** @var ProductPrice $price */
                    if ($degressiveByEquivalency->getProducts()->count() === 0 || $degressiveByEquivalency->getProducts()->contains($item->getVariant()->getProduct())) {
                        foreach ($item->getVariant()->getPrices() as $price) {
                            if ($price->getGroup()->getId()->toString() === $priceGroupId) {
                                if ($price->getPriceDiscount()) {
                                    array_push($allPricesVariant, $price->getPriceDiscount());
                                    $totalAmount = $totalAmount + ($price->getPriceDiscount() * $item->getQuantity());
                                } else {
                                    array_push($allPricesVariant, $price->getPrice());
                                    $totalAmount = $totalAmount + ($price->getPrice() * $item->getQuantity());
                                }
                            }
                        }
                    }
                }
                /** @var ArrayCollection<CartItem> $array */
                $array = $items->toArray();
                usort($array, fn($a, $b) => $this->sortByQuantityPriceAndType($a,$b,$typeDefault,$priceGroupId));
                $minPriceVariant = min($allPricesVariant);
                if ($degressiveByEquivalency->getBottlePrice() || $degressiveByEquivalency->getPackagePrice()) {
                    if ($degressiveByEquivalency->getBottlePrice()) {
                        if ($degressiveByEquivalency->isAllQuantity()) {
                            $degressiveTotal = $degressiveTotal + $degressiveByEquivalency->getBottlePrice() * $equivalencyQty;
                        } else {
                            $degressiveTotal = $degressiveTotal + $degressiveByEquivalency->getBottlePrice() * ($equivalencyQty - $degressiveByEquivalency->getQtyOf());
                        }
                    } else {
                        $degressiveTotal = $degressiveTotal + $degressiveByEquivalency->getPackagePrice();
                    }
                }
                if ($degressiveByEquivalency->getPackagePercent()) {
                    $degressiveTotal = $degressiveTotal + ($totalAmount * $degressiveByEquivalency->getPackagePercent());
                }
                if ($degressiveByEquivalency->getQtyOfBottleOffered()) {
                    $numberBottleOffered = (floor($equivalencyQty / ($degressiveByEquivalency->getQtyOf() + 1)) * $degressiveByEquivalency->getQtyOfBottleOffered());
                    if($degressiveByEquivalency->isMostOrderBottleInCart()){
                        $degressiveTotal     = $degressiveTotal + ($array[0]->getVariant()->getPriceByGroupId($priceGroupId)->getPrice() * $numberBottleOffered);
                    } else {
                        $degressiveTotal     = $degressiveTotal + ($minPriceVariant * $numberBottleOffered);
                    }

                }
            } else {

                $degressives     = $this->productDegressiveRepository->findAll();

                $degressiveArray = [];
                /** @var ProductDegressive $degressive */
                foreach ($degressives as $degressive) {
                    $iteratorTypes = $degressive->getTypes()->getIterator();
                    $iteratorTypes->uasort(function (ProductType $first, ProductType $second) {
                        return ((string)$first->getSlug() > (string)$second->getSlug()) ? 1 : -1;
                    });
                    $types            = implode(
                        ',', array_map(function (ProductType $type) {
                            return $type->getSlug();
                        }, $iteratorTypes->getArrayCopy())
                    );
                    $iteratorProducts = $degressive->getProducts()->getIterator();
                    $iteratorProducts->uasort(function (Product $first, Product $second) {
                        return ((string)$first->getSlug() > (string)$second->getSlug()) ? 1 : -1;
                    });
                    $products = implode(
                        ',', array_map(function (Product $product) {
                            return $product->getSlug();
                        }, $iteratorProducts->getArrayCopy())
                    );
                    $types    = $types.'-'.$products;
                    if (!isset($degressiveArray[$types])) {
                        $typeCollection = new ArrayCollection();
                        foreach ($iteratorTypes->getArrayCopy() as $iteratorElement) {
                            if (!$typeCollection->contains($iteratorElement)) {
                                $typeCollection->add($iteratorElement);
                            }
                        }
                        $degressiveArray[$types]['types']     = $typeCollection;
                        $degressiveArray[$types]['quantity']  = 0;
                        $degressiveArray[$types]['amount']    = 0;
                        $degressiveArray[$types]['productIn'] = $degressive->getProducts();
                    } else {
                        if ($degressiveArray[$types]['productIn']->isEmpty()) {
                            $degressiveArray[$types]['productIn'] = $degressive->getProducts();
                        }
                    }
                }
                foreach ($items as $item) {
                    foreach ($degressiveArray as $key => $degressiveElem) {
                        if (($degressiveElem['productIn']->count() === 0 && $degressiveElem['types']->contains($item->getVariant()->getType()) || $degressiveElem['productIn']->contains($item->getVariant()->getProduct())) && $degressiveElem['types']->contains($item->getVariant()->getType())) {
                            $degressiveArray[$key]['quantity'] = $degressiveArray[$key]['quantity'] + ($item->getQuantity() * $item->getVariant()->getType()->getEquivalencyDegressive());
                            foreach ($item->getVariant()->getPrices() as $price) {
                                if ($price->getGroup()->getId()->toString() === $priceGroupId) {
                                    if ($price->getPriceDiscount()) {
                                        $degressiveArray[$key]['amount'] = $degressiveArray[$key]['amount'] + ($price->getPriceDiscount() * $item->getQuantity());
                                    } else {
                                        $degressiveArray[$key]['amount'] = $degressiveArray[$key]['amount'] + ($price->getPrice() * $item->getQuantity());
                                    }
                                }
                            }
                        }
                    }
                }
                foreach ($degressiveArray as $key => $degressiveElem) {
                    $degressiveEm = $this->productDegressiveRepository->findOneByTypesAndProductsAndQuantity($degressiveElem['types'], $degressiveElem['productIn'], $degressiveArray[$key]['quantity'], $priceGroupId);
                    if ($degressiveEm) {
                        if ($degressiveEm->getBottlePrice() || $degressiveEm->getPackagePrice()) {
                            if ($degressiveEm->getBottlePrice()) {
                                if ($degressiveEm->isAllQuantity()) {
                                    $degressiveTotal = $degressiveTotal + $degressiveEm->getBottlePrice() * $degressiveArray[$key]['quantity'];
                                } else {
                                    $degressiveTotal = $degressiveTotal + $degressiveEm->getBottlePrice() * ($degressiveArray[$key]['quantity'] - $degressiveEm->getQtyOf());
                                }
                            } else {
                                $degressiveTotal = $degressiveTotal + $degressiveEm->getPackagePrice();
                            }
                        }
                        if ($degressive->getPackagePercent()) {
                            $degressiveTotal = $degressiveTotal + ($degressiveArray[$key]['amount'] * $degressiveEm->getPackagePercent());
                        }
                        if($degressiveEm->getQtyOfBottleOffered())
                        {
                            $array = $items->toArray();
                            usort($array, fn($a, $b) => $this->sortByQuantityPriceAndType($a,$b,$typeDefault,$priceGroupId));
                            $quantityOfBottles = 0;
                            foreach ($array as $item) {
                                if($item->getVariant()->getType()->getName() == $typeDefault->getName()) {
                                    $quantityOfBottles = $quantityOfBottles + $item->getQuantity();
                                }
                            }
                            $degressiveTotal = $degressiveTotal + ($array[0]->getVariant()->getPriceByGroupId($priceGroupId)->getPrice() * floor($quantityOfBottles / $degressiveEm->getQtyOf()));
                        }
                    }
                }
            }
        }
        if ($degressiveTotal > 0) {
            return $degressiveTotal;
        }

        return null;
    }

    public function sortByQuantityPriceAndType($a, $b, $typeDefault, $priceGroupId) {
        $aIsTypeDefault = $a->getVariant()->getType()->getName() == $typeDefault->getName();
        $bIsTypeDefault = $b->getVariant()->getType()->getName() == $typeDefault->getName();

        if ($aIsTypeDefault && !$bIsTypeDefault) {
            return -1;
        } elseif (!$aIsTypeDefault && $bIsTypeDefault) {
            return 1;
        } elseif ($aIsTypeDefault && $bIsTypeDefault) {
            $aEquivQuantity = $a->getQuantity() * $a->getVariant()->getType()->getEquivalencyFreeShipping();
            $bEquivQuantity = $b->getQuantity() * $b->getVariant()->getType()->getEquivalencyFreeShipping();

            if ($aEquivQuantity > $bEquivQuantity) {
                return -1;
            } elseif ($aEquivQuantity < $bEquivQuantity) {
                return 1;
            } else {
                $aPrice = $a->getVariant()->getPriceByGroupId($priceGroupId)->getPrice();
                $bPrice = $b->getVariant()->getPriceByGroupId($priceGroupId)->getPrice();

                if ($aPrice < $bPrice) {
                    return -1;
                } else {
                    return 1;
                }
            }
        } else {
            return 0;
        }
    }
}


