<?php

namespace App\Framework\View\Caching;

use App\Framework\Cache\Cache;

class TaggedFragmentCache implements FragmentCache
{
    private array $tagMapping = [];

    public function __construct(private Cache $cache) {}

    public function fragment(string $key, callable $generator, int $ttl, array $tags = []): string
    {
        $fullKey = "fragment:{$key}";

        $cached = $this->cache->get($fullKey);
        if ($cached->isHit) {
            return $cached->value;
        }

        $content = $generator();

        $this->cache->set($fullKey, $content, $ttl);
        $this->tagFragment($fullKey, $tags);

        return $content;
    }

    public function invalidateFragment(string $key): bool
    {
        $fullKey = "fragment:{$key}";
        return $this->cache->forget($fullKey);
    }

    public function invalidateByTags(array $tags): int
    {
        $invalidated = 0;
        foreach ($tags as $tag) {
            $keys = $this->getKeysByTag($tag);
            foreach ($keys as $key) {
                if ($this->cache->forget($key)) {
                    $invalidated++;
                }
            }
        }
        return $invalidated;
    }

    public function hasFragment(string $key): bool
    {
        $fullKey = "fragment:{$key}";
        return $this->cache->has($fullKey);
    }

    private function tagFragment(string $key, array $tags): void
    {
        foreach ($tags as $tag) {
            if (!isset($this->tagMapping[$tag])) {
                $this->tagMapping[$tag] = [];
            }
            $this->tagMapping[$tag][] = $key;
        }
    }

    private function getKeysByTag(string $tag): array
    {
        return $this->tagMapping[$tag] ?? [];
    }
}
