<?php

namespace Shared\Authentication\Entity;

use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\ExistsFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
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 Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
use Shared\Authentication\CustomFilters\DeletedFilter;
use Shared\RightManagement\Controller\DeleteSiteAction;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Webapp\Core\Entity\Device;
use Webapp\Core\Entity\Experiment;
use Webapp\Core\Entity\Factor;
use Webapp\Core\Entity\GeneratorVariable;
use Webapp\Core\Entity\GraphicalConfiguration;
use Webapp\Core\Entity\OezNature;
use Webapp\Core\Entity\OpenSilexInstance;
use Webapp\Core\Entity\Platform;
use Webapp\Core\Entity\Protocol;
use Webapp\Core\Entity\SimpleVariable;
use Webapp\Core\Entity\StateCode;
use Webapp\Core\Entity\UserGroup;
use Webapp\Core\Entity\ValueList;
use Webapp\FileManagement\Entity\ParsingJob;

/**
 * Class Site
 * @ApiResource(
 *     collectionOperations={
 *         "get"={},
 *         "post"={
 *              "security_post_denormalize"="is_granted('SITE_POST', object)",
 *              "denormalization_context"={"groups"={"site_post"}}
 *          },
 *     },
 *     itemOperations={
 *         "get"={"security"="is_granted('SITE_GET', object)"},
 *         "put"={"security"="is_granted('SITE_EDIT', object)"},
 *         "patch"={"security"="is_granted('SITE_EDIT', object)"},
 *         "delete"={
 *              "controller"=DeleteSiteAction::class,
 *              "security"="is_granted('SITE_DELETE', object)"
 *          },
 *     }
 * )
 * @ApiFilter(OrderFilter::class, properties={"label"}, arguments={"orderParameterName"="order"})
 * @ApiFilter(SearchFilter::class, properties={"label": "ipartial", "id": "exact", "userRoles": "exact", "userRoles.user": "exact"})
 * @ApiFilter(ExistsFilter::class, properties={"userRoles", "deletedAt"})
 * @ApiFilter(GroupFilter::class, arguments={"whitelist"={
 *     "design_explorer_view",
 *     "admin_explorer_view",
 *     "project_explorer_view",
 *     "data_explorer_view",
 *     "transfer_explorer_view",
 *     "id_read",
 *     "user_admin_liste"
 * }})
 * @ApiFilter(DeletedFilter::class)
 *
 * @Gedmo\SoftDeleteable()
 *
 * @ORM\Entity(repositoryClass="Shared\Authentication\Repository\SiteRepository")
 * @ORM\Table(name="ado_site", schema="shared")
 */
class Site extends IdentifiedEntity
{

    use SoftDeleteableEntity;

    /**
     * @var string
     * @Groups({"site_post", "user_admin_liste", "change_report", "data_entry_synthesis", "platform_synthesis", "protocol_synthesis", "project_synthesis", "variable_synthesis"})
     * @Assert\NotBlank()
     * @ORM\Column(name="label", type="string", length=255, unique=true)
     */
    private $label;

    /**
     * @var Collection<array-key, RelUserSite>|array<RelUserSite>
     *
     * @Groups({"site_post", "user_admin_liste"})
     * @ORM\OneToMany(targetEntity="Shared\Authentication\Entity\RelUserSite", mappedBy="site", cascade={"remove", "persist"})
     */
    private $userRoles;

    /**
     * @var Collection<array-key, Factor>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Factor", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"design_explorer_view"})
     */
    private $factors;

    /**
     * @var Collection<array-key, Protocol>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Protocol", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"design_explorer_view"})
     */
    private $protocols;

    /**
     * @var Collection<array-key, UserGroup>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\UserGroup", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"admin_explorer_view"})
     */
    private $userGroups;

    /**
     * @var Collection<array-key, Experiment>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Experiment", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"design_explorer_view"})
     */
    private $experiments;

    /**
     * @var Collection<array-key, Platform>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Platform", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"design_explorer_view", "project_explorer_view", "data_explorer_view"})
     */
    private $platforms;

    /**
     * @var Collection<array-key, SimpleVariable>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\SimpleVariable", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"project_explorer_view"})
     */
    private $simpleVariables;

    /**
     * @var Collection<array-key, GeneratorVariable>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\GeneratorVariable", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"project_explorer_view"})
     */
    private $generatorVariables;

    /**
     * @var Collection<array-key, ValueList>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\ValueList", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"project_explorer_view"})
     */
    private $valueLists;

    /**
     * @var Collection<array-key, StateCode>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\StateCode", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"project_explorer_view"})
     */
    private $stateCodes;

    /**
     * @var Collection<array-key, Device>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\Device", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"project_explorer_view"})
     */
    private $devices;

    /**
     * @var Collection<array-key, OezNature>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\OezNature", mappedBy="site", cascade={"remove", "persist"})
     * @Groups({"design_explorer_view"})
     */
    private $oezNatures;

    /**
     * @var Collection<array-key, ParsingJob>
     * @ApiSubresource()
     * @ORM\OneToMany(targetEntity="Webapp\FileManagement\Entity\ParsingJob", mappedBy="site", cascade={"remove", "persist"})
     */
    private $parsingJobs;

    /**
     * @var GraphicalConfiguration | null
     * @ORM\OneToOne(targetEntity="Webapp\Core\Entity\GraphicalConfiguration", mappedBy="site", cascade={"remove"})
     */
    private $graphicalConfiguration;

    /**
     * @var Collection<array-key, OpenSilexInstance>
     * @ORM\OneToMany(targetEntity="Webapp\Core\Entity\OpenSilexInstance", mappedBy="site", cascade={"remove"})
     * @Groups({"design_explorer_view", "project_explorer_view", "data_explorer_view", "admin_explorer_view"})
     */
    private $openSilexInstances;

    public function __construct()
    {
        $this->userRoles = new ArrayCollection();
        $this->factors = new ArrayCollection();
        $this->protocols = new ArrayCollection();
        $this->userGroups = new ArrayCollection();
        $this->experiments = new ArrayCollection();
        $this->platforms = new ArrayCollection();
        $this->simpleVariables = new ArrayCollection();
        $this->generatorVariables = new ArrayCollection();
        $this->valueLists = new ArrayCollection();
        $this->stateCodes = new ArrayCollection();
        $this->devices = new ArrayCollection();
        $this->oezNatures = new ArrayCollection();
        $this->openSilexInstances = new ArrayCollection();
    }

    /**
     * @return array
     */
    public function getVariables(): array
    {
        return array_merge(
            $this->getSimpleVariables()->toArray(),
            array_reduce($this->getDevices()->toArray(), function ($acc, Device $device) {
                return [...$acc, ...$device->getManagedVariables()];
            }, []),
            $this->getGeneratorVariables()->toArray());
    }

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

    /**
     * @param string $label
     * @return Site
     */
    public function setLabel(string $label): Site
    {
        $this->label = $label;
        return $this;
    }

    /**
     * @return Collection|RelUserSite[]
     */
    public function getUserRoles()
    {
        return $this->userRoles;
    }

    /**
     * @param Collection|RelUserSite[] $userRoles
     * @return Site
     */
    public function setUserRoles($userRoles)
    {
        $this->userRoles = $userRoles;
        foreach ($userRoles as $userRole) {
            $userRole->setSite($this);
        }
        return $this;
    }

    public function addUserRole(RelUserSite $operator): void
    {
        if (!$this->userRoles->contains($operator)) {
            $this->userRoles->add($operator);
            $operator->setSite($this);
        }
    }

    public function removeUserRole(RelUserSite $operator): void
    {
        if ($this->userRoles->contains($operator)) {
            $this->userRoles->removeElement($operator);
        }
    }

    /**
     * @return Collection
     */
    public function getFactors(): Collection
    {
        return $this->factors;
    }

    /**
     * @param Collection $factors
     * @return Site
     */
    public function setFactors(Collection $factors): Site
    {
        $this->factors = $factors;
        return $this;
    }

    /**
     * @param Factor $factor
     * @return Site
     */
    public function addFactor($factor)
    {
        if (!$this->factors->contains($factor)) {
            $this->factors->add($factor);
            $factor->setSite($this);
        }
        return $this;
    }

    /**
     * @param Factor $factor
     * @return Site
     */
    public function removeFactor($factor)
    {
        if ($this->factors->contains($factor)) {
            $this->factors->removeElement($factor);
            $factor->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getProtocols(): Collection
    {
        return $this->protocols;
    }

    /**
     * @param Collection $protocols
     * @return Site
     */
    public function setProtocols(Collection $protocols): Site
    {
        $this->protocols = $protocols;
        return $this;
    }

    /**
     * @param Protocol $protocol
     * @return Site
     */
    public function addProtocol($protocol)
    {
        if (!$this->protocols->contains($protocol)) {
            $this->protocols->add($protocol);
            $protocol->setSite($this);
        }
        return $this;
    }

    /**
     * @param Protocol $protocol
     * @return Site
     */
    public function removeProtocol($protocol)
    {
        if ($this->protocols->contains($protocol)) {
            $this->protocols->removeElement($protocol);
            $protocol->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getUserGroups(): Collection
    {
        return $this->userGroups;
    }

    /**
     * @param Collection $userGroups
     * @return Site
     */
    public function setUserGroups(Collection $userGroups): Site
    {
        $this->userGroups = $userGroups;
        return $this;
    }

    /**
     * @param UserGroup $userGroup
     * @return Site
     */
    public function addUserGroup($userGroup)
    {
        if (!$this->userGroups->contains($userGroup)) {
            $this->userGroups->add($userGroup);
            $userGroup->setSite($this);
        }
        return $this;
    }

    /**
     * @param UserGroup $userGroup
     * @return Site
     */
    public function removeUserGroup($userGroup)
    {
        if ($this->userGroups->contains($userGroup)) {
            $this->userGroups->removeElement($userGroup);
            $userGroup->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getExperiments(): Collection
    {
        return $this->experiments;
    }

    /**
     * @param Collection $experiments
     * @return Site
     */
    public function setExperiments(Collection $experiments): Site
    {
        $this->experiments = $experiments;
        return $this;
    }

    /**
     * @param Experiment $experiment
     * @return Site
     */
    public function addExperiment($experiment)
    {
        if (!$this->experiments->contains($experiment)) {
            $this->experiments->add($experiment);
            $experiment->setSite($this);
        }
        return $this;
    }

    /**
     * @param Experiment $experiment
     * @return Site
     */
    public function removeExperiment($experiment)
    {
        if ($this->experiments->contains($experiment)) {
            $this->experiments->removeElement($experiment);
            $experiment->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getPlatforms(): Collection
    {
        return $this->platforms;
    }

    /**
     * @param Collection $platforms
     * @return Site
     */
    public function setPlatforms(Collection $platforms): Site
    {
        $this->platforms = $platforms;
        return $this;
    }

    /**
     * @param Platform $platform
     * @return Site
     */
    public function addPlatform($platform)
    {
        if (!$this->platforms->contains($platform)) {
            $this->platforms->add($platform);
            $platform->setSite($this);
        }
        return $this;
    }

    /**
     * @param Platform $platform
     * @return Site
     */
    public function removePlatform($platform)
    {
        if ($this->platforms->contains($platform)) {
            $this->platforms->removeElement($platform);
            $platform->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getSimpleVariables(): Collection
    {
        return $this->simpleVariables;
    }

    /**
     * @param Collection $simpleVariables
     * @return Site
     */
    public function setSimpleVariables(Collection $simpleVariables): Site
    {
        $this->simpleVariables = $simpleVariables;
        return $this;
    }

    /**
     * @param SimpleVariable $simpleVariable
     * @return Site
     */
    public function addSimpleVariable($simpleVariable)
    {
        if (!$this->simpleVariables->contains($simpleVariable)) {
            $this->simpleVariables->add($simpleVariable);
            $simpleVariable->setSite($this);
        }
        return $this;
    }

    /**
     * @param SimpleVariable $simpleVariable
     * @return Site
     */
    public function removeSimpleVariable($simpleVariable)
    {
        if ($this->simpleVariables->contains($simpleVariable)) {
            $this->simpleVariables->removeElement($simpleVariable);
            $simpleVariable->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getGeneratorVariables(): Collection
    {
        return $this->generatorVariables;
    }

    /**
     * @param Collection $generatorVariables
     * @return Site
     */
    public function setGeneratorVariables(Collection $generatorVariables): Site
    {
        $this->generatorVariables = $generatorVariables;
        return $this;
    }

    /**
     * @param GeneratorVariable $generatorVariable
     * @return Site
     */
    public function addGeneratorVariable($generatorVariable)
    {
        if (!$this->generatorVariables->contains($generatorVariable)) {
            $this->generatorVariables->add($generatorVariable);
            $generatorVariable->setSite($this);
        }
        return $this;
    }

    /**
     * @param GeneratorVariable $generatorVariable
     * @return Site
     */
    public function removeGeneratorVariable($generatorVariable)
    {
        if ($this->generatorVariables->contains($generatorVariable)) {
            $this->generatorVariables->removeElement($generatorVariable);
            $generatorVariable->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getValueLists(): Collection
    {
        return $this->valueLists;
    }

    /**
     * @param Collection $valueLists
     * @return Site
     */
    public function setValueLists(Collection $valueLists): Site
    {
        $this->valueLists = $valueLists;
        return $this;
    }

    /**
     * @param ValueList $valueList
     * @return Site
     */
    public function addValueList($valueList)
    {
        if (!$this->valueLists->contains($valueList)) {
            $this->valueLists->add($valueList);
            $valueList->setSite($this);
        }
        return $this;
    }

    /**
     * @param ValueList $valueList
     * @return Site
     */
    public function removeValueList($valueList)
    {
        if ($this->valueLists->contains($valueList)) {
            $this->valueLists->removeElement($valueList);
            $valueList->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getDevices(): Collection
    {
        return $this->devices;
    }

    /**
     * @param Collection $devices
     * @return Site
     */
    public function setDevices(Collection $devices): Site
    {
        $this->devices = $devices;
        return $this;
    }

    /**
     * @param Device $device
     * @return Site
     */
    public function addDevice($device)
    {
        if (!$this->devices->contains($device)) {
            $this->devices->add($device);
            $device->setSite($this);
        }
        return $this;
    }

    /**
     * @param Device $device
     * @return Site
     */
    public function removeDevice($device)
    {
        if ($this->devices->contains($device)) {
            $this->devices->removeElement($device);
            $device->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getStateCodes(): Collection
    {
        return $this->stateCodes;
    }

    /**
     * @param Collection $stateCodes
     * @return Site
     */
    public function setStateCodes(Collection $stateCodes): Site
    {
        $this->stateCodes = $stateCodes;
        return $this;
    }

    /**
     * @param StateCode $stateCode
     * @return Site
     */
    public function addStateCode($stateCode)
    {
        if (!$this->stateCodes->contains($stateCode)) {
            $this->stateCodes->add($stateCode);
            $stateCode->setSite($this);
        }
        return $this;
    }

    /**
     * @param StateCode $stateCode
     * @return Site
     */
    public function removeStateCode($stateCode)
    {
        if ($this->stateCodes->contains($stateCode)) {
            $this->stateCodes->removeElement($stateCode);
            $stateCode->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getOezNatures()
    {
        return $this->oezNatures;
    }

    /**
     * @param OezNature $oezNature
     * @return Site
     */
    public function addOezNature($oezNature)
    {
        if (!$this->oezNatures->contains($oezNature)) {
            $this->oezNatures->add($oezNature);
            $oezNature->setSite($this);
        }
        return $this;
    }

    /**
     * @param OezNature $oezNature
     * @return Site
     */
    public function removeOezNature($oezNature)
    {
        if ($this->oezNatures->contains($oezNature)) {
            $this->oezNatures->removeElement($oezNature);
            $oezNature->setSite(null);
        }
        return $this;
    }

    /**
     * @return Collection
     */
    public function getParsingJobs(): Collection
    {
        return $this->parsingJobs;
    }

    /**
     * @param Collection $parsingJobs
     * @return Site
     */
    public function setParsingJobs(Collection $parsingJobs): Site
    {
        $this->parsingJobs = $parsingJobs;
        return $this;
    }

    /**
     * @return GraphicalConfiguration|null
     */
    public function getGraphicalConfiguration(): ?GraphicalConfiguration
    {
        return $this->graphicalConfiguration;
    }

    /**
     * @param GraphicalConfiguration|null $graphicalConfiguration
     * @return Site
     */
    public function setGraphicalConfiguration(?GraphicalConfiguration $graphicalConfiguration): Site
    {
        $this->graphicalConfiguration = $graphicalConfiguration;
        return $this;
    }

    /**
     * @return ArrayCollection|Collection
     */
    public function getOpenSilexInstances()
    {
        return $this->openSilexInstances;
    }

    /**
     * @param OpenSilexInstance $openSilexInstance
     * @return Site
     */
    public function addOpenSilexInstance($openSilexInstance)
    {
        if (!$this->openSilexInstances->contains($openSilexInstance)) {
            $this->openSilexInstances->add($openSilexInstance);
            $openSilexInstance->setSite($this);
        }
        return $this;
    }

    /**
     * @param OpenSilexInstance $openSilexInstance
     * @return Site
     */
    public function removeOpenSilexInstance($openSilexInstance)
    {
        if ($this->openSilexInstances->contains($openSilexInstance)) {
            $this->openSilexInstances->removeElement($openSilexInstance);
        }
        return $this;
    }


}
