<?php
declare(strict_types=1);

namespace ROITheme\Shared\Domain\ValueObjects;

/**
 * Value Object: Exclusion por categoria
 *
 * Evalua si un post pertenece a alguna de las categorias excluidas.
 * Soporta matching por slug o term_id.
 *
 * @package ROITheme\Shared\Domain\ValueObjects
 */
final class CategoryExclusion extends ExclusionRule
{
    /**
     * @param array<int|string> $excludedCategories Lista de slugs o IDs de categorias
     */
    public function __construct(
        private readonly array $excludedCategories = []
    ) {}

    /**
     * {@inheritdoc}
     *
     * Contexto esperado:
     * - categories: array<array{term_id: int, slug: string, name: string}>
     */
    public function matches(array $context): bool
    {
        if (!$this->hasValues()) {
            return false;
        }

        $postCategories = $context['categories'] ?? [];

        if (empty($postCategories)) {
            return false;
        }

        foreach ($postCategories as $category) {
            // Buscar por slug
            if (in_array($category['slug'], $this->excludedCategories, true)) {
                return true;
            }

            // Buscar por term_id
            if (in_array($category['term_id'], $this->excludedCategories, true)) {
                return true;
            }

            // Buscar por term_id como string (para comparaciones flexibles)
            if (in_array((string) $category['term_id'], $this->excludedCategories, true)) {
                return true;
            }
        }

        return false;
    }

    public function hasValues(): bool
    {
        return !empty($this->excludedCategories);
    }

    public function serialize(): string
    {
        return json_encode($this->excludedCategories, JSON_UNESCAPED_UNICODE);
    }

    /**
     * @return array<int|string>
     */
    public function getExcludedCategories(): array
    {
        return $this->excludedCategories;
    }

    /**
     * Crea instancia desde JSON
     */
    public static function fromJson(string $json): self
    {
        $decoded = json_decode($json, true);

        if (!is_array($decoded)) {
            return self::empty();
        }

        return new self($decoded);
    }

    /**
     * Crea instancia vacia
     */
    public static function empty(): self
    {
        return new self([]);
    }
}
