<?php

declare(strict_types=1);

namespace App\Framework\Database\Cache;

/**
 * Einfache Cache-Strategy als Fallback wenn kein Framework-Cache verfügbar
 */
final class SimpleCacheStrategy implements CacheStrategy
{
    private array $cache = [];

    private array $expiry = [];

    private array $stats = [
        'hits' => 0,
        'misses' => 0,
        'sets' => 0,
        'deletes' => 0,
        'invalidations' => 0,
    ];

    public function __construct(
        private readonly string $keyPrefix = 'db_query:'
    ) {
    }

    public function set(QueryCacheKey $key, array $value, int $ttlSeconds): bool
    {
        $keyString = $this->keyPrefix . $key->toString();

        $this->cache[$keyString] = $value;
        $this->expiry[$keyString] = time() + $ttlSeconds;
        $this->stats['sets']++;

        return true;
    }

    public function get(QueryCacheKey $key): ?array
    {
        $keyString = $this->keyPrefix . $key->toString();

        // Prüfe Ablauf
        if (isset($this->expiry[$keyString]) && time() > $this->expiry[$keyString]) {
            $this->delete($key);
            $this->stats['misses']++;

            return null;
        }

        if (isset($this->cache[$keyString])) {
            $this->stats['hits']++;

            return $this->cache[$keyString];
        }

        $this->stats['misses']++;

        return null;
    }

    public function has(QueryCacheKey $key): bool
    {
        return $this->get($key) !== null;
    }

    public function delete(QueryCacheKey $key): bool
    {
        $keyString = $this->keyPrefix . $key->toString();

        $existed = isset($this->cache[$keyString]);

        unset($this->cache[$keyString], $this->expiry[$keyString]);

        if ($existed) {
            $this->stats['deletes']++;
        }

        return $existed;
    }

    public function invalidatePattern(string $pattern): int
    {
        $deleted = 0;

        foreach (array_keys($this->cache) as $keyString) {
            if (fnmatch($pattern, $keyString)) {
                unset($this->cache[$keyString], $this->expiry[$keyString]);
                $deleted++;
            }
        }

        $this->stats['invalidations'] += $deleted;

        return $deleted;
    }

    public function clear(): void
    {
        $count = count($this->cache);
        $this->cache = [];
        $this->expiry = [];
        $this->stats['invalidations'] += $count;
    }

    public function getStats(): array
    {
        return array_merge($this->stats, [
            'size' => count($this->cache),
            'memory_usage' => $this->estimateMemoryUsage(),
            'hit_ratio' => $this->calculateHitRatio(),
            'cache_type' => 'SimpleCacheStrategy',
        ]);
    }

    private function estimateMemoryUsage(): int
    {
        return memory_get_usage() - memory_get_usage(true); // Grobe Schätzung
    }

    private function calculateHitRatio(): float
    {
        $total = $this->stats['hits'] + $this->stats['misses'];

        return $total > 0 ? ($this->stats['hits'] / $total) : 0.0;
    }

    /**
     * Bereinigt abgelaufene Einträge
     */
    public function cleanup(): int
    {
        $currentTime = time();
        $cleaned = 0;

        foreach ($this->expiry as $keyString => $expiry) {
            if ($currentTime > $expiry) {
                unset($this->cache[$keyString], $this->expiry[$keyString]);
                $cleaned++;
            }
        }

        return $cleaned;
    }
}
