<?php
declare(strict_types=1);

namespace ROITheme\Admin\CustomCSSManager\Domain\ValueObjects;

use ROITheme\Shared\Domain\Exceptions\ValidationException;

/**
 * Value Object para ID único de snippet CSS
 *
 * Soporta tres formatos:
 * 1. Generado: css_[timestamp]_[random] (ej: "css_1701432000_a1b2c3")
 * 2. Legacy con prefijo: css_[descriptive]_[number] (ej: "css_tablas_apu_1764624826")
 * 3. Legacy kebab-case: (ej: "cls-tables-apu", "generic-tables")
 *
 * Esto permite migrar snippets existentes sin romper IDs.
 */
final class SnippetId
{
    private const PREFIX = 'css_';
    private const PATTERN_GENERATED = '/^css_[0-9]+_[a-z0-9]{6}$/';
    private const PATTERN_LEGACY_PREFIX = '/^css_[a-z0-9_]+$/';
    private const PATTERN_LEGACY = '/^[a-z0-9]+(-[a-z0-9]+)*$/';

    private function __construct(
        private readonly string $value
    ) {}

    /**
     * Crea SnippetId desde string existente (desde BD)
     *
     * Acepta tanto IDs generados (css_*) como IDs legacy (kebab-case).
     *
     * @param string $id ID existente
     * @return self
     * @throws ValidationException Si el formato es inválido
     */
    public static function fromString(string $id): self
    {
        $id = trim($id);

        if (empty($id)) {
            throw new ValidationException('El ID del snippet no puede estar vacío');
        }

        if (strlen($id) > 50) {
            throw new ValidationException('El ID del snippet no puede exceder 50 caracteres');
        }

        // Validar formato generado (css_*)
        if (str_starts_with($id, self::PREFIX)) {
            // Acepta formato nuevo (css_timestamp_random) o legacy (css_descriptivo_numero)
            if (!preg_match(self::PATTERN_GENERATED, $id) && !preg_match(self::PATTERN_LEGACY_PREFIX, $id)) {
                throw new ValidationException(
                    sprintf('Formato de ID generado inválido: %s. Esperado: css_[timestamp]_[random]', $id)
                );
            }
            return new self($id);
        }

        // Validar formato legacy (kebab-case)
        if (!preg_match(self::PATTERN_LEGACY, $id)) {
            throw new ValidationException(
                sprintf('Formato de ID inválido: %s. Use kebab-case (ej: cls-tables-apu)', $id)
            );
        }

        return new self($id);
    }

    /**
     * Genera un nuevo SnippetId único
     *
     * @return self
     */
    public static function generate(): self
    {
        $timestamp = time();
        $random = bin2hex(random_bytes(3));

        return new self(self::PREFIX . $timestamp . '_' . $random);
    }

    /**
     * Verifica si es un ID generado (vs legacy)
     *
     * @return bool
     */
    public function isGenerated(): bool
    {
        return str_starts_with($this->value, self::PREFIX);
    }

    /**
     * Obtiene el valor del ID
     *
     * @return string
     */
    public function value(): string
    {
        return $this->value;
    }

    /**
     * Compara igualdad con otro SnippetId
     *
     * @param SnippetId $other
     * @return bool
     */
    public function equals(SnippetId $other): bool
    {
        return $this->value === $other->value;
    }

    /**
     * Representación string
     *
     * @return string
     */
    public function __toString(): string
    {
        return $this->value;
    }
}
