<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\EventBundle\Entity;

use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Chill\MainBundle\Entity\HasCenterInterface;
use Chill\MainBundle\Entity\HasScopeInterface;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation as Serializer;

/**
 * Class Event.
 */
#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
#[ORM\Table(name: 'chill_event_event')]
class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInterface, TrackUpdateInterface
{
    use TrackCreationTrait;
    use TrackUpdateTrait;

    #[Assert\NotNull]
    #[ORM\ManyToOne(targetEntity: Center::class)] // A
    private ?Center $center = null;

    #[ORM\ManyToOne(targetEntity: Scope::class)]
    private ?Scope $circle = null;

    #[ORM\Column(type: Types::DATETIME_MUTABLE)]
    private ?\DateTime $date = null;

    #[ORM\Id]
    #[ORM\Column(name: 'id', type: Types::INTEGER)]
    #[ORM\GeneratedValue(strategy: 'AUTO')]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: User::class)]
    private ?User $moderator = null;

    /**
     * @var Collection<int, User>
     */
    #[ORM\ManyToMany(targetEntity: User::class)]
    #[Serializer\Groups(['read'])]
    #[ORM\JoinTable('chill_event_animatorsintern')]
    private Collection $animatorsIntern;

    /**
     * @var Collection<int, ThirdParty>
     */
    #[ORM\ManyToMany(targetEntity: ThirdParty::class)]
    #[Serializer\Groups(['read'])]
    #[ORM\JoinTable('chill_event_animatorsextern')]
    private Collection $animatorsExtern;

    #[Assert\NotBlank]
    #[Serializer\Groups(['read'])]
    #[ORM\Column(type: Types::STRING, length: 150)]
    private ?string $name = null;

    /**
     * @var Collection<int, Participation>
     */
    #[ORM\OneToMany(mappedBy: 'event', targetEntity: Participation::class)]
    #[Serializer\Groups(['read'])]
    private Collection $participations;

    #[Assert\NotNull]
    #[Serializer\Groups(['read'])]
    #[ORM\ManyToOne(targetEntity: EventType::class)]
    private ?EventType $type = null;

    /**
     * @var Collection<int, EventTheme>
     */
    #[ORM\ManyToMany(targetEntity: EventTheme::class)]
    #[Serializer\Groups(['read'])]
    #[ORM\JoinTable('chill_event_eventtheme')]
    private Collection $themes;

    #[ORM\Embedded(class: CommentEmbeddable::class, columnPrefix: 'comment_')]
    private CommentEmbeddable $comment;

    #[ORM\ManyToOne(targetEntity: Location::class)]
    #[Serializer\Groups(['read'])]
    #[ORM\JoinColumn(nullable: true)]
    private ?Location $location = null;

    /**
     * @var Collection<int, StoredObject>
     */
    #[ORM\ManyToMany(targetEntity: StoredObject::class, cascade: ['persist', 'refresh'])]
    #[ORM\JoinTable('chill_event_event_documents')]
    private Collection $documents;

    /**
     * @var Collection<int, EventBudgetElement>
     */
    #[ORM\OneToMany(mappedBy: 'event', targetEntity: EventBudgetElement::class, cascade: ['persist'])]
    #[Serializer\Groups(['read'])]
    private Collection $budgetElements;

    /**
     * @deprecated use budgetElements instead
     */
    #[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 4, nullable: true, options: ['default' => '0.0'])]
    private string $organizationCost = '0.0';

    /**
     * Event constructor.
     */
    public function __construct()
    {
        $this->participations = new ArrayCollection();
        $this->documents = new ArrayCollection();
        $this->comment = new CommentEmbeddable();
        $this->themes = new ArrayCollection();
        $this->budgetElements = new ArrayCollection();
        $this->animatorsIntern = new ArrayCollection();
        $this->animatorsExtern = new ArrayCollection();
    }

    public function addBudgetElement(EventBudgetElement $budgetElement)
    {
        if (!$this->budgetElements->contains($budgetElement)) {
            $this->budgetElements[] = $budgetElement;
            $budgetElement->setEvent($this);
        }

        return $this;
    }

    /**
     * Add participation.
     *
     * @return Event
     */
    public function addParticipation(Participation $participation)
    {
        $this->participations[] = $participation;

        return $this;
    }

    public function addDocument(StoredObject $storedObject): self
    {
        if ($this->documents->contains($storedObject)) {
            $this->documents[] = $storedObject;
        }

        return $this;
    }

    public function removeDocument(StoredObject $storedObject): self
    {
        $this->documents->removeElement($storedObject);

        return $this;
    }

    public function getThemes(): Collection
    {
        return $this->themes;
    }

    public function addTheme(EventTheme $theme): self
    {
        $this->themes->add($theme);

        return $this;
    }

    public function removeTheme(EventTheme $theme): void
    {
        $this->themes->removeElement($theme);
    }

    public function getAnimatorsIntern(): Collection
    {
        return $this->animatorsIntern;
    }

    public function getAnimatorsExtern(): Collection
    {
        return $this->animatorsExtern;
    }

    public function addAnimatorsIntern(User $ai): self
    {
        $this->animatorsIntern->add($ai);

        return $this;
    }

    public function removeAnimatorsIntern(User $ai): void
    {
        $this->animatorsIntern->removeElement($ai);
    }

    public function addAnimatorsExtern(ThirdParty $ae): self
    {
        $this->animatorsExtern->add($ae);

        return $this;
    }

    public function removeAnimatorsExtern(ThirdParty $ae): void
    {
        $this->animatorsExtern->removeElement($ae);
    }

    public function getCenter(): Center
    {
        return $this->center;
    }

    public function getCircle(): ?Scope
    {
        return $this->circle;
    }

    /**
     * Get date.
     */
    public function getDate(): ?\DateTime
    {
        return $this->date;
    }

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

    public function getModerator(): ?User
    {
        return $this->moderator;
    }

    /**
     * Get label.
     */
    public function getName(): ?string
    {
        return $this->name;
    }

    /**
     * @return Collection<int, EventBudgetElement>
     */
    public function getBudgetElements(): Collection
    {
        return $this->budgetElements;
    }

    /**
     * @return Collection<int, Participation>
     */
    public function getParticipations(): Collection
    {
        return new ArrayCollection(iterator_to_array($this->getParticipationsOrdered()));
    }

    /**
     * Sort Collection of Participations.
     */
    public function getParticipationsOrdered(): \ArrayIterator|\Traversable
    {
        $iterator = iterator_to_array($this->participations->getIterator());

        uasort($iterator, static fn ($first, $second) => strnatcasecmp($first->getPerson()->getFirstName(), $second->getPerson()->getFirstName()));

        return new \ArrayIterator($iterator);
    }

    /**
     * @deprecated
     */
    public function getScope(): Scope
    {
        return $this->getCircle();
    }

    public function getType(): ?EventType
    {
        return $this->type;
    }

    public function removeBudgetElement(EventBudgetElement $budgetElement): void
    {
        $this->budgetElements->removeElement($budgetElement);
    }

    /**
     * Remove participation.
     */
    public function removeParticipation(Participation $participation): void
    {
        $this->participations->removeElement($participation);
    }

    /**
     * @return $this
     */
    public function setCenter(Center $center)
    {
        $this->center = $center;

        return $this;
    }

    /**
     * @return $this
     */
    public function setCircle(Scope $circle)
    {
        $this->circle = $circle;

        return $this;
    }

    /**
     * Set date.
     *
     * @return Event
     */
    public function setDate(\DateTime $date)
    {
        $this->date = $date;

        return $this;
    }

    public function setModerator(User $moderator): self
    {
        $this->moderator = $moderator;

        return $this;
    }

    /**
     * Set label.
     *
     * @return Event
     */
    public function setName(?string $label)
    {
        $this->name = $label;

        return $this;
    }

    /**
     * @return $this
     */
    public function setType(EventType $type)
    {
        $this->type = $type;

        return $this;
    }

    public function getComment(): CommentEmbeddable
    {
        return $this->comment;
    }

    public function setComment(CommentEmbeddable $comment): void
    {
        $this->comment = $comment;
    }

    public function getLocation(): ?Location
    {
        return $this->location;
    }

    public function setLocation(?Location $location): void
    {
        $this->location = $location;
    }

    public function getDocuments(): Collection
    {
        return $this->documents;
    }

    public function setDocuments(Collection $documents): void
    {
        $this->documents = $documents;
    }

    /**
     * @deprecated
     */
    public function getOrganizationCost(): string
    {
        return $this->organizationCost;
    }

    /**
     * @deprecated
     */
    public function setOrganizationCost(string $organizationCost): void
    {
        $this->organizationCost = $organizationCost;
    }
}
