<?php
declare (strict_types=1);

namespace App\Entity\Core;

use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\ApiResource;
use App\Entity\AccessWish\DocumentWish;
use App\Entity\Booking\Event;
use App\Entity\Booking\EventReport;
use App\Entity\Booking\Work;
use App\Entity\Message\TemplateSystem;
use App\Entity\Organization\Activity;
use App\Entity\Organization\OnlineRegistrationSettings;
use App\Entity\Organization\Organization;
use App\Entity\Person\Person;
use App\Enum\Core\FileHostEnum;
use App\Repository\Core\FileRepository;
use App\Entity\Organization\Parameters;
use DateTime;
//use DH\Auditor\Provider\Doctrine\Auditing\Annotation\Auditable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use JetBrains\PhpStorm\Pure;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use App\Enum\Core\FileStatusEnum;

#[ApiResource(
    operations: [
        new Get(),
        new Put()
    ]
)]
//#[Auditable]
#[ORM\Entity(repositoryClass: FileRepository::class)]
class File
{
    #[ORM\Id]
    #[ORM\Column]
    #[ORM\GeneratedValue]
    private ?int $id = null;

    /**
     * Propriétaire du fichier
     *
     * @var Person|null
     */
    #[ORM\ManyToOne(inversedBy: 'files')]
    #[ORM\JoinColumn(name: 'person_id', referencedColumnName: 'id')]
    private ?Person $person;

    /**
     * Organisation propriétaire du fichier
     * @var Organization|null
     */
    #[ORM\ManyToOne(inversedBy: 'files')]
    #[ORM\JoinColumn(name: 'organization_id', referencedColumnName: 'id')]
    private ?Organization $organization;

    /**
     * Slug du fichier (i.e. le chemin d'accès relatif)
     * @var string|null
     */
    #[ORM\Column(length: 255)]
    private ?string $slug = null;

    /**
     * Chemin d'accès du fichier
     * @var string|null
     */
    #[ORM\Column(length: 255)]
    private ?string $path = null;

    /**
     * Nom du fichier
     * @var string
     */
    #[ORM\Column(length: 255)]
    private string $name;

    /**
     * Mimetype du fichier
     * @var string|null
     */
    #[ORM\Column(length: 255, nullable: true)]
    private ?string $mimeType = null;

    /**
     * Visibilité du fichier (tout le monde, personne, l'organisation seulement...)
     * @var string
     */
    #[ORM\Column(length: 24, options: ['default' => 'NOBODY'])]
    private string $visibility = 'NOBODY';

    /**
     * Configuration particulière associée au fichier (exemple: image recadrée)
     * @var string|null
     */
    #[ORM\Column(type: 'text', length: 255, nullable: true)]
    private ?string $config;

    /**
     * Type de document (uploaded, mail, bill...etc)
     * @var string
     */
    #[ORM\Column(length: 50, options: ['default' => 'NONE'])]
    private string $type = "NONE";

    /**
     * Taille du document en octets
     * @var int|null
     */
    #[ORM\Column]
    private ?int $size;

    /**
     * Un fichier est temporaire par exemple s'il a été généré et est stocké pour être téléchargé dans la foulée
     * Les fichiers temporaires peuvent être supprimés sans risque, à l'inverse des fichiers uploadés par les
     * utilisateurs par exemple.
     *
     * @var boolean
     */
    #[ORM\Column(options: ['default' => false])]
    private bool $isTemporaryFile = false;

    /**
     * Date de création du fichier
     * @var DateTime
     */
    #[ORM\Column]
    private DateTime $createDate;

    /**
     * Id de l'access ayant créé ce fichier
     * @var int|null
     */
    #[ORM\Column]
    private ?int $createdBy;

    /**
     * Date de dernière mise à jour du fichier
     * @var DateTime
     */
    #[ORM\Column]
    private DateTime $updateDate;

    /**
     * Id de l'access ayant mis à jour ce fichier le dernier
     * @var int|null
     */
    #[ORM\Column]
    private ?int $updatedBy;

    /**
     * Statut du fichier (en cours de génération, prêt, supprimé, etc.)
     * @var string | null
     */
    #[ORM\Column(length: 50)]
    #[Assert\Choice(callback: [FileStatusEnum::class, 'toArray'])]
    private ?string $status = null;

    /**
     * Serveur sur lequel le fichier est physiquement stocké
     * @var string | null
     */
    #[ORM\Column(length: 5)]
    #[Assert\Choice(callback: [FileHostEnum::class, 'toArray'])]
    private ?string $host = 'ap2i';

    //    #[ORM\Column]
    //    private ?int $eventReport_id;
    //
    //    #[ORM\Column]
    //    private ?\DateTime $availabilityDate;
    //
    //    #[ORM\Column]
    //    private ?int $documentWish_id;
    //
    //    #[ORM\Column]
    //    private ?int $onlineRegistrationSetting_id;
    //
    //    #[ORM\Column]
    //    private ?int $templateSystem_id;
    //
    //    #[ORM\Column]
    //    private ?int $work_id;
    #[ORM\ManyToMany(targetEntity: Person::class, inversedBy: 'personFiles')]
    #[Groups(['file_person'])]
    private Collection $accessPersons;

    #[ORM\OneToMany(mappedBy: 'image', targetEntity: Person::class, orphanRemoval: true)]
    private Collection $personImages;

    #[ORM\OneToMany(mappedBy: 'logo', targetEntity: Organization::class, orphanRemoval: true)]
    private Collection $organizationLogos;

    #[ORM\OneToMany(mappedBy: 'image', targetEntity: Organization::class, orphanRemoval: true)]
    private Collection $organizationImages;

    #[ORM\OneToOne(mappedBy: "qrCode", targetEntity: Parameters::class, fetch: 'EAGER')]
    private Parameters $qrCode;

    #[ORM\OneToMany(mappedBy: 'image', targetEntity: Event::class)]
    private Collection $events;

    #[ORM\OneToMany(mappedBy: 'logo', targetEntity: Activity::class)]
    private Collection $activityLogos;

    #[ORM\OneToMany(mappedBy: 'imageActivity', targetEntity: Activity::class)]
    private Collection $activityImages;

    #[ORM\ManyToOne(inversedBy: 'files')]
    #[ORM\JoinColumn(onDelete: 'CASCADE')]
    private EventReport $eventReport;

    #[ORM\ManyToOne(cascade: ['persist'], inversedBy: 'files')]
    #[ORM\JoinColumn(onDelete: 'CASCADE')]
    private DocumentWish $documentWish;

    #[ORM\ManyToOne(cascade: ['persist'], inversedBy: 'introductionFiles')]
    #[ORM\JoinColumn(onDelete: 'CASCADE')]
    private OnlineRegistrationSettings $onlineRegistrationSetting;

    #[ORM\ManyToOne(cascade: ['persist'], inversedBy: 'introductionFilesNewEnrolments')]
    #[ORM\JoinColumn(onDelete: 'CASCADE')]
    private OnlineRegistrationSettings $onlineRegistrationSettingNewEnrolments;

    #[ORM\ManyToOne(cascade: ['persist'], inversedBy: 'files')]
    #[ORM\JoinColumn(onDelete: 'CASCADE')]
    private Work $work;

    #[ORM\ManyToOne(cascade: ['persist'], inversedBy: 'files')]
    #[ORM\JoinColumn(onDelete: 'CASCADE')]
    private TemplateSystem $templateSystem;

    #[Pure]
    public function __construct()
    {
        $this->personImages = new ArrayCollection();
        $this->organizationLogos = new ArrayCollection();
        $this->organizationImages = new ArrayCollection();
        $this->accessPersons = new ArrayCollection();
        $this->events = new ArrayCollection();
        $this->activityLogos = new ArrayCollection();
        $this->activityImages = new ArrayCollection();
    }

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

    /**
     * @return Person|null
     */
    public function getPerson(): ?Person
    {
        return $this->person;
    }

    /**
     * @param Person|null $person
     * @return File
     */
    public function setPerson(?Person $person): File
    {
        $this->person = $person;
        return $this;
    }

    /**
     * @return Organization|null
     */
    public function getOrganization(): ?Organization
    {
        return $this->organization;
    }

    /**
     * @param Organization|null $organization
     * @return File
     */
    public function setOrganization(?Organization $organization): File
    {
        $this->organization = $organization;
        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(?string $slug): self
    {
        $this->slug = $slug;
        return $this;
    }

    public function getPath(): ?string
    {
        return $this->path;
    }

    public function setPath(?string $path): self
    {
        $this->path = $path;
        return $this;
    }

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

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

    public function getMimeType(): ?string
    {
        return $this->mimeType;
    }

    public function setMimeType(?string $mimeType): self
    {
        $this->mimeType = $mimeType;
        return $this;
    }

    public function getConfig(): string
    {
        return $this->config;
    }

    public function setConfig(string $config): self
    {
        $this->config = $config;
        return $this;
    }

    public function getPersonImages(): Collection
    {
        return $this->personImages;
    }

    public function addPersonImage(Person $person): self
    {
        if (!$this->personImages->contains($person)) {
            $this->personImages[] = $person;
            $person->setImage($this);
        }
        return $this;
    }

    public function removePersonImage(Person $person): self
    {
        // set the owning side to null (unless already changed)
        if ($this->personImages->removeElement($person) && $person->getImage() === $this) {
            $person->setImage(null);
        }
        return $this;
    }

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

    /**
     * @param string $visibility
     * @return File
     */
    public function setVisibility(string $visibility): File
    {
        $this->visibility = $visibility;
        return $this;
    }

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

    /**
     * @param string $type
     * @return File
     */
    public function setType(string $type): File
    {
        $this->type = $type;
        return $this;
    }

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

    /**
     * @param int|null $size
     * @return File
     */
    public function setSize(?int $size): File
    {
        $this->size = $size;
        return $this;
    }

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

    /**
     * @param bool $isTemporaryFile
     * @return File
     */
    public function setIsTemporaryFile(bool $isTemporaryFile): File
    {
        $this->isTemporaryFile = $isTemporaryFile;
        return $this;
    }

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

    /**
     * @param DateTime $createDate
     * @return File
     */
    public function setCreateDate(DateTime $createDate): File
    {
        $this->createDate = $createDate;
        return $this;
    }

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

    /**
     * @param int|null $createdBy
     * @return File
     */
    public function setCreatedBy(?int $createdBy): File
    {
        $this->createdBy = $createdBy;
        return $this;
    }

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

    /**
     * @param DateTime $updateDate
     * @return File
     */
    public function setUpdateDate(DateTime $updateDate): File
    {
        $this->updateDate = $updateDate;
        return $this;
    }

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

    /**
     * @param int|null $updatedBy
     * @return File
     */
    public function setUpdatedBy(?int $updatedBy): File
    {
        $this->updatedBy = $updatedBy;
        return $this;
    }

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

    /**
     * @param string|null $status
     * @return File
     */
    public function setStatus(?string $status): File
    {
        $this->status = $status;
        return $this;
    }

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

    /**
     * @param string|null $host
     */
    public function setHost(?string $host): self
    {
        $this->host = $host;

        return $this;
    }

    public function getOrganizationLogos(): Collection
    {
        return $this->organizationLogos;
    }

    public function addOrganizationLogo(Organization $organization): self
    {
        if (!$this->organizationLogos->contains($organization)) {
            $this->organizationLogos[] = $organization;
            $organization->setLogo($this);
        }
        return $this;
    }

    public function removeOrganizationLogo(Organization $organization): self
    {
        // set the owning side to null (unless already changed)
        if ($this->organizationLogos->removeElement($organization) && $organization->getLogo() === $this) {
            $organization->setLogo(null);
        }
        return $this;
    }

    public function getOrganizationImages(): Collection
    {
        return $this->organizationImages;
    }

    public function addOrganizationImage(Organization $organization): self
    {
        if (!$this->organizationImages->contains($organization)) {
            $this->organizationImages[] = $organization;
            $organization->setImage($this);
        }
        return $this;
    }

    public function removeOrganizationImage(Organization $organization): self
    {
        // set the owning side to null (unless already changed)
        if ($this->organizationImages->removeElement($organization) && $organization->getImage() === $this) {
            $organization->setImage(null);
        }
        return $this;
    }

    public function getQrCode(): Parameters
    {
        return $this->qrCode;
    }

    public function setQrCode(Parameters $qrCode): self
    {
        $this->qrCode = $qrCode;
        return $this;
    }

    /**
     * @return Collection<int, Person>
     */
    public function getAccessPersons(): Collection
    {
        return $this->accessPersons;
    }

    public function addAccessPerson(Person $accessPerson): self
    {
        if (!$this->accessPersons->contains($accessPerson)) {
            $this->accessPersons[] = $accessPerson;
        }
        return $this;
    }

    public function removeAccessPerson(Person $accessPerson): self
    {
        $this->accessPersons->removeElement($accessPerson);
        return $this;
    }

    /**
     * @return Collection<int, Event>
     */
    public function getEvents(): Collection
    {
        return $this->events;
    }

    public function addEvent(Event $event): self
    {
        if (!$this->events->contains($event)) {
            $this->events[] = $event;
            $event->setImage($this);
        }
        return $this;
    }

    public function removeEvent(Event $event): self
    {
        // set the owning side to null (unless already changed)
        if ($this->events->removeElement($event) && $event->getImage() === $this) {
            $event->setImage(null);
        }
        return $this;
    }

    /**
     * @return Collection<int, Activity>
     */
    public function getActivityLogos(): Collection
    {
        return $this->activityLogos;
    }

    public function addActivityLogo(Activity $activityLogo): self
    {
        if (!$this->activityLogos->contains($activityLogo)) {
            $this->activityLogos[] = $activityLogo;
            $activityLogo->setLogo($this);
        }
        return $this;
    }

    public function removeActivityLogo(Activity $activityLogo): self
    {
        // set the owning side to null (unless already changed)
        if ($this->activityLogos->removeElement($activityLogo) && $activityLogo->getLogo() === $this) {
            $activityLogo->setLogo(null);
        }
        return $this;
    }

    /**
     * @return Collection<int, Activity>
     */
    public function getActivityImages(): Collection
    {
        return $this->activityImages;
    }

    public function addActivityImage(Activity $activityImage): self
    {
        if (!$this->activityImages->contains($activityImage)) {
            $this->activityImages[] = $activityImage;
            $activityImage->setImageActivity($this);
        }
        return $this;
    }

    public function removeActivityImage(Activity $activityImage): self
    {
        // set the owning side to null (unless already changed)
        if ($this->activityImages->removeElement($activityImage) && $activityImage->getImageActivity() === $this) {
            $activityImage->setImageActivity(null);
        }
        return $this;
    }

    public function getEventReport(): ?EventReport
    {
        return $this->eventReport;
    }

    public function setEventReport(?EventReport $eventReport): self
    {
        $this->eventReport = $eventReport;
        return $this;
    }

    public function getDocumentWish(): ?DocumentWish
    {
        return $this->documentWish;
    }

    public function setDocumentWish(?DocumentWish $documentWish): self
    {
        $this->documentWish = $documentWish;
        return $this;
    }

    public function getOnlineRegistrationSetting(): ?OnlineRegistrationSettings
    {
        return $this->onlineRegistrationSetting;
    }

    public function setOnlineRegistrationSetting(?OnlineRegistrationSettings $onlineRegistrationSetting): self
    {
        $this->onlineRegistrationSetting = $onlineRegistrationSetting;
        return $this;
    }

    public function getOnlineRegistrationSettingNewEnrolments(): ?OnlineRegistrationSettings
    {
        return $this->onlineRegistrationSettingNewEnrolments;
    }

    public function setOnlineRegistrationSettingNewEnrolments(?OnlineRegistrationSettings $onlineRegistrationSettingNewEnrolments): self
    {
        $this->onlineRegistrationSettingNewEnrolments = $onlineRegistrationSettingNewEnrolments;
        return $this;
    }

    public function getWork(): ?Work
    {
        return $this->work;
    }

    public function setWork(?Work $work): self
    {
        $this->work = $work;
        return $this;
    }

    public function getTemplateSystem(): ?TemplateSystem
    {
        return $this->templateSystem;
    }

    public function setTemplateSystem(?TemplateSystem $templateSystem): self
    {
        $this->templateSystem = $templateSystem;
        return $this;
    }
}
