<?php

namespace App\Framework\View\Caching;

use App\Framework\Cache\Cache;
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\RenderContext;
use Archive\Archived\SmartCacheEngine;

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
    {
        // 1. Template analysieren für optimale Strategy
        $analysis = $this->analyzer->analyze($context->template);
        $this->lastAnalysis = $analysis;

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

        if (!$strategy->shouldCache($context)) {
            return $renderer();
        }

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

        // 4. Cache-Lookup
        $cached = $this->cache->get($cacheKey);
        if ($cached->isHit) {
            return $cached->value;
        }

        // 5. Rendern und cachen
        $content = $renderer();
        $ttl = $strategy->getTtl($context);

        $this->cache->set($cacheKey, $content, $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(null $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;
    }
}
