<?php

declare(strict_types=1);

/*
 * This file is part of the Serenity package.
 *
 * (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\HasTranslatable;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Behavior\Impl\Translatable;
use CpCreation\VitiCore\Product\Model\Translation\ProductTypeTranslation;
use CpCreation\VitiCore\Product\Repository\ProductTypeRepository;
use CpCreation\VitiCore\Shop\Model\ShippingZone;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Sortable\Sortable;
use Knp\DoctrineBehaviors\Contract\Entity\TranslationInterface;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity(repositoryClass: ProductTypeRepository::class)]
#[ORM\Table(name: 'product_type')]
#[ORM\UniqueConstraint(name: 'uniq_product_type_code', columns: ['code'])]
#[UniqueEntity(fields: ['code'], message: 'sku.type.code_unique')]
#[ORM\HasLifecycleCallbacks]
class ProductType implements HasTimestamp, Sortable, HasTranslatable
{
    use Timestamp;
    use Translatable;

    /**
     * @var Collection<string, TranslationInterface>
     */
    #[Assert\Valid]
    #[ORM\OneToMany(
        targetEntity: ProductTypeTranslation::class,
        mappedBy: 'translatable',
        cascade: ['persist', 'remove'],
        indexBy: 'locale',
        orphanRemoval: true
    )]
    protected $translations;

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

    #[ORM\Column(type: 'integer')]
    #[Gedmo\SortablePosition]
    private ?int $position = null;

    #[ORM\Column(type: 'string', length: 64)]
    #[Assert\NotBlank(message: 'sku.type.code_required')]
    #[Assert\Length(max: 64, maxMessage: 'sku.type.code_too_long')]
    #[Assert\Regex(pattern: '/^[A-Z0-9]+(?:-[A-Z0-9]+)*$/', message: 'sku.type.code_invalid')]
    private ?string $code = null;

    #[ORM\Column(type: 'decimal', precision: 5, scale: 2, nullable: true)]
    private ?string $volume = null;

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

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

    #[ORM\Column(type: 'integer', options: ['default' => 1])]
    #[Assert\NotBlank]
    private int $multipleQuantityCart = 1;

    #[ORM\Column(type: 'integer', options: ['default' => 1])]
    private int $multipleQuantityDepot = 1;

    #[ORM\Column(type: 'decimal', precision: 4, scale: 2)]
    #[Assert\NotBlank]
    private ?string $equivalencyManu = null;

    #[ORM\Column(type: 'decimal', precision: 4, scale: 2)]
    #[Assert\NotBlank]
    private ?string $equivalency = null;

    #[ORM\Column(type: 'decimal', precision: 4, scale: 2, options: ['default' => 1])]
    #[Assert\NotBlank]
    private ?string $equivalencyDegressive = null;

    #[ORM\Column(type: 'decimal', precision: 4, scale: 2)]
    #[Assert\NotBlank]
    private ?string $equivalencyFreeShipping = null;

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

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

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

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

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

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

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

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

    #[ORM\Column(type: 'boolean', options: ['default' => 0])]
    private bool $accessory;

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

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

    /**
     * @var Collection<int, ProductTypeOption>
     */
    #[ORM\OneToMany(
        targetEntity: ProductTypeOption::class,
        mappedBy: 'productType',
        cascade: ['persist', 'remove']
    )]
    private Collection $options;

    public function __construct()
    {
        $this->id = Uuid::uuid4();
        $this->translations = new ArrayCollection();
        $this->equivalencyOnShipping = false;
        $this->equivalencyOnFreeShipping = false;
        $this->equivalencyDefault = false;
        $this->equivalencyDefaultQuantity = false;
        $this->freeShippingWithBottle = false;
        $this->disabledShippingManu = false;
        $this->disabledShippingAuto = false;
        $this->accessory = false;
        $this->zonesFreeShipping = new ArrayCollection();
        $this->options = new ArrayCollection();
    }

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

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

    public function getCode(): ?string
    {
        return $this->code;
    }

    public function setCode(?string $code): void
    {
        if (null === $code || '' === trim($code)) {
            $this->code = null;

            return;
        }

        $normalized = preg_replace('/[^A-Z0-9]+/', '-', mb_strtoupper(trim($code)));
        $normalized = null !== $normalized ? trim($normalized, '-') : '';
        $this->code = '' !== $normalized ? $normalized : null;
    }

    public function setPosition(int $position): void
    {
        $this->position = $position;
    }

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

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

    public function getUnity(): ?string
    {
        return $this->unity;
    }

    public function setUnity(?string $unity): void
    {
        $this->unity = $unity;
    }

    public function getMaximumQuantityCart(): ?int
    {
        return $this->maximumQuantityCart;
    }

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

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

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

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

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

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

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

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

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

    public function isEquivalencyDefault(): bool
    {
        return $this->equivalencyDefault;
    }

    public function setEquivalencyDefault(bool $equivalencyDefault): void
    {
        $this->equivalencyDefault = $equivalencyDefault;
    }

    public function isEquivalencyOnShipping(): bool
    {
        return $this->equivalencyOnShipping;
    }

    public function setEquivalencyOnShipping(bool $equivalencyOnShipping): void
    {
        $this->equivalencyOnShipping = $equivalencyOnShipping;
    }

    public function isEquivalencyOnFreeShipping(): bool
    {
        return $this->equivalencyOnFreeShipping;
    }

    public function setEquivalencyOnFreeShipping(bool $equivalencyOnFreeShipping): void
    {
        $this->equivalencyOnFreeShipping = $equivalencyOnFreeShipping;
    }

    public function isEquivalencyDefaultQuantity(): bool
    {
        return $this->equivalencyDefaultQuantity;
    }

    public function setEquivalencyDefaultQuantity(bool $equivalencyDefaultQuantity): void
    {
        $this->equivalencyDefaultQuantity = $equivalencyDefaultQuantity;
    }

    public function getMultipleQuantityCart(): int
    {
        return $this->multipleQuantityCart;
    }

    public function setMultipleQuantityCart(int $multipleQuantityCart): void
    {
        $this->multipleQuantityCart = $multipleQuantityCart;
    }

    public function getMultipleQuantityDepot(): int
    {
        return $this->multipleQuantityDepot;
    }

    public function setMultipleQuantityDepot(int $multipleQuantityDepot): void
    {
        $this->multipleQuantityDepot = $multipleQuantityDepot;
    }

    public function isFreeShippingWithBottle(): bool
    {
        return $this->freeShippingWithBottle;
    }

    public function setFreeShippingWithBottle(bool $freeShippingWithBottle): void
    {
        $this->freeShippingWithBottle = $freeShippingWithBottle;
    }

    public function isDisabledShippingManu(): bool
    {
        return $this->disabledShippingManu;
    }

    public function setDisabledShippingManu(bool $disabledShippingManu): void
    {
        $this->disabledShippingManu = $disabledShippingManu;
    }

    public function isDisabledShippingAuto(): bool
    {
        return $this->disabledShippingAuto;
    }

    public function setDisabledShippingAuto(bool $disabledShippingAuto): void
    {
        $this->disabledShippingAuto = $disabledShippingAuto;
    }

    public function isAccessory(): bool
    {
        return $this->accessory;
    }

    public function setAccessory(bool $accessory): void
    {
        $this->accessory = $accessory;
    }

    public function getOrderWithaMinimumEquivalency(): ?int
    {
        return $this->orderWithaMinimumEquivalency;
    }

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

    public function getMinFreeShippingWithBottle(): ?int
    {
        return $this->minFreeShippingWithBottle;
    }

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

    public function addZonesFreeShipping(ShippingZone $zone): self
    {
        if (!$this->zonesFreeShipping->contains($zone)) {
            $this->zonesFreeShipping->add($zone);
        }

        return $this;
    }

    public function removeZonesFreeShipping(ShippingZone $zone): void
    {
        $this->zonesFreeShipping->removeElement($zone);
    }

    /**
     * @return Collection<int, ShippingZone>
     */
    public function getZonesFreeShipping(): Collection
    {
        return $this->zonesFreeShipping;
    }

    public function getZonesFreeShippingId(): array
    {
        $id = [];

        foreach ($this->zonesFreeShipping as $zone) {
            $id[] = $zone->getId()->toString();
        }

        return $id;
    }

    /**
     * @return Collection<int, ProductTypeOption>
     */
    public function getOptions(): Collection
    {
        return $this->options;
    }
}
