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

namespace CpCreation\VitiCore\Bridge\Doctrine\EventSubscriber;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\Mailer;
use CpCreation\VitiCore\Cart\Model\CartCheckout;
use CpCreation\VitiCore\Cart\Model\CartItem;
use CpCreation\VitiCore\Cart\Model\Promo;
use CpCreation\VitiCore\Contact\Model\Contact;
use CpCreation\VitiCore\Product\Model\ProductGift;
use CpCreation\VitiCore\Shop\Model\ShopConfig;
use CpCreation\VitiCore\Shop\Repository\ShopConfigRepository;
use CpCreation\VitiCore\Product\Repository\ProductGiftRepository;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Symfony\Component\HttpFoundation\RequestStack;

class CartCheckoutSubscriber implements EventSubscriber
{
    private $request;
    private $mailer;
    private $shopConfigRepository;
    private $productGiftRepository;

    /**
     * CartCheckoutSubscriber constructor.
     * @param RequestStack $request
     * @param Mailer       $mailer
     */
    public function __construct(RequestStack $request, Mailer $mailer, ShopConfigRepository $shopConfigRepository, ProductGiftRepository $productGiftRepository)
    {
        $this->request              = $request;
        $this->mailer               = $mailer;
        $this->shopConfigRepository = $shopConfigRepository;
        $this->productGiftRepository = $productGiftRepository;
    }

    public function getSubscribedEvents()
    {

        return [
            Events::prePersist,
            Events::postUpdate,
            Events::onFlush,
        ];
    }

    /**
     * @param LifecycleEventArgs $event
     */
    public function prePersist(LifecycleEventArgs $event)
    {
        $entity = $event->getObject();
        if ($entity instanceof CartCheckout) {
            $entity->setLocale($this->request->getCurrentRequest()->getLocale());
            $entity->setIpClient($this->request->getMasterRequest()->getClientIp());
        }
    }

    /**
     * @param LifecycleEventArgs $event
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException@
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     */
    public function postUpdate(LifecycleEventArgs $event)
    {
        $entity = $event->getObject();
        $em     = $event->getEntityManager();
        if ($entity instanceof CartCheckout) {
            if ($entity->getPayedAt()) {

                $promoText = $entity->getCart()->getPromo();
                /** @var Promo $promo */
                $promo = $em->getRepository(Promo::class)->findOneBy(['title' => $promoText]);
                /** @var ProductGift $gift */
                $gift = $em->getRepository(ProductGift::class)->findOneBy(['token' => $promoText]);
                if ($promo) {
                    $promo->setCount($promo->getCount() + 1);
                    $em->persist($promo);
                    $em->flush();
                } else if ($gift){
                    $gift->setUsedAt(new DateTime('now'));
                    $em->persist($gift);
                    $em->flush();
                }
            }
            if ($entity->isDelivery() && !$entity->getDeletedAt() && !$entity->isDisabled()) {
                $contact = $em->getRepository(Contact::class)->findOne();
                $this->mailer->senDelivery($contact, $entity->getCart());
            }
        }
    }


    public function onFlush(OnFlushEventArgs $eventArgs)
    {

        $em  = $eventArgs->getEntityManager();
        $uow = $em->getUnitOfWork();
        $uow->computeChangeSets();
        $hasGift = false;
        foreach ($uow->getScheduledEntityUpdates() as $key => $entity) {
            if ($entity instanceof CartCheckout) {
                $changes = $uow->getEntityChangeSet($entity);
                if (isset($changes['payedAt']) && $changes['payedAt'][1] != null) {
                    $items = $entity->getCart()->getItems();
                    $cartCheckoutPayedAt = DateTime::createFromInterface($entity->getPayedAt());
                    $shopConfig = $this->shopConfigRepository->findOne();
                    if($shopConfig->getGiftCardValidTime() != null){
                        $cartCheckoutPayedAt->add($shopConfig->getGiftCardValidTime());
                    } else {
                        $defaultDateInterval = new \DateInterval('P12M');
                        $cartCheckoutPayedAt->add($defaultDateInterval);
                    }
                    /** @var CartItem $item */
                    foreach ($items as $item) {
                        if ($item->getVariant()->getType()->isGift()) {
                            for ($i = 0; $i < $item->getQuantity(); $i++) {
                                /** @var ProductGift $gift */
                                $gift = new ProductGift();
                                /** @var ShopConfig $shopConfig */
                                $gift->setValidUntilDate($cartCheckoutPayedAt);
                                $item->addGift($gift);
                                $metadata = $em->getClassMetadata(get_class($item));
                                $uow->computeChangeSet($metadata, $item);
                                $uow->persist($item);
                                $hasGift = true;
                            }
                        }
                    }
                    if ($hasGift) {
                        $contact = $em->getRepository(Contact::class)->findOne();
                        $this->mailer->sendGiftCard($contact, $entity->getCart());
                        $cart = $entity->getCart();
                        $giftUsed = $this->productGiftRepository->findGiftFromCart($cart);
                        $giftUsed->setUsedAt(new \DateTime());
                        $em->persist($giftUsed);
                    }
                }
                if (isset($changes['payedAt']) && $changes['payedAt'][1] == null) {
                    $items = $entity->getCart()->getItems();
                    /** @var CartItem $item */
                    foreach ($items as $item) {
                        if ($item->getVariant()->getType()->isGift()) {
                            foreach ($item->getGifts() as $gift) {
                                $em->remove($gift);
                            }
                        }
                    }
                }
            }
        }
    }
}
