<?php

declare(strict_types=1);

namespace App\Entity;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use App\Repository\TypeMachineRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity(repositoryClass: TypeMachineRepository::class)]
#[ORM\Table(name: 'type_machines')]
#[ORM\HasLifecycleCallbacks]
#[UniqueEntity(fields: ['name'], message: 'Ce nom de type de machine existe déjà.')]
#[ApiResource(
    operations: [
        new Get(),
        new GetCollection(),
        new Post(),
        new Put(),
        new Delete(),
    ],
    paginationClientItemsPerPage: true,
    paginationMaximumItemsPerPage: 500
)]
class TypeMachine
{
    #[ORM\Id]
    #[ORM\Column(type: Types::STRING, length: 36)]
    #[Groups(['type_machine:read'])]
    private ?string $id = null;

    #[ORM\Column(type: Types::STRING, length: 255, unique: true)]
    #[Assert\NotBlank]
    #[Groups(['type_machine:read', 'type_machine:write', 'machine:read'])]
    private string $name;

    #[ORM\Column(type: Types::TEXT, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?string $description = null;

    #[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?string $category = null;

    #[ORM\Column(type: Types::STRING, length: 255, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?string $maintenanceFrequency = null;

    #[ORM\Column(type: Types::JSON, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?array $components = null;

    #[ORM\Column(type: Types::JSON, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?array $criticalParts = null;

    #[ORM\Column(type: Types::JSON, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?array $machinePieces = null;

    #[ORM\Column(type: Types::JSON, nullable: true)]
    #[Groups(['type_machine:read', 'type_machine:write'])]
    private ?array $specifications = null;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'createdAt')]
    #[Groups(['type_machine:read'])]
    private DateTimeImmutable $createdAt;

    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updatedAt')]
    #[Groups(['type_machine:read'])]
    private DateTimeImmutable $updatedAt;

    /**
     * @var Collection<int, Machine>
     */
    #[ORM\OneToMany(targetEntity: Machine::class, mappedBy: 'typeMachine')]
    private Collection $machines;

    /**
     * @var Collection<int, CustomField>
     */
    #[ORM\OneToMany(targetEntity: CustomField::class, mappedBy: 'typeMachine', cascade: ['persist', 'remove'])]
    #[ApiProperty(readableLink: true, writableLink: true)]
    private Collection $customFields;

    /**
     * @var Collection<int, TypeMachineComponentRequirement>
     */
    #[ORM\OneToMany(targetEntity: TypeMachineComponentRequirement::class, mappedBy: 'typeMachine', cascade: ['persist', 'remove'])]
    #[ApiProperty(readableLink: true, writableLink: true)]
    private Collection $componentRequirements;

    /**
     * @var Collection<int, TypeMachinePieceRequirement>
     */
    #[ORM\OneToMany(targetEntity: TypeMachinePieceRequirement::class, mappedBy: 'typeMachine', cascade: ['persist', 'remove'])]
    #[ApiProperty(readableLink: true, writableLink: true)]
    private Collection $pieceRequirements;

    /**
     * @var Collection<int, TypeMachineProductRequirement>
     */
    #[ORM\OneToMany(targetEntity: TypeMachineProductRequirement::class, mappedBy: 'typeMachine', cascade: ['persist', 'remove'])]
    #[ApiProperty(readableLink: true, writableLink: true)]
    private Collection $productRequirements;

    public function __construct()
    {
        $this->id                    = 'cl'.bin2hex(random_bytes(12));
        $this->createdAt             = new DateTimeImmutable();
        $this->updatedAt             = new DateTimeImmutable();
        $this->machines              = new ArrayCollection();
        $this->customFields          = new ArrayCollection();
        $this->componentRequirements = new ArrayCollection();
        $this->pieceRequirements     = new ArrayCollection();
        $this->productRequirements   = new ArrayCollection();
    }

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

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): static
    {
        $this->name = $name;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(?string $description): static
    {
        $this->description = $description;

        return $this;
    }

    public function getCategory(): ?string
    {
        return $this->category;
    }

    public function setCategory(?string $category): static
    {
        $this->category = $category;

        return $this;
    }

    public function getMaintenanceFrequency(): ?string
    {
        return $this->maintenanceFrequency;
    }

    public function setMaintenanceFrequency(?string $maintenanceFrequency): static
    {
        $this->maintenanceFrequency = $maintenanceFrequency;

        return $this;
    }

    public function getComponents(): ?array
    {
        return $this->components;
    }

    public function setComponents(?array $components): static
    {
        $this->components = $components;

        return $this;
    }

    public function getCriticalParts(): ?array
    {
        return $this->criticalParts;
    }

    public function setCriticalParts(?array $criticalParts): static
    {
        $this->criticalParts = $criticalParts;

        return $this;
    }

    public function getMachinePieces(): ?array
    {
        return $this->machinePieces;
    }

    public function setMachinePieces(?array $machinePieces): static
    {
        $this->machinePieces = $machinePieces;

        return $this;
    }

    public function getSpecifications(): ?array
    {
        return $this->specifications;
    }

    public function setSpecifications(?array $specifications): static
    {
        $this->specifications = $specifications;

        return $this;
    }

    public function getCreatedAt(): DateTimeImmutable
    {
        return $this->createdAt;
    }

    public function getUpdatedAt(): DateTimeImmutable
    {
        return $this->updatedAt;
    }

    /**
     * @return Collection<int, Machine>
     */
    public function getMachines(): Collection
    {
        return $this->machines;
    }

    public function addMachine(Machine $machine): static
    {
        if (!$this->machines->contains($machine)) {
            $this->machines->add($machine);
            $machine->setTypeMachine($this);
        }

        return $this;
    }

    public function removeMachine(Machine $machine): static
    {
        if ($this->machines->removeElement($machine)) {
            if ($machine->getTypeMachine() === $this) {
                $machine->setTypeMachine(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection<int, CustomField>
     */
    public function getCustomFields(): Collection
    {
        return $this->customFields;
    }

    public function addCustomField(CustomField $customField): static
    {
        if (!$this->customFields->contains($customField)) {
            $this->customFields->add($customField);
            $customField->setTypeMachine($this);
        }

        return $this;
    }

    public function removeCustomField(CustomField $customField): static
    {
        if ($this->customFields->removeElement($customField)) {
            if ($customField->getTypeMachine() === $this) {
                $customField->setTypeMachine(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection<int, TypeMachineComponentRequirement>
     */
    public function getComponentRequirements(): Collection
    {
        return $this->componentRequirements;
    }

    public function addComponentRequirement(TypeMachineComponentRequirement $componentRequirement): static
    {
        if (!$this->componentRequirements->contains($componentRequirement)) {
            $this->componentRequirements->add($componentRequirement);
            $componentRequirement->setTypeMachine($this);
        }

        return $this;
    }

    public function removeComponentRequirement(TypeMachineComponentRequirement $componentRequirement): static
    {
        if ($this->componentRequirements->removeElement($componentRequirement)) {
            if ($componentRequirement->getTypeMachine() === $this) {
                $componentRequirement->setTypeMachine(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection<int, TypeMachinePieceRequirement>
     */
    public function getPieceRequirements(): Collection
    {
        return $this->pieceRequirements;
    }

    public function addPieceRequirement(TypeMachinePieceRequirement $pieceRequirement): static
    {
        if (!$this->pieceRequirements->contains($pieceRequirement)) {
            $this->pieceRequirements->add($pieceRequirement);
            $pieceRequirement->setTypeMachine($this);
        }

        return $this;
    }

    public function removePieceRequirement(TypeMachinePieceRequirement $pieceRequirement): static
    {
        if ($this->pieceRequirements->removeElement($pieceRequirement)) {
            if ($pieceRequirement->getTypeMachine() === $this) {
                $pieceRequirement->setTypeMachine(null);
            }
        }

        return $this;
    }

    /**
     * @return Collection<int, TypeMachineProductRequirement>
     */
    public function getProductRequirements(): Collection
    {
        return $this->productRequirements;
    }

    public function addProductRequirement(TypeMachineProductRequirement $productRequirement): static
    {
        if (!$this->productRequirements->contains($productRequirement)) {
            $this->productRequirements->add($productRequirement);
            $productRequirement->setTypeMachine($this);
        }

        return $this;
    }

    public function removeProductRequirement(TypeMachineProductRequirement $productRequirement): static
    {
        if ($this->productRequirements->removeElement($productRequirement)) {
            if ($productRequirement->getTypeMachine() === $this) {
                $productRequirement->setTypeMachine(null);
            }
        }

        return $this;
    }

    #[ORM\PrePersist]
    public function setCreatedAtValue(): void
    {
        $this->createdAt = new DateTimeImmutable();
        $this->updatedAt = new DateTimeImmutable();
    }

    #[ORM\PreUpdate]
    public function setUpdatedAtValue(): void
    {
        $this->updatedAt = new DateTimeImmutable();
    }
}
