<?php

declare(strict_types=1);

/*
 * This file is part of the VitiCore 2.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Product\Model;

use CpCreation\VitiCore\Behavior\HasTimestamp;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Product\Repository\ProductDegressiveRepository;
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 Symfony\Component\Validator\Context\ExecutionContextInterface;

#[ORM\Entity(repositoryClass: ProductDegressiveRepository::class)]
#[ORM\Table(name: 'product_degressive')]
#[ORM\HasLifecycleCallbacks]
class ProductDegressive implements HasTimestamp
{
    use Timestamp;

    #[ORM\Id]
    #[ORM\Column(type: 'uuid')]
    #[ORM\GeneratedValue(strategy: 'NONE')]
    private UuidInterface $id;

    #[ORM\Column(type: 'integer')]
    #[Assert\NotBlank]
    private ?int $qtyOf = null;

    #[ORM\Column(type: 'integer')]
    #[Assert\NotBlank]
    private ?int $qtyAt = null;

    /**
     * Montant fixe de remise TTC appliqué au package, en centimes.
     */
    #[ORM\Column(type: 'integer', nullable: true)]
    private ?int $packagePriceTTC = null;

    /**
     * Montant fixe de remise TTC appliqué par bouteille, en centimes.
     */
    #[ORM\Column(type: 'integer', nullable: true)]
    private ?int $bottlePriceTTC = null;

    /**
     * Pourcentage de remise.
     * Ex: 10.000 = 10%
     */
    #[ORM\Column(type: 'decimal', precision: 5, scale: 3, nullable: true)]
    private ?string $packagePercent = null;

    #[ORM\Column(type: 'integer', nullable: true)]
    private ?int $qtyOfBottleOffered = null;

    #[ORM\Column(type: 'boolean')]
    private bool $equivalency;

    #[ORM\Column(type: 'boolean')]
    private bool $allQuantity;

    /**
     * @var Collection<int, ProductType>
     */
    #[ORM\ManyToMany(targetEntity: ProductType::class)]
    #[Assert\Count(min: 1, minMessage: 'Vous devez ajouter au moins un type')]
    private Collection $types;

    /**
     * @var Collection<int, ProductPriceGroup>
     */
    #[ORM\ManyToMany(targetEntity: ProductPriceGroup::class)]
    #[Assert\Count(min: 1, minMessage: 'Vous devez ajouter au moins un groupe')]
    private Collection $groups;

    /**
     * @var Collection<int, Product>
     */
    #[ORM\ManyToMany(targetEntity: Product::class)]
    private Collection $products;

    #[ORM\Column(type: 'boolean', nullable: true)]
    private ?bool $mostOrderBottleInCart = null;

    public function __construct()
    {
        $this->id = Uuid::uuid4();
        $this->types = new ArrayCollection();
        $this->groups = new ArrayCollection();
        $this->products = new ArrayCollection();
        $this->allQuantity = false;
        $this->equivalency = false;
    }

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

    public function getQtyOf(): ?int
    {
        return $this->qtyOf;
    }

    public function setQtyOf(int $qtyOf): void
    {
        $this->qtyOf = $qtyOf;
    }

    public function getQtyAt(): ?int
    {
        return $this->qtyAt;
    }

    public function setQtyAt(int $qtyAt): void
    {
        $this->qtyAt = $qtyAt;
    }

    public function getPackagePriceTTC(): ?int
    {
        return $this->packagePriceTTC;
    }

    public function setPackagePriceTTC(?int $packagePriceTTC): void
    {
        $this->packagePriceTTC = $packagePriceTTC;
    }

    /**
     * Alias de compatibilité éventuelle.
     */
    public function getPackagePrice(): ?int
    {
        return $this->getPackagePriceTTC();
    }

    /**
     * Alias de compatibilité éventuelle.
     */
    public function setPackagePrice(?int $packagePrice): void
    {
        $this->setPackagePriceTTC($packagePrice);
    }

    public function getBottlePriceTTC(): ?int
    {
        return $this->bottlePriceTTC;
    }

    public function setBottlePriceTTC(?int $bottlePriceTTC): void
    {
        $this->bottlePriceTTC = $bottlePriceTTC;
    }

    /**
     * Alias de compatibilité éventuelle.
     */
    public function getBottlePrice(): ?int
    {
        return $this->getBottlePriceTTC();
    }

    /**
     * Alias de compatibilité éventuelle.
     */
    public function setBottlePrice(?int $bottlePrice): void
    {
        $this->setBottlePriceTTC($bottlePrice);
    }

    public function getPackagePercent(): ?float
    {
        return null !== $this->packagePercent ? (float) $this->packagePercent : null;
    }

    public function setPackagePercent(?float $packagePercent): void
    {
        $this->packagePercent = null !== $packagePercent ? (string) $packagePercent : null;
    }

    public function isEquivalency(): bool
    {
        return $this->equivalency;
    }

    public function setEquivalency(bool $equivalency): void
    {
        $this->equivalency = $equivalency;
    }

    public function isAllQuantity(): bool
    {
        return $this->allQuantity;
    }

    public function setAllQuantity(bool $allQuantity): void
    {
        $this->allQuantity = $allQuantity;
    }

    public function getQtyOfBottleOffered(): ?int
    {
        return $this->qtyOfBottleOffered;
    }

    public function setQtyOfBottleOffered(?int $qtyOfBottleOffered): void
    {
        $this->qtyOfBottleOffered = $qtyOfBottleOffered;
    }

    public function addType(ProductType $productType): self
    {
        if (!$this->types->contains($productType)) {
            $this->types->add($productType);
        }

        return $this;
    }

    public function removeType(ProductType $productType): void
    {
        $this->types->removeElement($productType);
    }

    /**
     * @return Collection<int, ProductType>
     */
    public function getTypes(): Collection
    {
        return $this->types;
    }

    public function addProduct(Product $product): self
    {
        if (!$this->products->contains($product)) {
            $this->products->add($product);
        }

        return $this;
    }

    public function removeProduct(Product $product): void
    {
        $this->products->removeElement($product);
    }

    /**
     * @return Collection<int, Product>
     */
    public function getProducts(): Collection
    {
        return $this->products;
    }

    public function addGroup(ProductPriceGroup $group): self
    {
        if (!$this->groups->contains($group)) {
            $this->groups->add($group);
        }

        return $this;
    }

    public function removeGroup(ProductPriceGroup $group): void
    {
        $this->groups->removeElement($group);
    }

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

    #[Assert\Callback]
    public function validate(ExecutionContextInterface $context): void
    {
        if (
            null === $this->getPackagePriceTTC()
            && null === $this->getBottlePriceTTC()
            && null === $this->getPackagePercent()
            && null === $this->getQtyOfBottleOffered()
        ) {
            $context->buildViolation('Veuillez ajouter un prix ou une remise.')
                ->atPath('bottlePriceTTC')
                ->addViolation();
        }
    }

    public function isMostOrderBottleInCart(): ?bool
    {
        return $this->mostOrderBottleInCart;
    }

    public function setMostOrderBottleInCart(?bool $mostOrderBottleInCart): void
    {
        $this->mostOrderBottleInCart = $mostOrderBottleInCart;
    }
}
