<?php


namespace Webapp\Core\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Serializer\Filter\GroupFilter;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
use Shared\Authentication\Entity\IdentifiedEntity;
use Symfony\Component\Serializer\Annotation\Groups;
use Webapp\Core\Annotation\GraphicallyDeletable;
use Webapp\Core\Traits\GraphicallyDeletableEntity;
use Webapp\Core\Traits\GraphicallyDeletedAtEntity;

/**
 * Class Individual
 * @package Webapp\Core\Entity
 *
 * @ApiResource(
 *     collectionOperations={
 *          "get"={}
 *     },
 *     itemOperations={
 *          "get"={},
 *          "patch"={"denormalization_context"={"groups"={"declare_dead", "edit"}}}
 *     }
 * )
 *
 * @ApiFilter(SearchFilter::class, properties={"unitPlot": "exact"})
 * @ApiFilter(GroupFilter::class, arguments={"whitelist"={"design_explorer_view", "platform_full_view", "parent_view"}})
 *
 * @Gedmo\SoftDeleteable()
 * @GraphicallyDeletable()
 *
 * @ORM\Entity()
 * @ORM\Table(name="individual", schema="webapp")
 */
class Individual extends IdentifiedEntity implements BusinessObject
{
    use GraphicallyDeletableEntity;

    use SoftDeleteableEntity;

    use OpenSilexEntity;

    use HasGeometryEntity;

    /**
     * @var string
     *
     * @ORM\Column(type="string")
     * @Groups({"design_explorer_view", "platform_full_view", "webapp_data_view", "fusion_result"})
     */
    private string $number;

    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @Groups({"design_explorer_view", "platform_full_view", "webapp_data_view", "change_report"})
     */
    private int $x;

    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @Groups({"design_explorer_view", "platform_full_view", "webapp_data_view", "change_report"})
     */
    private int $y;

    /**
     * @var bool
     *
     * @ORM\Column(type="boolean")
     * @Groups({"design_explorer_view", "platform_full_view", "webapp_data_view", "declare_dead"})
     */
    private bool $dead;

    /**
     * @var DateTime $appeared
     *
     * @Gedmo\Timestampable(on="change", field="dead", value=false)
     * @ORM\Column(type="datetime")
     * @Groups({"platform_full_view", "webapp_data_view", "change_report"})
     */
    private DateTime $appeared;

    /**
     * @var DateTime|null $disappeared
     *
     * @Gedmo\Timestampable(on="change", field="dead", value=true)
     * @ORM\Column(type="datetime", nullable=true)
     * @Groups({"platform_full_view", "webapp_data_view", "change_report"})
     */
    private ?DateTime $disappeared;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", nullable=true)
     * @Groups({"design_explorer_view", "platform_full_view", "webapp_data_view"})
     */
    private ?string $identifier;

    /**
     * @var float|null
     *
     * @ORM\Column(type="float", nullable=true)
     * @Groups({"design_explorer_view", "platform_full_view"})
     */
    private ?float $latitude;

    /**
     * @var float|null
     *
     * @ORM\Column(type="float", nullable=true)
     * @Groups({"design_explorer_view", "platform_full_view"})
     */
    private ?float $longitude;

    /**
     * @var float|null
     *
     * @ORM\Column(type="float", nullable=true)
     * @Groups({"design_explorer_view", "platform_full_view"})
     */
    private ?float $height;

    /**
     * @var UnitPlot
     *
     * @ORM\ManyToOne(targetEntity="Webapp\Core\Entity\UnitPlot", inversedBy="individuals")
     * @ORM\JoinColumn(nullable=false)
     * @Groups({"webapp_data_view", "parent_view", "change_report"})
     */
    private UnitPlot $unitPlot;

    /**
     * @var Collection|array<Note>
     *
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Note", mappedBy="individualTarget", cascade={"persist", "remove"}, orphanRemoval=true)
     * @Groups({"note_view"})
     * @ApiSubresource()
     */
    private $notes;

    /**
     * @var int|null
     * @ORM\Column(type="integer", nullable=true)
     * @Groups({"platform_full_view"})
     */
    private ?int $color;

    /**
     * @var string|null
     *
     * @ORM\Column(type="string", nullable=true)
     * @Groups({"platform_full_view", "edit"})
     */
    private ?string $comment;

    public function __construct()
    {
        $this->dead = false;
        $this->disappeared = null;
        $this->identifier = null;
        $this->latitude = null;
        $this->longitude = null;
        $this->height = null;
        $this->notes = new ArrayCollection();
        $this->color = null;
        $this->appeared = new DateTime();
        $this->comment = null;
        $this->openSilexInstance = null;
        $this->openSilexUri = null;
    }

    /**
     * @Groups({"platform_full_view"})
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return string
     */
    public function getNumber(): string
    {
        return $this->number;
    }

    /**
     * @param string $number
     * @return Individual
     */
    public function setNumber(string $number): Individual
    {
        $this->number = $number;
        return $this;
    }

    /**
     * @return int
     */
    public function getX(): int
    {
        return $this->x;
    }

    /**
     * @param int $x
     * @return Individual
     */
    public function setX(int $x): Individual
    {
        $this->x = $x;
        return $this;
    }

    /**
     * @return int
     */
    public function getY(): int
    {
        return $this->y;
    }

    /**
     * @param int $y
     * @return Individual
     */
    public function setY(int $y): Individual
    {
        $this->y = $y;
        return $this;
    }

    /**
     * @return bool
     */
    public function isDead(): bool
    {
        return $this->dead;
    }

    /**
     * @param bool $dead
     * @return Individual
     */
    public function setDead(bool $dead): Individual
    {
        $this->dead = $dead;
        return $this;
    }

    /**
     * @return DateTime
     */
    public function getAppeared(): DateTime
    {
        return $this->appeared;
    }

    /**
     * @param DateTime $appeared
     * @return Individual
     */
    public function setAppeared(DateTime $appeared): Individual
    {
        $this->appeared = $appeared;
        return $this;
    }

    /**
     * @return DateTime|null
     */
    public function getDisappeared(): ?DateTime
    {
        return $this->disappeared;
    }

    /**
     * @param DateTime|null $disappeared
     * @return Individual
     */
    public function setDisappeared(?DateTime $disappeared): Individual
    {
        $this->disappeared = $disappeared;
        return $this;
    }

    /**
     * @return string|null
     */
    public function getIdentifier(): ?string
    {
        return $this->identifier;
    }

    /**
     * @param string|null $identifier
     * @return Individual
     */
    public function setIdentifier(?string $identifier): Individual
    {
        $this->identifier = $identifier;
        return $this;
    }

    /**
     * @return float|null
     */
    public function getLatitude(): ?float
    {
        return $this->latitude;
    }

    /**
     * @param float|null $latitude
     * @return Individual
     */
    public function setLatitude(?float $latitude): Individual
    {
        $this->latitude = $latitude;
        return $this;
    }

    /**
     * @return float|null
     */
    public function getLongitude(): ?float
    {
        return $this->longitude;
    }

    /**
     * @param float|null $longitude
     * @return Individual
     */
    public function setLongitude(?float $longitude): Individual
    {
        $this->longitude = $longitude;
        return $this;
    }

    /**
     * @return float|null
     */
    public function getHeight(): ?float
    {
        return $this->height;
    }

    /**
     * @param float|null $height
     * @return Individual
     */
    public function setHeight(?float $height): Individual
    {
        $this->height = $height;
        return $this;
    }

    /**
     * @return UnitPlot
     */
    public function getUnitPlot(): UnitPlot
    {
        return $this->unitPlot;
    }

    /**
     * @param UnitPlot $unitPlot
     * @return Individual
     */
    public function setUnitPlot(UnitPlot $unitPlot): Individual
    {
        $this->unitPlot = $unitPlot;
        return $this;
    }

    /**
     * @return Collection|Note[]
     */
    public function getNotes()
    {
        return $this->notes;
    }

    /**
     * @param Collection|Note[] $notes
     * @return Individual
     */
    public function setNotes($notes)
    {
        $this->notes = $notes;
        return $this;
    }


    /**
     * @param Note $note
     * @return Individual
     */
    public function addNote($note)
    {
        if (!$this->notes->contains($note)) {
            $this->notes->add($note);
            $note->setTarget($this);
        }
        return $this;
    }

    /**
     * @param Note $note
     * @return Individual
     */
    public function removeNote($note)
    {
        if ($this->notes->contains($note)) {
            $this->notes->removeElement($note);
            $note->setTarget(null);
        }
        return $this;
    }

    /**
     * @return int|null
     */
    public function getColor(): ?int
    {
        return $this->color;
    }

    /**
     * @param int|null $color
     * @return Individual
     */
    public function setColor(?int $color): Individual
    {
        $this->color = $color;
        return $this;
    }

    /**
     * @return string|null
     */
    public function getComment(): ?string
    {
        return $this->comment;
    }

    /**
     * @param string|null $comment
     * @return Individual
     */
    public function setComment(?string $comment): Individual
    {
        $this->comment = $comment;
        return $this;
    }

    public function setDeletedAt(DateTime $deletedAt = null)
    {
        $this->deletedAt = $deletedAt;
        if($deletedAt === null){
            foreach ($this->getNotes() as $child){
                $child->setDeletedAt($deletedAt);
            }
        }

        return $this;
    }

    function parent(): ?BusinessObject
    {
        return $this->unitPlot;
    }

    function children(): array
    {
        return [];
    }

}
