<?php

declare(strict_types=1);

namespace App\Entity;

use App\Enum\Orientation;
use App\Repository\ImageRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: ImageRepository::class)]
class Image
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(inversedBy: 'images')]
    #[ORM\JoinColumn(nullable: false)]
    private ?User $user = null;

    #[ORM\Column(length: 255)]
    private string $originalFilename = '';

    /** Relative path from project root to the original file. */
    #[ORM\Column(length: 500)]
    private string $storagePath = '';

    /** JSON-encoded crop parameters from the client editor, or null if not cropped. */
    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $cropParams = null;

    /** JSON-encoded sticker state from the client editor, or null if no stickers. */
    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $stickerState = null;

    /**
     * Orientation the user picked in the crop editor. Drives the warning
     * indicator on the library and the crop page when it doesn't match an
     * approved device's current orientation. Null on legacy uploads predating
     * the toggle.
     */
    #[ORM\Column(nullable: true, enumType: Orientation::class)]
    private ?Orientation $cropOrientation = null;

    #[ORM\Column]
    private \DateTimeImmutable $uploadedAt;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $deletedAt = null;

    /** @var Collection<int, Device> */
    #[ORM\ManyToMany(targetEntity: Device::class)]
    #[ORM\JoinTable(name: 'image_device_approval')]
    private Collection $approvedDevices;

    /** @var Collection<int, RenderedAsset> */
    #[ORM\OneToMany(targetEntity: RenderedAsset::class, mappedBy: 'image', orphanRemoval: true)]
    private Collection $renderedAssets;

    public function __construct()
    {
        $this->uploadedAt     = new \DateTimeImmutable();
        $this->approvedDevices = new ArrayCollection();
        $this->renderedAssets  = new ArrayCollection();
    }

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

    public function getUser(): ?User { return $this->user; }
    public function setUser(?User $user): static { $this->user = $user; return $this; }

    public function getOriginalFilename(): string { return $this->originalFilename; }
    public function setOriginalFilename(string $f): static { $this->originalFilename = $f; return $this; }

    public function getStoragePath(): string { return $this->storagePath; }
    public function setStoragePath(string $p): static { $this->storagePath = $p; return $this; }

    public function getUploadedAt(): \DateTimeImmutable { return $this->uploadedAt; }

    public function getDeletedAt(): ?\DateTimeImmutable { return $this->deletedAt; }
    public function setDeletedAt(?\DateTimeImmutable $dt): static { $this->deletedAt = $dt; return $this; }

    public function isDeleted(): bool { return $this->deletedAt !== null; }

    public function getCropParams(): ?string { return $this->cropParams; }
    public function setCropParams(?string $p): static { $this->cropParams = $p; return $this; }

    public function getStickerState(): ?string { return $this->stickerState; }
    public function setStickerState(?string $s): static { $this->stickerState = $s; return $this; }

    public function getCropOrientation(): ?Orientation { return $this->cropOrientation; }
    public function setCropOrientation(?Orientation $o): static { $this->cropOrientation = $o; return $this; }

    /** @return Collection<int, Device> */
    public function getApprovedDevices(): Collection { return $this->approvedDevices; }

    public function approveForDevice(Device $device): void
    {
        if (!$this->approvedDevices->contains($device)) {
            $this->approvedDevices->add($device);
        }
    }

    public function revokeForDevice(Device $device): void
    {
        $this->approvedDevices->removeElement($device);
    }

    public function isApprovedForDevice(Device $device): bool
    {
        return $this->approvedDevices->contains($device);
    }

    /** @return Collection<int, RenderedAsset> */
    public function getRenderedAssets(): Collection { return $this->renderedAssets; }
}
