<?php

declare(strict_types=1);

namespace App\Entity\Booking;

use App\Attribute\ActivityYearConstraintAware;
use App\Attribute\OrganizationDefaultValue;
use App\Entity\Access\Access;
use App\Entity\Core\Tagg;
use App\Entity\Product\Equipment;
use App\Entity\Traits\ActivityYearTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * Données d'un évènement générique, classe de base des évènements.
 *
 * @see Event, Course, EducationalProject, Examen, OrganizationHoliday, PersonHoliday
 */
#[ActivityYearConstraintAware(startYearFieldName: 'startYear', endYearFieldName: 'endYear')]
#[OrganizationDefaultValue(fieldName: 'organization')]
#[ORM\Entity]
#[ORM\Table(name: 'Booking')]
#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'discr', type: 'string')]
#[ORM\DiscriminatorMap(
    [
        'educationalproject' => EducationalProject::class,
        'course' => Course::class,
        'event' => Event::class,
        'examen' => Examen::class,
        'organizationholiday' => OrganizationHoliday::class,
        'personholiday' => PersonHoliday::class,
    ]
)]
abstract class AbstractBooking
{
    use ActivityYearTrait;

    #[ORM\Id]
    #[ORM\Column]
    #[ORM\GeneratedValue]
    protected ?int $id = null;

    #[ORM\Column]
    protected string $name;

    /** @var Collection<int, Access> */
    #[ORM\ManyToMany(targetEntity: Access::class, inversedBy: 'educationalProjectOrganizers')]
    #[ORM\JoinTable(name: 'booking_organizer')]
    #[ORM\JoinColumn(name: 'booking_id', referencedColumnName: 'id')]
    #[ORM\InverseJoinColumn(name: 'organizer_id', referencedColumnName: 'id')]
    protected Collection $organizer;

    #[ORM\Column(type: 'datetime', nullable: true)]
    protected ?\DateTimeInterface $datetimeStart = null;

    #[ORM\Column(type: 'datetime', nullable: true)]
    protected ?\DateTimeInterface $datetimeEnd = null;

    /** @var Collection<int, Equipment> */
    #[ORM\ManyToMany(targetEntity: Equipment::class, cascade: [], orphanRemoval: false)]
    #[ORM\JoinTable(name: 'booking_equipment')]
    #[ORM\JoinColumn(name: 'booking_id')]
    #[ORM\InverseJoinColumn(name: 'equipment_id')]
    protected Collection $equipments;

    #[ORM\Column(unique: true)]
    protected string $uuid;

    /** @var Collection<int, Tagg> */
    #[ORM\ManyToMany(targetEntity: Tagg::class, inversedBy: 'bookings', cascade: ['persist'], orphanRemoval: false)]
    #[ORM\JoinTable(name: 'tag_booking')]
    #[ORM\JoinColumn(name: 'booking_id')]
    #[ORM\InverseJoinColumn(name: 'tag_id')]
    protected Collection $tags;

    public function __construct()
    {
        $this->organizer = new ArrayCollection();
        $this->equipments = new ArrayCollection();
        $this->tags = new ArrayCollection();
    }

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

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

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

        return $this;
    }

    public function getOrganizer(): Collection
    {
        return $this->organizer;
    }

    public function addOrganizer(Access $organizer): self
    {
        if (!$this->organizer->contains($organizer)) {
            $this->organizer[] = $organizer;
        }

        return $this;
    }

    public function removeOrganizer(Access $organizer): self
    {
        $this->organizer->removeElement($organizer);

        return $this;
    }

    public function setDatetimeStart(?\DateTimeInterface $datetimeStart = null): self
    {
        $this->datetimeStart = $datetimeStart;

        return $this;
    }

    public function getDatetimeStart(): ?\DateTimeInterface
    {
        return $this->datetimeStart;
    }

    public function setDatetimeEnd(?\DateTimeInterface $datetimeEnd = null): self
    {
        $this->datetimeEnd = $datetimeEnd;

        return $this;
    }

    public function getDatetimeEnd(): ?\DateTimeInterface
    {
        return $this->datetimeEnd;
    }

    public function getEquipments(): Collection
    {
        return $this->equipments;
    }

    public function addEquipment(Equipment $equipment): self
    {
        $this->equipments[] = $equipment;

        return $this;
    }

    public function removeEquipment(Equipment $equipment): self
    {
        $this->equipments->removeElement($equipment);

        return $this;
    }

    public function getUuid(): string
    {
        return $this->uuid;
    }

    public function setUuid(string $uuid): self
    {
        $this->uuid = $uuid;

        return $this;
    }

    public function getTags(): Collection
    {
        return $this->tags;
    }

    public function addTag(Tagg $tag): self
    {
        if (!$this->tags->contains($tag)) {
            $this->tags[] = $tag;
            $tag->addBooking($this);
        }

        return $this;
    }

    public function removeTag(Tagg $tag): self
    {
        if ($this->tags->removeElement($tag)) {
            $tag->removeBooking($this);
        }

        return $this;
    }
}
