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

namespace CpCreation\VitiCore\Bridge\Doctrine\EventSubscriber;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\CalculDegressive;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\CalculShipping;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\Promo;
use CpCreation\VitiCore\Product\Model\Product;
use CpCreation\VitiCore\Product\Model\ProductGift;
use CpCreation\VitiCore\Product\Model\ProductPriceCode;
use CpCreation\VitiCore\Product\Model\ProductPriceGroup;
use CpCreation\VitiCore\Product\Model\ProductTax;
use CpCreation\VitiCore\Shop\Model\ShippingCountry;
use CpCreation\VitiCore\Shop\Model\ShippingCounty;
use CpCreation\VitiCore\Shop\Model\ShippingZone;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Events;
use Hautelook\AliceBundle\Functional\TestBundle\Entity\Prod;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\SessionInterface;

class CartSubscriber implements EventSubscriber
{
    private $requestStack;
    private $calculDegressive;
    private $calculShipping;
    private $session;

    public function __construct(RequestStack $requestStack,
        CalculDegressive $calculDegressive,
        CalculShipping $calculShipping,
        SessionInterface $session
    ) {
        $this->requestStack     = $requestStack;
        $this->calculDegressive = $calculDegressive;
        $this->calculShipping   = $calculShipping;
        $this->session          = $session;
    }

    public function getSubscribedEvents()
    {

        return [
            Events::prePersist,
            Events::preUpdate,
            Events::postPersist,
            Events::postUpdate,
        ];
    }

    /**
     * @param LifecycleEventArgs $event
     */
    public function prePersist(LifecycleEventArgs $event)
    {
        $entity        = $event->getObject();
        $entityManager = $event->getEntityManager();
        if ($entity instanceof Cart) {
            $taxDefault = $entityManager->getRepository(ProductTax::class)->findOneBy(['byDefault' => true]);
            if (!$entity->getDeliveryAddress()->isDifferentAddress()) {
                $invoiceAddress = $entity->getInvoiceAddress();
                $entity->getDeliveryAddress()->setPostalCode($invoiceAddress->getPostalCode());
                $entity->getDeliveryAddress()->setLastname($invoiceAddress->getLastname());
                $entity->getDeliveryAddress()->setFirstname($invoiceAddress->getFirstname());
                $entity->getDeliveryAddress()->setCity($invoiceAddress->getCity());
                $entity->getDeliveryAddress()->setCountry($invoiceAddress->getCountry());
                $entity->getDeliveryAddress()->setStreet($invoiceAddress->getStreet());
            }

            if ($this->session->get('groupPrice')) {
                $groupPrice = $entityManager->getRepository(ProductPriceGroup::class)->findOneBy(['id' => $this->session->get('groupPrice')]);
                $codePrice  = $entityManager->getRepository(ProductPriceCode::class)->findOneBy(['id' => $this->session->get('codePrice')]);
                if ($groupPrice->isViewHT()) {
                    $entity->setViewHT(true);
                }
                if ($codePrice) {
                    $entity->setGroupCode($codePrice->getCode());
                }
                $entity->setTax($taxDefault->getValue());
            }
        }
    }

    /**
     * @param LifecycleEventArgs $event
     */
    public function preUpdate(LifecycleEventArgs $event)
    {
        $entity        = $event->getObject();
        $entityManager = $event->getEntityManager();
        if ($entity instanceof Cart) {
            $taxDefault = $entityManager->getRepository(ProductTax::class)->findOneBy(['byDefault' => true]);
            if (!$entity->getDeliveryAddress()->isDifferentAddress()) {
                $invoiceAddress = $entity->getInvoiceAddress();
                $entity->getDeliveryAddress()->setPostalCode($invoiceAddress->getPostalCode());
                $entity->getDeliveryAddress()->setLastname($invoiceAddress->getLastname());
                $entity->getDeliveryAddress()->setFirstname($invoiceAddress->getFirstname());
                $entity->getDeliveryAddress()->setCity($invoiceAddress->getCity());
                $entity->getDeliveryAddress()->setCountry($invoiceAddress->getCountry());
                $entity->getDeliveryAddress()->setStreet($invoiceAddress->getStreet());
            }
            if ($this->session->get('groupPrice')) {
                $groupPrice = $entityManager->getRepository(ProductPriceGroup::class)->findOneBy(['id' => $this->session->get('groupPrice')]);
                $codePrice  = $entityManager->getRepository(ProductPriceCode::class)->findOneBy(['id' => $this->session->get('codePrice')]);
                if ($groupPrice->isViewHT()) {
                    $entity->setViewHT(true);
                }
                if ($codePrice) {
                    $entity->setGroupCode($codePrice->getCode());
                }
                $entity->setTax($taxDefault->getValue());
            }
        }
    }

    /**
     * @param LifecycleEventArgs $event
     * @throws \Doctrine\ORM\NonUniqueResultException
     * @throws \Exception
     */
    public function postPersist(LifecycleEventArgs $event)
    {
        $entity = $event->getObject();
        if ($entity instanceof Cart) {

            $entityManager = $event->getEntityManager();
            $entity        = $this->calcul($entityManager, $entity);
            $om            = $event->getObjectManager();
            $om->persist($entity);
            $om->flush();
        }
    }

    /**
     * @param LifecycleEventArgs $event
     * @throws \Doctrine\ORM\NonUniqueResultException
     * @throws \Exception
     */
    public function postUpdate(LifecycleEventArgs $event)
    {
        $entity = $event->getObject();
        if ($entity instanceof Cart) {
            $entityManager = $event->getEntityManager();
            $entity        = $this->calcul($entityManager, $entity);
            $om            = $event->getObjectManager();
            $om->persist($entity);
            $om->flush();
        }
    }

    /**
     * @param EntityManager $entityManager
     * @param Cart          $entity
     * @return Cart
     * @throws \Doctrine\ORM\NonUniqueResultException
     * @throws \Exception
     */
    private function calcul(EntityManager $entityManager, Cart $entity)
    {

        $entity->setPromoValueAmount(null);
        $entity->setPromoValuePercent(null);
        $entity->setPromoWithShippingFees(false);
        $groupPrice = $this->session->get('groupPrice');

        /** @var Promo $promo */
        $promo = $entityManager->getRepository(Promo::class)->findPromoActivWithCode($entity, $groupPrice);

        if (!$promo) {
            /** @var Promo $promo */
            $promo = $entityManager->getRepository(Promo::class)->findPromoActivAutoWithGroup($entity, $groupPrice);
        }
        /** @var ProductGift $gift */
        $gift = $entityManager->getRepository(ProductGift::class)->findGiftFromCart($entity);

        if ($promo) {
            if ($promo->getZones()->count() > 0) {
                /** @var ShippingCountry $country */
                $country = $entityManager->getRepository(ShippingCountry::class)->findOneByGroup($entity->getDeliveryAddress()->getCountry(), $groupPrice);
                $county  = null;
                if ($country->isCounty()) {
                    $department = substr($entity->getDeliveryAddress()->getPostalCode(), 0, 2);
                    $county     = $entityManager->getRepository(ShippingCounty::class)->findDepartmentByCountry($department, $country->getCode());
                }
                $zone  = $entityManager->getRepository(ShippingZone::class)->findByCountryAndByCounty($country, $county);
                $promo = $entityManager->getRepository(Promo::class)->findPromoActivWithCode($entity, $groupPrice, $zone);
                if (!$promo) {
                    /** @var Promo $promo */
                    $promo = $entityManager->getRepository(Promo::class)->findPromoActivAutoWithGroup($entity, $groupPrice, $zone);
                }
            }
            if ($promo) {
                $amount  = 0;
                $percent = 0;
                if ($promo->getProducts()->count() > 0) {
                    /** @var Product $product */
                    foreach ($promo->getProducts() as $key => $product) {
                        $quantity = $entity->getQuantityByProducts($promo->getProducts());
                    }
                } else {
                    $quantity = $entity->getQuantityAllAbsolute();
                }
                if ((!$promo->getMaxCount() || ($promo->getCount() < $promo->getMaxCount())) && (!$promo->getMinEquivalency() || ($promo->getMinEquivalency() <= $quantity))) {
                    $countByUser = $entityManager->getRepository(Cart::class)->countPromoByUser($promo, $entity);
                    if (!$promo->getMaxCountByCustomer() || ($promo->getMaxCountByCustomer() > count($countByUser))) {
                        if ($promo->getAmount()) {
                            $amount = $promo->getAmount();
                            if ($promo->isMultipleByQuantity())
                            {
                                $amount = $promo->getAmount() * ($quantity/$promo->getMinEquivalency());
                            }
                        }
                        if ($promo->getPercentShippingCost()) {
                            $shippingCost = $this->calculShipping->shippingTotalPrice($entity);
                            $amount = $amount + round($shippingCost['amount'] * $promo->getPercentShippingCost());
                        }
                        if ($promo->getPercent()) {
                            if ($promo->isIncludeShippingFees()) {
                                $entity->setPromoWithShippingFees(true);
                                $shippingCost = $this->calculShipping->shippingTotalPrice($entity);
                                $amount       = $amount + round(($entity->getItemsTotal() + $shippingCost['amount']) * $promo->getPercent());
                            } else {
                                $percent = $promo->getPercent();

                            }
                        }
                        $entity->setPromo($promo->getTitle());
                        $entity->setPromoId($promo->getId());
                    }
                }
                if ($percent > 0) {
                    $entity->setPromoValuePercent($percent);
                }
                if ($amount > 0) {
                    $entity->setPromoValueAmount($amount);
                }
            }

        } else {
            $entity->setPromo(null);
            $entity->setPromoId(null);
        }

        if($gift){
            $entity->setPromo($gift->getToken());
            $entity->setPromoValueAmount($gift->getCartItem()->getPrice());
        }

        $degressiveTotal = $this->calculDegressive->calcul($entity);

        if ($degressiveTotal > 0) {
            $entity->setDegressiveValue($degressiveTotal);
        } else {
            $entity->setDegressiveValue(null);
        }

        return $entity;
    }
}
