<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Cache;

use Flowaxy\Contracts\Cache\CacheInterface;
use Flowaxy\Support\Facades\Log;
use Throwable;

/**
 * Тегирование кеша для массовой инвалидации
 *
 * @package Flowaxy\Infrastructure\Cache
 */
final class CacheTags
{
    private CacheInterface $cache;
    private string $tagPrefix = 'cache:tag:';

    public function __construct(CacheInterface $cache)
    {
        $this->cache = $cache;
    }

    /**
     * Пометить ключ тегами
     *
     * @param string $key Ключ кеша
     * @param array<int, string> $tags Теги
     * @return void
     */
    public function tag(string $key, array $tags): void
    {
        foreach ($tags as $tag) {
            $tagKey = $this->tagPrefix . $tag;
            $keys = $this->cache->get($tagKey, []);
            if (!is_array($keys)) {
                $keys = [];
            }
            if (!in_array($key, $keys, true)) {
                $keys[] = $key;
            }
            $this->cache->set($tagKey, $keys, 86400 * 30); // 30 дней
        }
    }

    /**
     * Инвалидировать все ключи с указанными тегами
     *
     * @param array<int, string> $tags Теги
     * @return int Количество удаленных ключей
     */
    public function flush(array $tags): int
    {
        $count = 0;

        foreach ($tags as $tag) {
            $tagKey = $this->tagPrefix . $tag;
            $keys = $this->cache->get($tagKey, []);

            if (is_array($keys)) {
                foreach ($keys as $key) {
                    if ($this->cache->delete($key)) {
                        $count++;
                    }
                }
            }

            $this->cache->delete($tagKey);
        }

        return $count;
    }

    /**
     * Получить все ключи с указанным тегом
     *
     * @param string $tag Тег
     * @return array<int, string>
     */
    public function getKeysByTag(string $tag): array
    {
        $tagKey = $this->tagPrefix . $tag;
        $keys = $this->cache->get($tagKey, []);
        return is_array($keys) ? $keys : [];
    }
}
