<?php

namespace Mobile\Measure\Entity\Variable;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Mobile\Measure\Entity\Variable\Base\Variable;
use Mobile\Project\Entity\DataEntryProject;
use Shared\Authentication\Entity\IdentifiedEntity;
use Shared\Utils\ArrayCollectionUtils;

/**
 * @ORM\Entity()
 *
 * @ORM\Table(name="material", schema="adonis")
 */
class Material extends IdentifiedEntity
{
    /**
     * @ORM\Column(type="string", nullable=false)
     */
    private string $name = '';

    /**
     * @ORM\Column(type="string", nullable=false)
     */
    private string $physicalDevice = '';

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private ?string $manufacturer = null;

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private ?string $type = null;

    /**
     * @ORM\OneToOne(targetEntity="Mobile\Measure\Entity\Variable\Driver", inversedBy="material", cascade={"persist","remove", "detach"})
     */
    private Driver $driver;

    /**
     * @var Collection<int, UniqueVariable>
     *
     * @ORM\OneToMany(targetEntity="Mobile\Measure\Entity\Variable\UniqueVariable", mappedBy="material", cascade={"persist","remove", "detach"})
     */
    private Collection $uniqueVariables;

    /**
     * @var Collection<int, GeneratorVariable>
     *
     * @ORM\OneToMany(targetEntity="Mobile\Measure\Entity\Variable\GeneratorVariable", mappedBy="material", cascade={"persist","remove", "detach"})
     */
    private Collection $generatorVariables;

    /**
     * @ORM\ManyToOne(targetEntity="Mobile\Project\Entity\DataEntryProject", inversedBy="materials")
     *
     * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
     */
    private DataEntryProject $project;

    public function __construct()
    {
        $this->generatorVariables = new ArrayCollection();
        $this->uniqueVariables = new ArrayCollection();
    }

    /**
     * @psalm-mutation-free
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @return $this
     */
    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getPhysicalDevice(): string
    {
        return $this->physicalDevice;
    }

    /**
     * @return $this
     */
    public function setPhysicalDevice(string $physicalDevice): self
    {
        $this->physicalDevice = $physicalDevice;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getManufacturer(): ?string
    {
        return $this->manufacturer;
    }

    /**
     * @return $this
     */
    public function setManufacturer(?string $manufacturer): self
    {
        $this->manufacturer = $manufacturer;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getType(): ?string
    {
        return $this->type;
    }

    /**
     * @return $this
     */
    public function setType(?string $type): self
    {
        $this->type = $type;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getDriver(): Driver
    {
        return $this->driver;
    }

    /**
     * @return $this
     */
    public function setDriver(Driver $driver): self
    {
        $this->driver = $driver;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getUniqueVariables(): Collection
    {
        return $this->uniqueVariables;
    }

    /**
     * @param iterable<array-key, UniqueVariable> $uniqueVariables
     *
     * @return $this
     */
    public function setUniqueVariables(iterable $uniqueVariables): self
    {
        ArrayCollectionUtils::update($this->uniqueVariables, $uniqueVariables, function (UniqueVariable $uniqueVariable) {
            $uniqueVariable->setMaterial($this);
        });

        return $this;
    }

    /**
     * @return $this
     */
    public function addUniqueVariable(UniqueVariable $uniqueVariable): self
    {
        if (!$this->uniqueVariables->contains($uniqueVariable)) {
            $uniqueVariable->setMaterial($this);
            $this->uniqueVariables->add($uniqueVariable);
        }

        return $this;
    }

    /**
     * @return $this
     */
    public function removeUniqueVariable(UniqueVariable $uniqueVariable): self
    {
        if ($this->uniqueVariables->contains($uniqueVariable)) {
            $this->uniqueVariables->removeElement($uniqueVariable);
        }

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getGeneratorVariables(): Collection
    {
        return $this->generatorVariables;
    }

    /**
     * @param iterable<array-key, GeneratorVariable> $generatorVariables
     *
     * @return $this
     */
    public function setGeneratorVariables(iterable $generatorVariables): self
    {
        ArrayCollectionUtils::update($this->generatorVariables, $generatorVariables, function (GeneratorVariable $generatorVariable) {
            $generatorVariable->setMaterial($this);
        });

        return $this;
    }

    /**
     * @return $this
     */
    public function addGeneratorVariable(GeneratorVariable $generatorVariable): self
    {
        if (!$this->generatorVariables->contains($generatorVariable)) {
            $this->generatorVariables->add($generatorVariable);
            $generatorVariable->setMaterial($this);
        }

        return $this;
    }

    /**
     * @return $this
     */
    public function removeGeneratorVariable(GeneratorVariable $generatorVariable): self
    {
        if ($this->generatorVariables->contains($generatorVariable)) {
            $this->generatorVariables->removeElement($generatorVariable);
        }

        return $this;
    }

    /**
     * @param Variable[] $variables
     *
     * @return $this
     */
    public function setVariables(array $variables): self
    {
        $this->setUniqueVariables(array_filter($variables, fn (Variable $variable) => $variable instanceof UniqueVariable));
        $this->setGeneratorVariables(array_filter($variables, fn (Variable $variable) => $variable instanceof GeneratorVariable));

        return $this;
    }

    /**
     * @return $this
     */
    public function addVariable(Variable $variable): self
    {
        if ($variable instanceof UniqueVariable) {
            $this->addUniqueVariable($variable);
        } elseif ($variable instanceof GeneratorVariable) {
            $this->addGeneratorVariable($variable);
        }

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getProject(): DataEntryProject
    {
        return $this->project;
    }

    /**
     * @return $this
     */
    public function setProject(DataEntryProject $project): self
    {
        $this->project = $project;

        return $this;
    }
}
