<?php

declare(strict_types=1);

namespace App\Framework\View\Caching;

use App\Framework\Cache\Cache;
use App\Framework\Cache\CacheItem;
use App\Framework\View\Caching\Analysis\CacheStrategy;
use App\Framework\View\Caching\Analysis\TemplateAnalysis;
use App\Framework\View\Caching\Analysis\TemplateAnalyzer;
use App\Framework\View\Caching\Strategies\ComponentCacheStrategy;
use App\Framework\View\Caching\Strategies\FragmentCacheStrategy;
use App\Framework\View\Caching\Strategies\FullPageCacheStrategy;
use App\Framework\View\Caching\Strategies\NoCacheStrategy;
use App\Framework\View\Caching\Strategies\ViewCacheStrategy;
use App\Framework\View\Exceptions\TemplateCacheException;

class CacheManager
{
    private array $strategies = [];

    private ?TemplateAnalysis $lastAnalysis = null;

    public function __construct(
        private Cache $cache,
        private TemplateAnalyzer $analyzer,
        private FragmentCache $fragmentCache,
        private array $strategyMapping = []
    ) {
        $this->initializeStrategies();
    }

    public function render(TemplateContext $context, callable $renderer): string
    {
        // DEBUG: Log cache analysis for routes template
        if ($context->template === 'routes') {
            error_log("CacheManager::render - Template: routes");
        }

        // 1. Template analysieren für optimale Strategy
        $analysis = $this->analyzer->analyze($context->template);
        $this->lastAnalysis = $analysis;

        // DEBUG: Log analysis results for routes template
        if ($context->template === 'routes') {
            error_log("CacheManager::render - Strategy: " . $analysis->recommendedStrategy->name);
            error_log("CacheManager::render - Cacheable: " . ($analysis->cacheability->isCacheable() ? 'YES' : 'NO'));
            error_log("CacheManager::render - Static ratio: " . $analysis->cacheability->staticContentRatio);
        }

        // 2. Passende Strategy auswählen
        $strategy = $this->selectStrategy($analysis);

        if (! $strategy->shouldCache($context)) {
            $content = $renderer();
            if (! is_string($content)) {
                throw TemplateCacheException::invalidCacheFormat(
                    'non_cached_content',
                    'string',
                    get_debug_type($content)
                );
            }

            return $content;
        }

        // 3. Cache-Key generieren
        $cacheKey = $strategy->generateKey($context);

        // 4. Cache-Lookup
        $result = $this->cache->get($cacheKey);
        $cached = $result->getItem($cacheKey);
        if ($cached->isHit && is_string($cached->value)) {
            // DEBUG: Log cache hit for routes template
            if ($context->template === 'routes') {
                error_log("CacheManager::render - CACHE HIT! Returning cached content (length: " . strlen($cached->value) . ")");
                error_log("CacheManager::render - First 200 chars: " . substr($cached->value, 0, 200));
            }

            return $cached->value;
        }

        // 5. Rendern und cachen
        if ($context->template === 'routes') {
            error_log("CacheManager::render - CACHE MISS! Calling renderer()");
        }
        $content = $renderer();

        if (! is_string($content)) {
            throw TemplateCacheException::invalidCacheFormat(
                $cacheKey,
                'string',
                get_debug_type($content)
            );
        }

        $ttl = $strategy->getTtl($context);
        $this->cache->set(CacheItem::forSet($cacheKey, $content, \App\Framework\Core\ValueObjects\Duration::fromSeconds($ttl)));

        return $content;
    }

    public function invalidateTemplate(string $template): int
    {
        $invalidated = 0;

        // Invalidiere alle Strategies für dieses Template
        foreach ($this->strategies as $strategy) {
            if ($strategy->canInvalidate($template)) {
                // Pattern-basierte Invalidierung je nach Strategy
                $pattern = $this->buildInvalidationPattern($strategy, $template);
                $invalidated += $this->invalidateByPattern($pattern);
            }
        }

        return $invalidated;
    }

    private function selectStrategy(TemplateAnalysis $analysis): ViewCacheStrategy
    {
        return match($analysis->recommendedStrategy) {
            CacheStrategy::FULL_PAGE => $this->strategies['full_page'],
            CacheStrategy::COMPONENT => $this->strategies['component'],
            CacheStrategy::FRAGMENT => $this->strategies['fragment'],
            CacheStrategy::USER_AWARE => $this->strategies['user_aware'],
            default => $this->strategies['no_cache']
        };
    }

    private function initializeStrategies(): void
    {
        $this->strategies = [
            'full_page' => new FullPageCacheStrategy($this->cache),
            'component' => new ComponentCacheStrategy($this->cache),
            'fragment' => new FragmentCacheStrategy($this->cache),
            'no_cache' => new NoCacheStrategy(),
        ];
    }

    private function buildInvalidationPattern(mixed $strategy, string $template): string
    {
        return match(get_class($strategy)) {
            FullPageCacheStrategy::class => "page:{$template}:*",
            ComponentCacheStrategy::class => "component:*{$template}*",
            FragmentCacheStrategy::class => "fragment:{$template}:*",
            default => "*{$template}*"
        };
    }

    private function invalidateByPattern(string $pattern): int
    {
        // Vereinfachte Implementation - in Realität müsste das der Cache-Driver unterstützen
        // Für jetzt: Cache komplett leeren bei Pattern-Match
        $invalidated = 0;

        if (str_contains($pattern, '*')) {
            $this->cache->clear();
            $invalidated = 1;
        }

        return $invalidated;
    }
}
