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

namespace CpCreation\VitiCore\Product\Model;

use CpCreation\VitiCore\Behavior\HasTimestamp;
use CpCreation\VitiCore\Behavior\Impl\SoftDeletable;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Behavior\IsSoftDeletable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use CpCreation\VitiCore\Product\Model\ProductGift;

/**
 * Class ProductVariant
 *
 * @ORM\Entity(repositoryClass="CpCreation\VitiCore\Product\Repository\ProductVariantRepository")
 * @ORM\Table(name="product_variant")
 * @ORM\HasLifecycleCallbacks()
 */
class ProductVariant implements HasTimestamp, IsSoftDeletable
{
    use Timestamp, SoftDeletable;

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

    /**
     * @ORM\Column(type="integer")
     * @Assert\NotBlank()
     *
     * @var integer
     */
    private $lot;

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

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

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

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

    /**
     * @ORM\ManyToOne(targetEntity="Product", inversedBy="variants")
     * @ORM\JoinColumn(name="product_id", referencedColumnName="id")
     * @Gedmo\SortableGroup()
     *
     * @var Product
     */
    private $product;

    /**
     * @ORM\ManyToOne(targetEntity="ProductType")
     * @ORM\JoinColumn(name="product_type_id", referencedColumnName="id")
     *
     * @var ProductType
     */
    private $type;

    /**
     * @ORM\OneToMany(targetEntity="ProductPrice", mappedBy="variant", cascade={"persist"})
     * @Assert\Valid()
     *
     * @var Collection<ProductPrice>
     */
    private $prices;

    /**
     *
     * @var integer
     */
    private $price = 0;

    /**
     *
     * @var integer
     */
    private $priceDiscount = null;

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

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

    public function __construct()
    {
        $this->id = Uuid::uuid4();
        $this->unPublished = 0;
        $this->soldOut = 0;
        $this->byDefault = 0;
        $this->prices = new ArrayCollection();
    }

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

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

    /**
     * @param int $lot
     */
    public function setLot(int $lot): void
    {
        $this->lot = $lot;
    }

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

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

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

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

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

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

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

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

    /**
     * @return Product
     */
    public function getProduct(): Product
    {
        return $this->product;
    }

    /**
     * @param Product $product
     */
    public function setProduct(?Product $product): void
    {
        $this->product = $product;
    }

    /**
     * @return ProductType
     */
    public function getType(): ?ProductType
    {
        return $this->type;
    }

    /**
     * @param ProductType $type
     */
    public function setType(ProductType $type): void
    {
        $this->type = $type;
    }

    /**
     * @return int
     */
    public function getPrice(): int
    {
        return $this->price;
    }

    /**
     * @param int $price
     */
    public function setPrice(int $price): void
    {
        $this->price = $price;
    }

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

    /**
     * @param int $priceDiscount
     */
    public function setPriceDiscount(int $priceDiscount = null): void
    {
        $this->priceDiscount = $priceDiscount;
    }

    /**
     * @return \DateTime|null
     */
    public function getStockAt(): ?\DateTime
    {
        return $this->stockAt;
    }

    /**
     * @param \DateTime|null $stockAt
     */
    public function setStockAt(?\DateTime $stockAt): void
    {
        $this->stockAt = $stockAt;
    }

    /**
     * @return int|null
     */
    public function getStock(): ?int
    {
        return $this->stock;
    }

    /**
     * @param int|null $stock
     */
    public function setStock(?int $stock): void
    {
        $this->stock = $stock;
    }

    /**
     * @param ProductPrice $price
     * @return $this
     */
    public function addPrice(ProductPrice $price)
    {
        $price->setVariant($this);
        $this->prices[] = $price;

        return $this;
    }

    /**
     * @param ProductPrice $price
     */
    public function removePrice(ProductPrice $price)
    {
        $this->prices->removeElement($price);
        $price->setVariant(null);
    }

    /**
     * @return Collection<ProductPrice>
     */
    public function getPrices(): Collection
    {
        return $this->prices;
    }

    public function getName()
    {
        $quality = '';
        if ($this->getProduct()->getQuality()) {
            $quality = $this->getProduct()->getQuality();
        }
        if ($this->getProduct()->getVariants()->count() > 1 || $this->getType()->getName() != $this->getProduct()->getName()) {
            return $this->getProduct()->getName() . ' ' . $quality . ' - ' . $this->getType()->getName();
        } else {
            return $this->getProduct()->getName() . ' ' . $quality;
        }
    }

    /**
     * @param \Symfony\Component\Validator\Context\ExecutionContextInterface $context
     * @Assert\Callback()
     */
    public function validate(ExecutionContextInterface $context)
    {
        if ($this->getStock() xor $this->getStockAt()) {
            $message = 'Vous devez entrer une date de début de stock si un stock est renseigné';
            $context->buildViolation($message)
                ->atPath("variant.stockAt")
                ->addViolation();
        }
    }

    public function getPriceByGroupId($groupId):ProductPrice
    {
        foreach ($this->getPrices() as $price){
            if ($price->getGroup()->getId() == $groupId){
                return $price;
            }
        }
    }
}
