<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\PageBuilder\Model;

use CpCreation\VitiCore\Behavior\HasDisable;
use CpCreation\VitiCore\Behavior\HasImage;
use CpCreation\VitiCore\Behavior\HasSortable;
use CpCreation\VitiCore\Behavior\HasTimestamp;
use CpCreation\VitiCore\Behavior\HasTranslatable;
use CpCreation\VitiCore\Behavior\Impl\Disable;
use CpCreation\VitiCore\Behavior\Impl\Image;
use CpCreation\VitiCore\Behavior\Impl\Sortable;
use CpCreation\VitiCore\Behavior\Impl\Timestamp;
use CpCreation\VitiCore\Behavior\Impl\Translatable;
use CpCreation\VitiCore\PageBuilder\Repository\PageSectionRepository;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\Validator\Constraints as Assert;

#[ORM\Entity(repositoryClass: PageSectionRepository::class)]
#[ORM\Table(name: 'page_builder_page_section')]
#[ORM\HasLifecycleCallbacks]
class PageSection implements HasDisable, HasImage, HasSortable, HasTimestamp, HasTranslatable
{
    use Disable;
    use Image;
    use Sortable;
    use Timestamp;
    use Translatable;

    #[ORM\Id]
    #[ORM\Column(type: 'uuid')]
    #[ORM\GeneratedValue(strategy: 'NONE')]
    private UuidInterface $id;

    #[ORM\ManyToOne(targetEntity: Page::class, inversedBy: 'sections')]
    #[ORM\JoinColumn(name: 'page_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
    private ?Page $page = null;

    #[ORM\Column(type: 'string', length: 64)]
    #[Assert\NotBlank]
    private string $type;

    #[ORM\Column(type: 'string', length: 255, nullable: true)]
    private ?string $adminLabel = null;

    #[ORM\Column(type: 'json', nullable: true, options: ['default' => '[]'])]
    private array $settings = [];

    #[ORM\Column(type: 'datetime', nullable: true)]
    private ?\DateTime $publishedAt = null;

    #[ORM\Column(type: 'datetime', nullable: true)]
    private ?\DateTime $unPublishedAt = null;

    public function __construct(string $type)
    {
        $this->id = Uuid::uuid4();
        $this->type = trim($type);
        $this->disabled = false;
        $this->position = 0;
    }

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

    public function getPage(): ?Page
    {
        return $this->page;
    }

    public function setPage(Page $page): void
    {
        $this->page = $page;
    }

    public function clearPage(): void
    {
        $this->page = null;
    }

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

    public function setType(string $type): void
    {
        $this->type = trim($type);
    }

    public function getAdminLabel(): ?string
    {
        return $this->adminLabel;
    }

    public function setAdminLabel(?string $adminLabel): void
    {
        $this->adminLabel = null !== $adminLabel ? trim($adminLabel) : null;
    }

    /**
     * @return array<string, mixed>
     */
    public function getSettings(): array
    {
        return $this->settings;
    }

    /**
     * @param array<string, mixed>|null $settings
     */
    public function setSettings(?array $settings): void
    {
        $this->settings = array_filter($settings ?? [], static fn (mixed $value): bool => null !== $value);
    }

    public function getSetting(string $key, mixed $default = null): mixed
    {
        return $this->settings[$key] ?? $default;
    }

    public function setSetting(string $key, mixed $value): void
    {
        if (null === $value) {
            unset($this->settings[$key]);

            return;
        }

        $this->settings[$key] = $value;
    }

    public function getPublishedAt(): ?\DateTime
    {
        return $this->publishedAt;
    }

    public function setPublishedAt(?\DateTime $publishedAt): void
    {
        $this->publishedAt = $publishedAt;
    }

    public function getUnPublishedAt(): ?\DateTime
    {
        return $this->unPublishedAt;
    }

    public function setUnPublishedAt(?\DateTime $unPublishedAt): void
    {
        $this->unPublishedAt = $unPublishedAt;
    }

    public function isCurrentlyPublished(?\DateTimeInterface $referenceDate = null): bool
    {
        if ($this->isDisabled()) {
            return false;
        }

        $referenceDate ??= new \DateTimeImmutable();

        if ($this->publishedAt instanceof \DateTimeInterface && $this->publishedAt > $referenceDate) {
            return false;
        }

        if ($this->unPublishedAt instanceof \DateTimeInterface && $this->unPublishedAt < $referenceDate) {
            return false;
        }

        return true;
    }
}
