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

namespace CpCreation\VitiCore\Product\Model;

use CpCreation\VitiCore\Award\Model\Award;
use CpCreation\VitiCore\Behavior\HasDisable;
use CpCreation\VitiCore\Behavior\HasFile;
use CpCreation\VitiCore\Behavior\HasImage;
use CpCreation\VitiCore\Behavior\HasTimestamp;
use CpCreation\VitiCore\Behavior\HasTranslatable;
use CpCreation\VitiCore\Behavior\Impl\Disable;
use CpCreation\VitiCore\Behavior\Impl\File;
use CpCreation\VitiCore\Behavior\Impl\Image;
use CpCreation\VitiCore\Behavior\Impl\SoftDeletable;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Behavior\Impl\Translatable;
use CpCreation\VitiCore\Behavior\IsSoftDeletable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Sortable\Sortable;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;
use CpCreation\VitiCore\Media\Model\Image as ModelImage;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use CpCreation\VitiCore\Product\Model\ProductTypeOption;
use CpCreation\VitiCore\Product\Model\ProductGift;

/**
 * Class Product
 *
 * @ORM\Entity(repositoryClass="CpCreation\VitiCore\Product\Repository\ProductRepository")
 * @ORM\Table(name="product_product")
 * @ORM\HasLifecycleCallbacks()
 */
class Product implements HasTimestamp, HasImage, Sortable, HasDisable, HasFile, HasTranslatable, IsSoftDeletable
{
    use Timestamp, Image, Disable, File, Translatable, SoftDeletable;

    /**
     * @ORM\Id()
     * @ORM\Column(type="uuid")
     * @ORM\GeneratedValue(strategy="NONE")
     *
     * @var UuidInterface
     */
    private $id;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var bool
     */
    private $cuvee;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var bool
     */
    private $shop;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var bool
     */
    private $favorite;

    /**
     * @ORM\Column(type="integer")
     * @Gedmo\SortablePosition()
     *
     * @var integer
     */
    private $position;

    /**
     * @ORM\Column(type="integer", nullable=true)
     *
     * @var integer|null
     */
    private $positionShop;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var boolean
     */
    private $new;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var boolean
     */
    private $soldOut;

    /**
     * @ORM\Column(type="text", nullable=true, length=8)
     *
     * @var string | null
     */
    private $ribbonCustomColor;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var boolean
     */
    private $enableColor;

    /**
     * @ORM\Column(type="boolean")
     *
     * @var boolean
     */
    private $enableColorQuality;

    /**
     * @ORM\Column(type="text", nullable=true, length=8)
     *
     * @var string | null
     */
    private $color;

    /**
     * @ORM\Column(type="text",nullable=true,length=8)
     *
     * @var string
     */
    private $colorGradient1;


    /**
     * @ORM\Column(type="text",nullable=true,length=8)
     *
     * @var string
     */
    private $colorGradient2;

    /**
     * @ORM\Column(type="integer", nullable=true, length=8)
     *
     * @var integer
     */
    private $orderInFavorites;

    /**
     * @ORM\ManyToOne(targetEntity="ProductCategory", inversedBy="products")
     * @ORM\JoinColumn(name="product_category_id", referencedColumnName="id", nullable=true)
     * @Assert\NotBlank()
     *
     * @var ProductCategory
     */
    private $category;

    /**
     * @ORM\OneToMany(targetEntity="ProductVariant", mappedBy="product", cascade={"persist","remove"}, orphanRemoval=true)
     * @ORM\OrderBy({"position" = "ASC"})
     *
     * @Assert\Count( min = 1 , minMessage="Vous devez ajouter au moins un variant de produit")
     * @Assert\Valid()
     *
     * @var Collection<ProductVariant>
     */
    private $variants;

    /**
     * @ORM\ManyToMany(targetEntity="CpCreation\VitiCore\Award\Model\Award")
     * @Assert\Valid()
     *
     * @var Collection<Award>
     */
    private $awards;

    /**
     * @ORM\OneToOne(targetEntity="CpCreation\VitiCore\Media\Model\Image", cascade={"all"})
     * @var ModelImage
     */
    private $secondImage;

    /**
     * @ORM\OneToOne(targetEntity="CpCreation\VitiCore\Media\Model\Image", cascade={"all"})
     * @ORM\JoinColumn(name="background_image_id", nullable=true, referencedColumnName="id", onDelete="SET NULL")
     * @var ModelImage | null
     */
    private $backgroundImage;

    /**
     * @ORM\OneToMany(targetEntity="CpCreation\VitiCore\Product\Model\ProductImage", cascade={"persist","remove"}, mappedBy="product", orphanRemoval=true)
     * @ORM\OrderBy({"position" = "ASC"})
     * @Assert\Valid()
     *
     * @var Collection<ProductImage>
     */
    private $images;

    /**
     * @ORM\OneToMany(targetEntity="CpCreation\VitiCore\Product\Model\ProductFile", cascade={"persist","remove"}, mappedBy="product", orphanRemoval=true)
     * @ORM\OrderBy({"locale" = "ASC"})
     * @Assert\Valid()
     *
     * @var Collection|ProductFile[]
     */
    private $files;

    /**
     * @ORM\ManyToMany(targetEntity="CpCreation\VitiCore\Product\Model\ProductPriceGroup")
     * @var Collection<ProductPriceGroup>
     */
    private $groups;

    private array $degressivities = [];

    /**
     * @ORM\Column(type="text", nullable=true, length=8)
     *
     * @var string | null
     */
    private string $referenceToken;

    public function __construct()
    {
        $this->id                 = Uuid::uuid4();
        $this->variants           = new ArrayCollection();
        $this->awards             = new ArrayCollection();
        $this->groups             = new ArrayCollection();
        $this->images             = new ArrayCollection();
        $this->files              = new ArrayCollection();
        $this->disabled           = false;
        $this->cuvee              = true;
        $this->shop               = true;
        $this->favorite           = false;
        $this->new                = false;
        $this->soldOut            = false;
        $this->enableColor        = false;
        $this->enableColorQuality = false;
    }

    /**
     * @return UuidInterface
     */
    public function getId(): UuidInterface
    {
        return $this->id;
    }

    /**
     * @param Uuid $id
     */
    public function setId(Uuid $id)
    {
        $this->id = $id;
    }

    /**
     * @return bool
     */
    public function isCuvee(): bool
    {
        return $this->cuvee;
    }

    /**
     * @param bool $cuvee
     */
    public function setCuvee(bool $cuvee = true)
    {
        $this->cuvee = $cuvee;
    }

    /**
     * @return bool
     */
    public function isShop(): bool
    {
        return $this->shop;
    }

    /**
     * @param bool $shop
     */
    public function setShop(bool $shop)
    {
        $this->shop = $shop;
    }

    /**
     * @return bool
     */
    public function isFavorite(): bool
    {
        return $this->favorite;
    }

    /**
     * @param bool $favorite
     */
    public function setFavorite(bool $favorite): void
    {
        $this->favorite = $favorite;
    }

    /**
     * @return int
     */
    public function getPosition(): ?int
    {
        return $this->position;
    }

    /**
     * @return int
     */
    public function getPositionShop(): ?int
    {
        return $this->positionShop;
    }

    /**
     * @return bool
     */
    public function isNew(): bool
    {
        return $this->new;
    }

    /**
     * @param bool $new
     */
    public function setNew(bool $new)
    {
        $this->new = $new;
    }

    /**
     * @return bool
     */
    public function isSoldOut(): bool
    {
        return $this->soldOut;
    }

    /**
     * @param bool $soldOut
     */
    public function setSoldOut(bool $soldOut): void
    {
        $this->soldOut = $soldOut;
    }

    /**
     * @return null|string
     */
    public function getRibbonCustomColor(): ?string
    {
        return $this->ribbonCustomColor;
    }

    /**
     * @param null|string $ribbonCustomColor
     */
    public function setRibbonCustomColor(?string $ribbonCustomColor): void
    {
        $this->ribbonCustomColor = $ribbonCustomColor;
    }

    /**
     * @return bool
     */
    public function isEnableColor(): bool
    {
        return $this->enableColor;
    }

    /**
     * @param bool $enableColor
     */
    public function setEnableColor(bool $enableColor): void
    {
        $this->enableColor = $enableColor;
    }

    /**
     * @return bool
     */
    public function isEnableColorQuality(): bool
    {
        return $this->enableColorQuality;
    }

    /**
     * @param bool $enableColorQuality
     */
    public function setEnableColorQuality(bool $enableColorQuality): void
    {
        $this->enableColorQuality = $enableColorQuality;
    }

    /**
     * @return null|string
     */
    public function getColor(): ?string
    {
        return $this->color;
    }

    /**
     * @param null|string $color
     */
    public function setColor(?string $color): void
    {
        $this->color = $color;
    }

    /**
     * @param int $position | null
     */
    public function setPosition(?int $position)
    {
        $this->position = $position;
    }

    /**
     * @param int $positionShop | null
     */
    public function setPositionShop(?int $positionShop)
    {
        $this->positionShop = $positionShop;
    }

    /**
     * @return int
     */
    public function getOrderInFavorites(): ?int
    {
        return $this->orderInFavorites;
    }

    /**
     * @param int $orderInFavorites
     */
    public function setOrderInFavorites(?int $orderInFavorites): void
    {
        $this->orderInFavorites = $orderInFavorites;
    }

    /**
     * @return ProductCategory
     */
    public function getCategory(): ?ProductCategory
    {
        return $this->category;
    }

    /**
     * @param ProductCategory $category
     */
    public function setCategory(ProductCategory $category = null)
    {
        $this->category = $category;
    }

    /**
     * @return ModelImage|null
     */
    public function getBackgroundImage(): ?ModelImage
    {
        return $this->backgroundImage;
    }

    /**
     * @param ModelImage|null $backgroundImage
     */
    public function setBackgroundImage(?ModelImage $backgroundImage): void
    {
        $this->backgroundImage = $backgroundImage;
    }

    /**
     * @param ProductVariant $variant
     * @return $this
     */
    public function addVariant(ProductVariant $variant)
    {
        $variant->setProduct($this);
        $this->variants[] = $variant;

        return $this;
    }

    /**
     * @param ProductVariant $variant
     */
    public function removeVariant(ProductVariant $variant)
    {
        $variant->markDeleted();
        $this->variants[] = $variant;

        return $this;
    }

    /**
     * @return Collection<ProductVariant>
     */
    public function getVariants(): Collection
    {

        return $this->variants;
    }

    public function addAward(Award $award)
    {
        $this->awards[] = $award;
    }

    public function removeAward(Award $award)
    {
        $this->awards->removeElement($award);
    }

    /**
     * @return Collection<Award>
     */
    public function getAwards(): Collection
    {
        return $this->awards;
    }

    /**
     * @return ModelImage
     */
    public function getSecondImage(): ?ModelImage
    {
        return $this->secondImage;
    }

    public function addImage(ProductImage $image): self
    {

        if (!$this->images->contains($image)) {
            $this->images[] = $image;
            $image->setProduct($this);
        }

        return $this;
    }

    public function removeImage(ProductImage $image): self
    {

        if ($this->images->contains($image)) {
            $this->images->removeElement($image);
            // set the owning side to null (unless already changed)
            if ($image->getProduct() === $this) {
                $image->setProduct(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection<Image>
     */
    public function getImages(): Collection
    {
        return $this->images;
    }

    public function addFile(ProductFile $file): self
    {

        if (!$this->files->contains($file)) {
            $this->files[] = $file;
            $file->setProduct($this);
        }

        return $this;
    }

    public function removeFile(ProductFile $file): self
    {

        if ($this->images->contains($file)) {
            $this->images->removeElement($file);
            // set the owning side to null (unless already changed)
            if ($file->getProduct() === $this) {
                $file->setProduct(null);
            }
        }

        return $this;
    }

    /**
     * @return ProductFile[]|Collection
     */
    public function getFiles(): Collection
    {
        return $this->files;
    }

    /**
     * @param ProductPriceGroup $group
     * @return $this
     */
    public function addGroup(ProductPriceGroup $group)
    {
        $this->groups[] = $group;

        return $this;
    }

    /**
     * @param ProductPriceGroup $group
     */
    public function removeGroup(ProductPriceGroup $group)
    {
        $this->groups->removeElement($group);
    }

    /**
     * @return Collection<ProductPriceGroup>
     */
    public function getGroups(): Collection
    {
        return $this->groups;
    }

    /**
     * @param ModelImage $secondImage
     */
    public function setSecondImage(ModelImage $secondImage = null)
    {
        if ($secondImage->getPath() || $secondImage->getFile()) {
            $this->secondImage = $secondImage;
        } else {
            $this->secondImage = null;
        }
    }

    public function getFullName()
    {
        $fullName = '';
        if ($this->getHeader()) {
            $fullName = $this->getHeader().' ';
        }

        $fullName .= $this->getName();

        if ($this->getQuality()) {
            $fullName .= ' '.$this->getQuality();
        }

        return $fullName;
    }

    /**
     * @param array $degressivities
     */
    public function setDegressivities(array $degressivities): void
    {
        $this->degressivities = $degressivities;
    }

    /**
     * @return array
     */
    public function getDegressivities(): array
    {
        return $this->degressivities;
    }

    public function getColorGradient1(){
        return $this->colorGradient1;
    }

    public function setColorGradient1(string $colorGradient1){
        $this->colorGradient1 = $colorGradient1;
    }

    public function getColorGradient2(){
        return $this->colorGradient2;
    }

    public function setColorGradient2(string $colorGradient2){
        $this->colorGradient2 = $colorGradient2;
    }

    /**
     * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context
     * @Assert\Callback()
     */
    public function validate(ExecutionContextInterface $context)
    {
        if (!$this->getImage()) {
            $message = 'Veuillez ajouter une image';
            $context->buildViolation($message)
                    ->atPath("image.file")
                    ->addViolation();
        }
    }

    public function getReferenceToken(): ?string
    {
        return $this->referenceToken;
    }

    public function setReferenceToken(string $referenceToken): void
    {
        $this->referenceToken = $referenceToken;
    }

}
