<?php

namespace Lc\CaracoleBundle\Repository\Order;

use App\Entity\Delivery\DeliveryAvailabilityPointSale;
use App\Entity\Delivery\DeliveryAvailabilityZone;
use App\Entity\PointSale\PointSale;
use Knp\Component\Pager\PaginatorInterface;
use Lc\CaracoleBundle\Model\Address\AddressInterface;
use Lc\CaracoleBundle\Model\Order\OrderReductionCartInterface;
use Lc\CaracoleBundle\Model\Order\OrderReductionCreditInterface;
use Lc\CaracoleBundle\Model\User\VisitorInterface;
use Lc\CaracoleBundle\Repository\SectionRepositoryQueryTrait;
use Lc\SovBundle\Model\User\UserInterface;
use Lc\SovBundle\Repository\AbstractRepositoryQuery;
use DateTime;

class OrderShopRepositoryQuery extends AbstractRepositoryQuery
{
    use SectionRepositoryQueryTrait;

    protected $isJoinOrderReductionCredits = false;
    protected $isJoinOrderReductionCarts = false;
    protected $isJoinOrderStatus = false;
    protected $isJoinComplementaryOrderShops = false;
    protected $isJoinDeliveryPointSale = false;
    protected $isJoinDeliveryAvailabilityZone = false;
    protected $isJoinDeliverySlotZone = false;
    protected $isJoinDeliveryAvailabilityPointSale = false;
    protected $isJoinDeliverySlotPointSale = false;
    protected $isHorsTournee = false;
    protected $isGiftVoucher = false;

    public function __construct(OrderShopRepository $repository, PaginatorInterface $paginator)
    {
        parent::__construct($repository, 'r', $paginator);
    }

    public function selectParam($select): self
    {
        return $this
            ->addSelect($select);
    }

    public function selectCount(): self
    {
        return $this
            ->select('count(r.id) as total');
    }

    public function filterByUser(UserInterface $user): self
    {
        return $this
            ->andWhere('.user = :user')
            ->setParameter('user', $user);
    }

    public function filterByDateStart(string $dateField, DateTime $dateStart): self
    {
        return $this
            ->andWhere('.' . $dateField . ' >= :dateStart')
            ->setParameter('dateStart', $dateStart);
    }

    public function filterByDateEnd(string $dateField, DateTime $dateEnd): self
    {
        return $this
            ->andWhere('.' . $dateField . ' <= :dateEnd')
            ->setParameter('dateEnd', $dateEnd);
    }

    public function filterByEstimatedDeliveryDateStart(string $dateStart): self
    {
        return $this
            ->andWhere('.estimatedDeliveryDateTime >= :deliveryDateStart')
            ->setParameter('deliveryDateStart', $dateStart);
    }

    public function filterByEstimatedDeliveryDateEnd(string $dateEnd): self
    {
        return $this
            ->andWhere('.estimatedDeliveryDateTime < :deliveryDateEnd')
            ->setParameter('deliveryDateEnd', $dateEnd);
    }

    public function filterByDeliveryDateStart(string $dateStart): self
    {
        return $this
            ->andWhere('.deliveryDate >= :deliveryDateStart')
            ->setParameter('deliveryDateStart', $dateStart);
    }

    public function filterByDeliveryDateEnd(string $dateEnd): self
    {
        return $this
            ->andWhere('.deliveryDate < :deliveryDateEnd')
            ->setParameter('deliveryDateEnd', $dateEnd);
    }

    public function filterByVisitor(VisitorInterface $visitor): self
    {
        return $this
            ->andWhere('.visitor = :visitor')
            ->setParameter('visitor', $visitor);
    }

    public function filterByAddress(AddressInterface $address): self
    {
        return $this
            ->andWhere('.deliveryAddress = :address OR .invoiceAddress = :address')
            ->setParameter('address', $address);
    }

    public function filterByWeekDeliveryTruck(string $weekDeliveryTrucks): self
    {
        return $this
            ->andWhere('.weekDeliveryTruck IN (:weekDeliveryTrucks)')
            ->setParameter('weekDeliveryTrucks', $weekDeliveryTrucks);
    }

    public function filterByStatus(array $statusArray): self
    {
        $this->joinOrderStatus();

        return $this
            ->andWhere('os.alias IN (:alias)')
            ->setParameter('alias', $statusArray);
    }

    public function filterByReductionCredit(OrderReductionCreditInterface $reductionCredit): self
    {
        $this->joinOrderReductionCredits();

        return $this
            ->andWhere('orc.reductionCredit = :reductionCredit')
            ->setParameter('reductionCredit', $reductionCredit);
    }

    public function filterByReductionCart(OrderReductionCartInterface $reductionCart): self
    {
        $this->joinOrderReductionCarts();

        return $this
            ->andWhere('orcart.reductionCart = :reductionCart')
            ->setParameter('reductionCart', $reductionCart);
    }

    public function filterByAvailabilityPointZone(DeliveryAvailabilityPointSale $deliveryAvailabilityPointSale): self
    {
        return $this
            ->andWhere('.deliveryAvailabilityPointSale = :deliveryAvailabilityPointSale')
            ->setParameter('deliveryAvailabilityPointSale', $deliveryAvailabilityPointSale);
    }

    public function filterByAvailabilityPointSale(DeliveryAvailabilityPointSale $deliveryAvailabilityPointSale): self
    {
        return $this
            ->andWhere('.deliveryAvailabilityPointSale = :deliveryAvailabilityPointSale')
            ->setParameter('deliveryAvailabilityPointSale', $deliveryAvailabilityPointSale);
    }

    public function filterByWeekNumber(int $weekNumber): self
    {
        return $this
            ->andWhere('.weekNumber = :weekNumber')
            ->setParameter('weekNumber', $weekNumber);
    }

    public function filterIsNotMainOrderShop(): self
    {
        return $this
            ->andWhere('.mainOrderShop = false OR  .mainOrderShop IS NULL');
    }

    public function filterIsNullMainOrderShop(): self
    {
        return $this
            ->andWhere('.mainOrderShop IS NULL');
    }

    public function filterIsNullDeliveryPointSale(): self
    {
        $this
            ->joinDeliveryPointSale()
            ->andWhere(
                '.deliveryPointSale IS NULL OR (pointSale.isDepository = 0 AND (pointSale.devAlias IS NULL OR (pointSale.devAlias != :devAliasHorsTournee AND pointSale.devAlias != :devAliasGiftVoucher)))'
            )
            ->setParameterGiftVoucher()
            ->setParameterHorsTournee();

        return $this;
    }

    public function filterIsNotNullDeliveryPointSale(): self
    {
        $this
            ->joinDeliveryPointSale()
            ->andWhere(
                'pointSale IS NOT NULL AND pointSale.isDepository = 1 AND (pointSale.devAlias IS NULL OR (pointSale.devAlias != :devAliasHorsTournee AND pointSale.devAlias != :devAliasGiftVoucher))'
            )
            ->setParameterGiftVoucher()
            ->setParameterHorsTournee();

        return $this;
    }


    public function filterIsPointSale(string $devAlias = 'devAliasHorsTournee'): self
    {
        $this
            ->joinDeliveryPointSale()
            ->andWhere('pointSale IS NOT NULL AND pointSale.devAlias = :' . $devAlias);

        if($devAlias == 'devAliasHorsTournee'){
            $this->setParameterHorsTournee();
        } elseif($devAlias == 'devAliasGiftVoucher') {
            $this->setParameterGiftVoucher();
        }

        return $this;
    }

    public function selectOrderReductionCarts(): self
    {
        $this->joinOrderReductionCarts();

        return $this->addSelect('orcart');
    }

    public function setParameterGiftVoucher(): self
    {
        if (!$this->isGiftVoucher) {
            $this->isGiftVoucher = true;

            return $this
                ->setParameter('devAliasGiftVoucher', PointSale::DEV_ALIAS_GIFT_VOUCHER);
        }
        return $this;
    }

    public function setParameterHorsTournee(): self
    {
        if (!$this->isHorsTournee) {
            $this->isHorsTournee = true;

            return $this
                ->setParameter('devAliasHorsTournee', PointSale::DEV_ALIAS_OFF_CIRCUIT);
        }
        return $this;
    }

    public function joinOrderReductionCredits(): self
    {
        if (!$this->isJoinOrderReductionCredits) {
            $this->isJoinOrderReductionCredits = true;

            return $this
                ->innerJoin('.orderReductionCredits', 'orc');
        }
        return $this;
    }

    public function joinDeliveryAvailabilityZone(): self
    {
        if (!$this->isJoinDeliveryAvailabilityZone) {
            $this->isJoinDeliveryAvailabilityZone = true;

            return $this
                ->leftJoin('.deliveryAvailabilityZone', 'deliveryAvailabilityZone');
        }
        return $this;
    }

    public function joinDeliverySlotZone(): self
    {
        $this->joinDeliveryAvailabilityZone();

        if (!$this->isJoinDeliverySlotZone) {
            $this->isJoinDeliverySlotZone = true;

            return $this
                ->leftJoin('deliveryAvailabilityZone.deliverySlot', 'deliverySlotZone');
        }
        return $this;
    }

    public function joinDeliveryAvailabilityPointSale(): self
    {
        if (!$this->isJoinDeliveryAvailabilityPointSale) {
            $this->isJoinDeliveryAvailabilityPointSale = true;

            return $this
                ->leftJoin('.deliveryAvailabilityPointSale', 'deliveryAvailabilityPointSale');
        }
        return $this;
    }

    public function joinDeliverySlotPointSale(): self
    {
        $this->joinDeliveryAvailabilityPointSale();

        if (!$this->isJoinDeliverySlotPointSale) {
            $this->isJoinDeliverySlotPointSale = true;

            return $this
                ->leftJoin('deliveryAvailabilityPointSale.deliverySlot', 'deliverySlotPointSale');
        }
        return $this;
    }

    public function joinOrderStatus(): self
    {
        if (!$this->isJoinOrderStatus) {
            $this->isJoinOrderStatus = true;

            return $this
                ->leftJoin('.orderStatus', 'os');
        }
        return $this;
    }

    public function joinOrderReductionCarts(): self
    {
        if (!$this->isJoinOrderReductionCarts) {
            $this->isJoinOrderReductionCarts = true;

            return $this
                ->leftJoin('.orderReductionCarts', 'orcart');
        }
        return $this;
    }

    public function joinComplementaryOrderShops(): self
    {
        if (!$this->isJoinComplementaryOrderShops) {
            $this->isJoinComplementaryOrderShops = true;

            return $this
                ->leftJoin('.complementaryOrderShops', 'complementaryOrderShops');
        }
        return $this;
    }

    public function joinDeliveryPointSale(): self
    {
        if (!$this->isJoinDeliveryPointSale) {
            $this->isJoinDeliveryPointSale = true;

            return $this
                ->leftJoin('.deliveryPointSale', 'pointSale');
        }
        return $this;
    }
}