<?php
declare(strict_types=1);
namespace App\Entity;
use App\Contracts\Video\VideoAvailability;
use App\Repository\VideoRepository;
use DateTime;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\ManyToOne;
use Doctrine\ORM\Mapping\OneToMany;
use Doctrine\ORM\Mapping\PrePersist;
use Doctrine\ORM\Mapping\PreUpdate;
use Doctrine\ORM\Mapping\UniqueConstraint;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[Entity(VideoRepository::class)]
#[UniqueEntity('externalId', 'Video is already used')]
#[UniqueConstraint('unique_external_id', ['external_id'])]
#[HasLifecycleCallbacks]
class Video
{
#[Id]
#[GeneratedValue]
#[Column('id', 'bigint', options: ['unsigned' => true])]
private ?int $id = null;
#[ManyToOne(targetEntity: Creator::class, inversedBy: 'videoCollection')]
private Creator $creator;
#[Column(type: 'text')]
private string $url;
#[Column(type: 'string')]
private string $externalId;
#[Column(type: 'string')]
private string $title;
#[Column(type: 'text')]
private string $description;
#[Column(name: 'boost_code', type: 'string', nullable: true, options: [
'comment' => 'Boost code for boosting the video',
])]
private ?string $boostCode;
#[Column(type: 'integer')]
private int $duration;
#[Column(type: 'bigint', options: ['unsigned' => true])]
private int $views;
#[Column(type: 'bigint', options: ['unsigned' => true])]
private int $likes;
#[Column(type: 'bigint', options: ['unsigned' => true])]
private int $comments;
#[Column(type: 'bigint', options: ['unsigned' => true])]
private int $shares;
#[Column(type: 'bigint', options: ['unsigned' => true, 'default' => 0])]
private int $saves = 0;
#[Column(type: 'string', length: 20, enumType: VideoAvailability::class, options: ['default' => VideoAvailability::AVAILABLE->value])]
private VideoAvailability $availability = VideoAvailability::AVAILABLE;
#[Column(name: 'unavailable_since', type: 'datetime_immutable', nullable: true)]
private ?DateTimeImmutable $unavailableSince = null;
#[Column(name: 'unavailable_reason', type: 'string', length: 64, nullable: true)]
private ?string $unavailableReason = null;
#[OneToMany(mappedBy: 'video', targetEntity: VideoStatisticsHistory::class)]
private Collection $videoStatisticsHistory;
#[Column(type: 'datetime')]
private DateTime $createdAt;
#[Column(type: 'datetime')]
private DateTime $updatedAt;
#[Column(type: 'datetime_immutable')]
private ?DateTimeImmutable $platformCreatedAt = null;
public function __construct()
{
$this->videoStatisticsHistory = new ArrayCollection();
}
#[PrePersist]
public function prePersist(): void
{
$this->createdAt = new DateTime();
$this->updatedAt = new DateTime();
}
#[PreUpdate]
public function preUpdate(): void
{
$this->updatedAt = new DateTime();
}
public function getId(): ?int
{
return $this->id;
}
public function getCreator(): Creator
{
return $this->creator;
}
public function setCreator(Creator $creator): static
{
$this->creator = $creator;
return $this;
}
public function getBoostCode(): ?string
{
return $this->boostCode;
}
public function setBoostCode(?string $boostCode): static
{
$this->boostCode = $boostCode;
return $this;
}
public function getExternalId(): string
{
return $this->externalId;
}
public function setExternalId(string $id): static
{
$this->externalId = $id;
return $this;
}
public function setUrl(string $url): self
{
$this->url = $url;
return $this;
}
public function getVideoStatisticsHistory(): Collection
{
return $this->videoStatisticsHistory;
}
public function getUrl(): string
{
return $this->url;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getDescription(): string
{
return $this->description;
}
public function setDescription(string $description): static
{
$this->description = $description;
return $this;
}
public function getDuration(): int
{
return $this->duration;
}
public function setDuration(int $duration): static
{
$this->duration = $duration;
return $this;
}
public function getViews(): int
{
return $this->views;
}
public function setViews(int $views): static
{
$this->views = $views;
return $this;
}
public function getLikes(): int
{
return $this->likes;
}
public function setLikes(int $likes): static
{
$this->likes = $likes;
return $this;
}
public function getComments(): int
{
return $this->comments;
}
public function setComments(int $comments): static
{
$this->comments = $comments;
return $this;
}
public function getShares(): int
{
return $this->shares;
}
public function setShares(int $shares): static
{
$this->shares = $shares;
return $this;
}
public function getSaves(): int
{
return $this->saves;
}
public function setSaves(int $saves): static
{
$this->saves = $saves;
return $this;
}
public function getAvailability(): VideoAvailability
{
return $this->availability;
}
public function isUnavailable(): bool
{
return $this->availability === VideoAvailability::UNAVAILABLE;
}
public function getUnavailableSince(): ?DateTimeImmutable
{
return $this->unavailableSince;
}
public function getUnavailableReason(): ?string
{
return $this->unavailableReason;
}
/** Mark the post as confirmed-gone. Stamps unavailable_since once, never overwrites it. */
public function markUnavailable(string $reason): static
{
$this->availability = VideoAvailability::UNAVAILABLE;
$this->unavailableReason = $reason;
$this->unavailableSince ??= new DateTimeImmutable();
return $this;
}
/** Clear the flag — e.g. a creator un-privated the post and it is fetchable again. */
public function markAvailable(): static
{
$this->availability = VideoAvailability::AVAILABLE;
$this->unavailableSince = null;
$this->unavailableReason = null;
return $this;
}
public function setCreatedAt(DateTime $createdAt): static
{
$this->createdAt = $createdAt;
return $this;
}
public function getCreatedAt(): DateTime
{
return $this->createdAt;
}
public function setUpdatedAt(DateTime $updatedAt): static
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getUpdatedAt(): DateTime
{
return $this->updatedAt;
}
public function getPlatformCreatedAt(): ?DateTimeImmutable
{
return $this->platformCreatedAt;
}
public function setPlatformCreatedAt(?DateTimeImmutable $platformCreatedAt): static
{
$this->platformCreatedAt = $platformCreatedAt;
return $this;
}
}