<?php

namespace Webapp\Core\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Core\Serializer\Filter\GroupFilter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Webapp\Core\Enumeration\PathLevelEnum;
use Webapp\Core\Enumeration\VariableTypeEnum;
use Webapp\Core\Validator\UniqueAttributeInParent;

/**
 * @ApiResource(
 *     collectionOperations={
 *          "get"={"security"="is_granted('ROLE_PLATFORM_MANAGER')"},
 *          "post"={
 *              "security_post_denormalize"="object.getDevice().getProject() !== null"
 *          }
 *     },
 *     itemOperations={
 *          "get"={"security"="is_granted('ROLE_PLATFORM_MANAGER', object.getDevice().getSite())"},
 *          "patch"={
 *              "security_post_denormalize"="is_granted('ROLE_PLATFORM_MANAGER', object.getDevice().getSite())"
 *          }
 *     }
 * )
 *
 * @ApiFilter(SearchFilter::class, properties={"site": "exact", "generatorVariable": "exact", "projectData.sessions": "exact", "projectData": "exact"})
 * @ApiFilter(GroupFilter::class, arguments={"whitelist"={"project_explorer_view", "connected_variables"}})
 *
 * @ORM\Entity()
 *
 * @ORM\Table(name="variable_semi_automatic", schema="webapp")
 *
 * @psalm-import-type VariableTypeEnumId from VariableTypeEnum
 * @psalm-import-type PathLevelEnumId from PathLevelEnum
 */
class SemiAutomaticVariable extends AbstractVariable
{
    /**
     * @ORM\Column(type="string", nullable=false)
     *
     * @Groups({"project_explorer_view", "semi_automatic_variable", "webapp_data_view", "data_explorer_view", "data_entry_synthesis", "project_synthesis", "variable_synthesis", "fusion_result", "webapp_data_path", "webapp_data_fusion"})
     *
     * @Assert\NotBlank
     *
     * @UniqueAttributeInParent(parentsAttributes={"device.managedVariables"})
     */
    protected string $name;

    /**
     * @ORM\Column(type="integer", name="frame_start")
     *
     * @Groups({"semi_automatic_variable"})
     */
    private int $start;

    /**
     * @ORM\Column(type="integer", name="frame_end")
     *
     * @Groups({"semi_automatic_variable"})
     */
    private int $end;

    /**
     * @psalm-var VariableTypeEnumId|''
     *
     * @ORM\Column(type="string", nullable=false)
     *
     * @Groups({"semi_automatic_variable", "webapp_data_view", "data_entry_synthesis", "project_synthesis", "variable_synthesis", "webapp_data_path", "webapp_data_fusion"})
     */
    protected string $type;

    /**
     * @ORM\ManyToOne(targetEntity="Webapp\Core\Entity\Device", inversedBy="managedVariables", cascade={"persist"})
     *
     * @Groups({"data_explorer_view"})
     */
    private ?Device $device;

    /**
     * @var Collection<int, Test>
     *
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Test",mappedBy="variableSemiAutomatic", cascade={"persist", "remove"}, orphanRemoval=true)
     *
     * @Groups({"project_explorer_view", "project_synthesis", "variable_synthesis"})
     */
    protected Collection $tests;

    /**
     * @var Collection<int, VariableConnection>
     *
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\VariableConnection", mappedBy="projectSemiAutomaticVariable", cascade={"persist", "remove"}, orphanRemoval=true)
     *
     * @Groups({"project_explorer_view", "connected_variables", "project_synthesis"})
     */
    protected Collection $connectedVariables;

    /**
     * @ORM\ManyToOne(targetEntity="Webapp\Core\Entity\ProjectData", inversedBy="semiAutomaticVariables")
     */
    protected ?ProjectData $projectData = null;

    /**
     * @param PathLevelEnumId|''    $pathLevel
     * @param VariableTypeEnumId|'' $type
     */
    public function __construct(string $name = '', string $shortName = '', int $repetitions = 0, string $pathLevel = '', bool $mandatory = false, string $type = '', int $start = 0, int $end = 0)
    {
        parent::__construct();
        $this->name = $name; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->shortName = $shortName; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->repetitions = $repetitions; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->pathLevel = $pathLevel; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->mandatory = $mandatory; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->type = $type; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->start = $start; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->end = $end; // TODO delete when https://github.com/api-platform/core/issues/3974 is solved
        $this->tests = new ArrayCollection();
    }

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

    /**
     * @psalm-param VariableTypeEnumId|'' $type
     *
     * @return $this
     */
    public function setType(string $type): self
    {
        $this->type = $type;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getStart(): int
    {
        return $this->start;
    }

    /**
     * @return $this
     */
    public function setStart(int $start): self
    {
        $this->start = $start;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getEnd(): int
    {
        return $this->end;
    }

    /**
     * @return $this
     */
    public function setEnd(int $end): self
    {
        $this->end = $end;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getDevice(): ?Device
    {
        return $this->device;
    }

    /**
     * @return $this
     */
    public function setDevice(?Device $device): self
    {
        $this->device = $device;

        return $this;
    }

    /**
     * @psalm-mutation-free
     */
    public function getProject(): ?Project
    {
        return null !== $this->device ? $this->device->getProject() : null;
    }

    /**
     * @psalm-mutation-free
     */
    public function getProjectData(): ?ProjectData
    {
        return $this->projectData;
    }

    /**
     * @return $this
     */
    public function setProjectData(?ProjectData $projectData): self
    {
        $this->projectData = $projectData;

        return $this;
    }
}
