<?php

namespace Lc\ShopBundle\Model;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Lc\ShopBundle\Context\FilterMerchantInterface;
use Lc\ShopBundle\Context\PriceInterface;
use Lc\ShopBundle\Context\ProductInterface;
use Lc\ShopBundle\Context\ProductPropertyInterface;
use Gedmo\Mapping\Annotation as Gedmo;


/**
 * @ORM\MappedSuperclass()
 */

abstract class ProductFamily extends AbstractDocumentEntity implements ProductPropertyInterface, PriceInterface, FilterMerchantInterface
{

        use ProductPropertyTrait;

        const BEHAVIOR_COUNT_STOCK_UNLIMITED = 'unlimited' ;
        const BEHAVIOR_COUNT_STOCK_BY_MEASURE = 'by-measure' ;
        const BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY = 'by-product-family' ;
        const BEHAVIOR_COUNT_STOCK_BY_PRODUCT = 'by-product' ;

        const BEHAVIOR_STOCK_WEEK_RENEWABLE = 'renewable';
        const BEHAVIOR_STOCK_WEEK_RENEWABLE_VALIDATION = 'renewable-with-validation';
        const BEHAVIOR_STOCK_WEEK_NON_RENEWABLE = 'non-renewable';

        const WARNING_MESSAGE_TYPE_SUCCESS = 'success';
        const WARNING_MESSAGE_TYPE_ERROR = 'error';
        const WARNING_MESSAGE_TYPE_WARNING = 'warning';
        const WARNING_MESSAGE_TYPE_INFO = 'info';

        const BEHAVIOR_ADD_TO_CART_SIMPLE = 'simple';
        const BEHAVIOR_ADD_TO_CART_MULTIPLE = 'multiple';

        const BEHAVIOR_PRICE_BY_PIECE = 'by-piece';
        const BEHAVIOR_PRICE_BY_REFERENCE_UNIT = 'by-reference-unit';

        const PROPERTY_ORGANIC_LABEL_AB = 'ab';
        const PROPERTY_ORGANIC_LABEL_NP = 'nature-progres';
        const PROPERTY_ORGANIC_LABEL_HVE = 'hve';

        const TYPE_EXPIRATION_DATE_DLC = 'dlc';
        const TYPE_EXPIRATION_DATE_DDM = 'ddm';
        const TYPE_EXPIRATION_DATE_DLUO = 'dluo';

        const BEHAVIOR_EXPIRATION_DATE_BY_PRODUCT_FAMILY = 'by-product-family';
        const BEHAVIOR_EXPIRATION_DATE_BY_PRODUCT = 'by-product';

        //Champ hydraté par ProductFamilyUtils
        protected $reductionCatalog;

        /**
         * @Gedmo\Blameable(on="create")
         * @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\UserInterface")
         * @ORM\JoinColumn(nullable=true)
         */
        protected $createdBy;

        /**
         * @Gedmo\Blameable(on="update")
         * @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\UserInterface")
         * @ORM\JoinColumn(nullable=true)
         */
        protected $updatedBy;

        /**
         * @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\MerchantInterface", inversedBy="productFamilies")
         * @ORM\JoinColumn(nullable=false)
         */
        protected $merchant;

        /**
         * @ORM\ManyToMany(targetEntity="Lc\ShopBundle\Context\ProductCategoryInterface", inversedBy="productFamilies")
         */
        protected $productCategories;

        /**
         * @ORM\Column(type="boolean")
         */
        protected $activeProducts;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $productsType;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $quantityLabel;

        /**
         * @ORM\OneToMany(targetEntity="Lc\ShopBundle\Context\ProductInterface", mappedBy="productFamily", orphanRemoval=true, cascade={"persist"})
         * @ORM\OrderBy({"position" = "ASC"})
         */
        protected $products;

        /**
         * @ORM\ManyToOne(targetEntity="Lc\ShopBundle\Context\TaxRateInterface")
         */
        protected $supplierTaxRate;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $subtitle;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $warningMessage;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $warningMessageType;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $note;

        /**
         * @ORM\Column(type="string", length=31, nullable=true)
         */
        protected $behaviorOutOfStock;

        /**
         * @ORM\Column(type="string", length=31)
         */
        protected $behaviorCountStock;

        /**
         * @ORM\Column(type="date", nullable=true)
         */
        protected $propertyNoveltyExpirationDate;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $propertyOrganicLabel;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyAllergens;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyComposition;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyFragrances;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyPackaging;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyCharacteristics;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyWeight;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyQuantity;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyFeature;


        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyVariety;

        /**
         * @ORM\Column(type="text", nullable=true)
         */
        protected $propertyAlcoholLevel;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $behaviorExpirationDate;

        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $typeExpirationDate;

        /**
         * @ORM\Column(type="string", length=32, nullable=true)
         */
        protected $behaviorAddToCart;

        /**
         * @ORM\Column(type="string", length=31)
         */
        protected $behaviorPrice;


        public function __construct()
        {
                $this->productCategories = new ArrayCollection();
                $this->products = new ArrayCollection();
        }

        public function __toString()
        {
                return $this->getTitle();
        }

        public function getAvailableQuantityInherited()
        {
                $availableQuantity = 0 ;

                switch ($this->getBehaviorCountStock()) {

                        case self::BEHAVIOR_COUNT_STOCK_BY_MEASURE :
                        case self::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY :

                                $availableQuantity = $this->getAvailableQuantity() ;
                                break;

                        case self::BEHAVIOR_COUNT_STOCK_BY_PRODUCT :

                                foreach($this->getProducts() as $product) {
                                        $availableQuantity += $product->getAvailableQuantityInherited() ;
                                }
                                break ;

                        case self::BEHAVIOR_COUNT_STOCK_UNLIMITED :
                                $availableQuantity = false;
                                break;
                }

                return $availableQuantity ;
        }

        public function getTaxRateInherited()
        {
                if ($this->getTaxRate()) {
                        return $this->getTaxRate();
                } else {
                        return $this->getMerchant()->getTaxRate();
                }
        }

        public function getMerchant(): ?Merchant
        {
                return $this->merchant;
        }

        public function setMerchant(?Merchant $merchant): self
        {
                $this->merchant = $merchant;

                return $this;
        }

        public function getActiveProducts(): ?bool
        {
                return $this->activeProducts;
        }

        public function setActiveProducts(bool $activeProducts): self
        {
                $this->activeProducts = $activeProducts;

                return $this;
        }

        public function getProductsType(): ?string
        {
                return $this->productsType;
        }

        public function setProductsType(?string $productsType): self
        {
                $this->productsType = $productsType;

                return $this;
        }

        public function getQuantityLabel(): ?string
        {
                return $this->quantityLabel;
        }

        public function setQuantityLabel(?string $quantityLabel): self
        {
                $this->quantityLabel = $quantityLabel;

                return $this;
        }

        /**
         * @return Collection|ProductInterface[]
         */
        public function getProducts(): Collection
        {
                return $this->products;
        }

        public function getProductsOnline(): Collection
        {
                $products = $this->getProducts() ;
                $productsOnlineArray = new ArrayCollection() ;

                foreach($products as $product) {
                        if($product->getStatus() == 1) {
                                $productsOnlineArray[] = $product ;
                        }
                }

                return $productsOnlineArray ;
        }

        public function addProduct(ProductInterface $product): self
        {
                if (!$this->products->contains($product)) {
                        $this->products[] = $product;
                        $product->setProductFamily($this);
                }

                return $this;
        }

        public function removeProduct(ProductInterface $product): self
        {
                if ($this->products->contains($product)) {
                        $this->products->removeElement($product);
                        // set the owning side to null (unless already changed)
                        if ($product->getProductFamily() === $this) {
                                $product->setProductFamily(null);
                        }
                }

                return $this;
        }

        public function getReductionCatalog(): ?ReductionCatalog
        {
                return $this->reductionCatalog;
        }

        public function getReductionCatalogInherited(): ?ReductionCatalog
        {
                return $this->getReductionCatalog() ;
        }

        public function setReductionCatalog(?ReductionCatalog $reductionCatalog): self
        {
                $this->reductionCatalog = $reductionCatalog;

                return $this;
        }
        /**
         * @return Collection|ProductCategory[]
         */
        public function getProductCategories(): Collection
        {
                return $this->productCategories;
        }

        public function initProductCategories()
        {
                $this->productCategories = new ArrayCollection();
        }

        public function addProductCategory(ProductCategory $productCategory): self
        {
                if (!$this->productCategories->contains($productCategory)) {
                        $this->productCategories[] = $productCategory;
                }

                return $this;
        }

        public function removeProductCategory(ProductCategory $productCategory): self
        {
                if ($this->productCategories->contains($productCategory)) {
                        $this->productCategories->removeElement($productCategory);
                }

                return $this;
        }

        public function getProductCategoryParent()
        {
                $productCategories = $this->getProductCategories();

                if (count($productCategories) > 0) {
                        return $productCategories[0]->getParent();
                }

                return false;
        }

        public function getProductCategoryChild()
        {
                $productCategories = $this->getProductCategories();

                foreach ($productCategories as $productCategory) {
                        if ($productCategory->getParent()) {
                                return $productCategory;
                        }
                }

                return false;
        }

        public function getSupplierTaxRate(): ?TaxRate
        {
                return $this->supplierTaxRate;
        }

        public function setSupplierTaxRate(?TaxRate $supplierTaxRate): self
        {
                $this->supplierTaxRate = $supplierTaxRate;

                return $this;
        }

        public function getSubtitle(): ?string
        {
                return $this->subtitle;
        }

        public function setSubtitle(?string $subtitle): self
        {
                $this->subtitle = $subtitle;

                return $this;
        }


        public function getWarningMessage(): ?string
        {
                return $this->warningMessage;
        }

        public function setWarningMessage(?string $warningMessage): self
        {
                $this->warningMessage = $warningMessage;

                return $this;
        }

        public function getWarningMessageType(): ?string
        {
                return $this->warningMessageType;
        }

        public function setWarningMessageType(?string $warningMessageType): self
        {
                $this->warningMessageType = $warningMessageType;

                return $this;
        }

        public function getNote(): ?string
        {
                return $this->note;
        }

        public function setNote(?string $note): self
        {
                $this->note = $note;

                return $this;
        }

        public function getBehaviorOutOfStock(): ?string
        {
                return $this->behaviorOutOfStock;
        }

        public function setBehaviorOutOfStock(?string $behaviorOutOfStock): self
        {
                $this->behaviorOutOfStock = $behaviorOutOfStock;

                return $this;
        }

        public function getBehaviorCountStock(): ?string
        {
                return $this->behaviorCountStock;
        }


        public function setBehaviorCountStock(string $behaviorCountStock): self
        {
                $this->behaviorCountStock = $behaviorCountStock;

                return $this;
        }

        public function isPropertyNoveltyOnline(): ?bool
        {
                if ($this->getPropertyNoveltyExpirationDate()) {
                        $now = new \DateTime();
                        if ($now <= $this->getPropertyNoveltyExpirationDate()) {
                                return true;
                        }
                }

                return false;
        }

        public function getPropertyNoveltyExpirationDate(): ?\DateTimeInterface
        {
                return $this->propertyNoveltyExpirationDate;
        }

        public function setPropertyNoveltyExpirationDate(?\DateTimeInterface $propertyNoveltyExpirationDate): self
        {
                $this->propertyNoveltyExpirationDate = $propertyNoveltyExpirationDate;

                return $this;
        }

        public function getPropertyOrganicLabel(): ?string
        {
                return $this->propertyOrganicLabel;
        }

        public function setPropertyOrganicLabel(?string $propertyOrganicLabel): self
        {
                $this->propertyOrganicLabel = $propertyOrganicLabel;

                return $this;
        }

        public function getPropertyAllergens(): ?string
        {
                return $this->propertyAllergens;
        }

        public function setPropertyAllergens(?string $propertyAllergens): self
        {
                $this->propertyAllergens = $propertyAllergens;

                return $this;
        }

        public function getPropertyComposition(): ?string
        {
                return $this->propertyComposition;
        }

        public function setPropertyComposition(?string $propertyComposition): self
        {
                $this->propertyComposition = $propertyComposition;

                return $this;
        }

        public function getPropertyFragrances(): ?string
        {
                return $this->propertyFragrances;
        }

        public function setPropertyFragrances(?string $propertyFragrances): self
        {
                $this->propertyFragrances = $propertyFragrances;

                return $this;
        }

        public function countProperties(): bool
        {
                $count = 0;

                $count += (int)strlen($this->getPropertyAllergens()) > 0;
                $count += (int)strlen($this->getPropertyComposition()) > 0;
                $count += (int)strlen($this->getPropertyFragrances()) > 0;
                $count += (int)strlen($this->getPropertyOrganicLabel()) > 0;
                $count += (int)($this->getPropertyExpirationDate() != null);

                return $count;
        }

        public function getBehaviorExpirationDate(): ?string
        {
                return $this->behaviorExpirationDate;
        }

        public function setBehaviorExpirationDate(?string $behaviorExpirationDate): self
        {
                $this->behaviorExpirationDate = $behaviorExpirationDate;

                return $this;
        }

        public function getTypeExpirationDate(): ?string
        {
                return $this->typeExpirationDate;
        }

        public function setTypeExpirationDate(?string $typeExpirationDate): self
        {
                $this->typeExpirationDate = $typeExpirationDate;

                return $this;
        }


        public function getPropertyWeight(): ?string
        {
                return $this->propertyWeight;
        }

        public function setPropertyWeight(?string $propertyWeight): self
        {
                $this->propertyWeight = $propertyWeight;

                return $this;
        }


        public function getPropertyQuantity(): ?string
        {
                return $this->propertyQuantity;
        }

        public function setPropertyQuantity(?string $propertyQuantity): self
        {
                $this->propertyQuantity = $propertyQuantity;

                return $this;
        }

        public function getPropertyVariety(): ?string
        {
                return $this->propertyVariety;
        }

        public function setPropertyVariety(?string $propertyVariety): self
        {
                $this->propertyVariety = $propertyVariety;

                return $this;
        }

        public function getPropertyFeature(): ?string
        {
                return $this->propertyFeature;
        }

        public function setPropertyFeature(?string $propertyFeature): self
        {
                $this->propertyFeature = $propertyFeature;

                return $this;
        }

        public function getPropertyAlcoholLevel(): ?string
        {
                return $this->propertyAlcoholLevel;
        }

        public function setPropertyAlcoholLevel(?string $propertyAlcoholLevel): self
        {
                $this->propertyAlcoholLevel = $propertyAlcoholLevel;

                return $this;
        }


        public function getPropertyPackaging(): ?string
        {
                return $this->propertyPackaging;
        }

        public function setPropertyPackaging(?string $propertyPackaging): self
        {
                $this->propertyPackaging = $propertyPackaging;

                return $this;
        }

        public function getPropertyCharacteristics(): ?string
        {
                return $this->propertyCharacteristics;
        }

        public function setPropertyCharacteristics(?string $propertyCharacteristics): self
        {
                $this->propertyCharacteristics = $propertyCharacteristics;

                return $this;
        }

        public function getBehaviorAddToCart(): ?string
        {
                return $this->behaviorAddToCart;
        }

        public function setBehaviorAddToCart(?string $behaviorAddToCart): self
        {
                $this->behaviorAddToCart = $behaviorAddToCart;

                return $this;
        }


        public function getBehaviorPrice(): ?string
        {
                return $this->behaviorPrice;
        }

        public function getBehaviorPriceInherited()
        {
                return $this->getBehaviorPrice() ;
        }

        public function setBehaviorPrice(?string $behaviorPrice): self
        {
                $this->behaviorPrice = $behaviorPrice;

                return $this;
        }


        public function hasProductsWithVariousWeight()
        {
                if ($this->getActiveProducts()) {
                        $arrayCountProducts = [];
                        $products = $this->getProducts();

                        foreach ($products as $product) {
                                $titleProduct = $product->getTitleInherited();
                                if (!isset($arrayCountProducts[$titleProduct])) {
                                        $arrayCountProducts[$titleProduct] = [];
                                }

                                if (!in_array($product->getQuantityLabelInherited(), $arrayCountProducts[$titleProduct])) {
                                        $arrayCountProducts[$titleProduct][] = $product->getQuantityLabelInherited();
                                }

                                if (count($arrayCountProducts[$titleProduct]) > 1) {
                                        return true;
                                }
                        }
                }

                return false;
        }

        public function getProductsGroupByTitle()
        {
                $arrayProductsGroupByTitle = [];
                $products = $this->getProducts();

                foreach ($products as $product) {
                        if($product->getStatus() == 1) {
                                $titleProduct = $product->getTitleInherited();
                                if (!isset($arrayProductsGroupByTitle[$titleProduct])) {
                                        $arrayProductsGroupByTitle[$titleProduct] = [];
                                }
                                $arrayProductsGroupByTitle[$titleProduct][] = $product;
                        }
                }

                return $arrayProductsGroupByTitle;
        }
}
