<?php

declare(strict_types=1);

namespace App\Entity;

use App\Tag\TagTypes;
use Doctrine\ORM\Mapping as ORM;
use InvalidArgumentException;
use Symfony\Component\Uid\Uuid;

#[ORM\Entity]
#[ORM\Table(name: 'knowledge_tag')]
#[ORM\Index(name: 'idx_knowledge_tag_slug', columns: ['slug'])]
#[ORM\Index(name: 'idx_knowledge_tag_label', columns: ['label'])]
class Tag
{
    #[ORM\Id]
    #[ORM\Column(type: 'uuid', unique: true)]
    private Uuid $id;

    #[ORM\Column(length: 120, unique: true)]
    private string $slug;

    #[ORM\Column(length: 180)]
    private string $label;

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

    #[ORM\Column(length: 50)]
    private string $type = TagTypes::GENERIC;

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

    public function __construct(
        string $slug,
        string $label,
        ?string $description = null,
        string $type = TagTypes::GENERIC,
    ) {
        $this->id = Uuid::v4();
        $this->createdAt = new \DateTimeImmutable();

        $this->setSlug($slug);
        $this->setLabel($label);
        $this->setDescription($description);
        $this->setType($type);
    }

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

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

    public function setSlug(string $slug): static
    {
        $slug = $this->normalizeSlug($slug);

        if ($slug === '') {
            throw new InvalidArgumentException('Tag slug must not be empty.');
        }

        $this->slug = $slug;

        return $this;
    }

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

    public function setLabel(string $label): static
    {
        $label = trim($label);

        if ($label === '') {
            throw new InvalidArgumentException('Tag label must not be empty.');
        }

        $this->label = $label;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(?string $description): static
    {
        $description = trim((string) $description);
        $this->description = $description !== '' ? $description : null;

        return $this;
    }

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

    public function setType(string $type): static
    {
        $normalizedType = TagTypes::normalize($type);

        if (!TagTypes::isValid($normalizedType)) {
            throw new InvalidArgumentException(sprintf('Unsupported tag type "%s".', $type));
        }

        $this->type = $normalizedType;

        return $this;
    }

    public function isGeneric(): bool
    {
        return $this->type === TagTypes::GENERIC;
    }

    public function isCatalogEntity(): bool
    {
        return $this->type === TagTypes::CATALOG_ENTITY;
    }

    public function isSalesSignal(): bool
    {
        return $this->type === TagTypes::SALES_SIGNAL;
    }

    public function getCreatedAt(): \DateTimeImmutable
    {
        return $this->createdAt;
    }

    private function normalizeSlug(string $slug): string
    {
        $slug = mb_strtolower(trim($slug));
        $slug = preg_replace('/\s+/u', '-', $slug) ?? $slug;
        $slug = preg_replace('/-+/u', '-', $slug) ?? $slug;

        return trim($slug, '-');
    }
}