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

namespace CpCreation\VitiCore\Cart\Repository;

use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\CartItem;
use CpCreation\VitiCore\Cart\Model\Promo;
use CpCreation\VitiCore\Product\Model\Product;
use CpCreation\VitiCore\Repository\BaseRepository;
use CpCreation\VitiCore\Shop\Model\ShippingZone;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\Persistence\ManagerRegistry;

class PromoRepository extends BaseRepository
{
    /**
     * PaymentMethodRepository constructor.
     * @param ManagerRegistry $registry
     * @throws \ReflectionException
     */
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Promo::class);
    }

    /**
     * @return mixed
     */
    public function findPromoActiv()
    {
        $qb = $this->createQueryBuilder('p')
                   ->andWhere('p.disabled = FALSE')
                   ->andWhere('p.beginAt < :datetime')
                   ->andWhere('p.auto = FALSE')
                   ->andWhere('p.endAt > :datetime')
                   ->setParameter('datetime', new \DateTime('now'))
                   ->getQuery();

        return $qb->execute();

    }

    /**
     * @param Cart              $cart
     * @param null              $group
     * @param ShippingZone|null $zone
     * @return int|mixed|string
     */
    public function findPromoActivWithCode(Cart $cart, $group = null, ShippingZone $zone = null)
    {
        $arrayItem = [];
        /** @var CartItem $item */
        foreach ($cart->getItems() as $item) {
            $arrayItem[] = $item->getVariant()->getProduct()->getId()->toString();
        }
        $code = strtoupper($cart->getPromo());
        $qb   = $this->createQueryBuilder('p');

        $qb->andWhere('p.disabled = FALSE')
           ->andWhere('p.title = :code')
           ->andWhere('p.beginAt < :datetime')
           ->andWhere('p.endAt > :datetime')
           ->setParameter('datetime', new \DateTime('now'))
           ->setParameter('code', $code);
        $qb->leftjoin('p.products', 'pr');
        $qb->andWhere(
            $qb->expr()->orX(
                $qb->expr()->in('pr.id', "'".implode("','", $arrayItem)."'"),
                $qb->expr()->isNull('pr.id'),
            )
        );
        if ($group) {
            $qb
                ->innerJoin('p.groups', 'gr', Join::WITH, 'gr.id = :group')
                ->setParameter('group', $group);
        }
        if ($zone) {
            $qb->leftjoin('p.zones', 'z');
            $qb->andWhere(
                $qb->expr()->orX(
                    $qb->expr()->eq('z.id', "'".$zone->getId()->toString()."'"),
                    $qb->expr()->isNull('z.id'),
                )
            );
        }

        $query = $qb->getQuery();
        if ($query->getResult()) {
            return $query->getResult()[0];
        } else {
            return $query->getResult();
        }
    }

    /**
     * @param Cart              $cart
     * @param null              $group
     * @param ShippingZone|null $zone
     * @return int|mixed|string
     */
    public function findPromoActivAutoWithGroup(Cart $cart, $group = null, ShippingZone $zone = null)
    {
        $arrayItem = [];
        /** @var CartItem $item */
        foreach ($cart->getItems() as $item) {
            $arrayItem[] = $item->getVariant()->getProduct()->getId()->toString();
        }

        $qb = $this->createQueryBuilder('p');
        $qb->andWhere('p.disabled = FALSE')
           ->andWhere('p.beginAt < :datetime')
           ->andWhere('p.endAt > :datetime')
           ->andWhere('p.auto = TRUE');

        $qb->leftjoin('p.products', 'pr');
        $qb->andWhere(
            $qb->expr()->orX(
                $qb->expr()->lte('p.minEquivalency', $cart->getQuantityAllAbsolute()),
                $qb->expr()->isNull('p.minEquivalency'),
            )
        );
        $qb->andWhere(
            $qb->expr()->orX(
                $qb->expr()->gte('p.maxEquivalency', $cart->getQuantityAllAbsolute()),
                $qb->expr()->isNull('p.maxEquivalency'),
            )
        );
        $qb->andWhere(
            $qb->expr()->orX(
                $qb->expr()->in('pr.id', "'".implode("','", $arrayItem)."'"),
                $qb->expr()->isNull('pr.id')
            )
        );

        $qb->orderBy('p.minEquivalency', 'DESC');
        $qb->setParameter('datetime', new \DateTime('now'));

        if ($group) {
            $qb
                ->innerJoin('p.groups', 'gr', Join::WITH, 'gr.id = :group')
                ->setParameter('group', $group);
        }

        if ($zone) {
            $qb->leftjoin('p.zones', 'z');
            $qb->andWhere(
                $qb->expr()->orX(
                    $qb->expr()->eq('z.id', "'".$zone->getId()->toString()."'"),
                    $qb->expr()->isNull('z.id'),
                )
            );
        }

        $query = $qb->getQuery();

        if ($query->getResult()) {
            /** @var Promo $result */
            foreach ($query->getResult() as $result) {
                $qb2 = $this->createQueryBuilder('p');
                $qb2->andWhere('p.id = :result')
                    ->andWhere('p.minEquivalency <= :quantity');
                $qb2->orderBy('p.minEquivalency', 'DESC');
                $qb2->setParameter('result', $result->getId()->toString())
                    ->setParameter('quantity', $cart->getQuantityByProducts($result->getProducts()));
                $query2 = $qb2->getQuery();
                if ($query2->getResult()) {
                    return $query2->getResult()[0];
                } else {
                    $query2->getResult();
                }
            }
        } else {
            return $query->getResult();
        }
    }

}
