<?php
declare(strict_types=1);

namespace Archive\StreamWrapper\Filter;

use App\Framework\StreamWrapper\Exception\StreamWrapperException;
use App\Framework\StreamWrapper\Filter\Filters;

/**
 * Registry zur Verwaltung und Registrierung von Stream-Filtern
 */
final class StreamFilterRegistry
{
    private static array $registeredFilters = [];
    private static bool $initialized = false;

    /**
     * Registriert einen Stream-Filter
     */
    public static function register(string $filterName, string $filterClass): void
    {
        if (self::isRegistered($filterName)) {
            stream_filter_remove($filterName);
        }

        if (!stream_filter_register($filterName, $filterClass)) {
            throw new StreamWrapperException("Failed to register filter: $filterName");
        }

        self::$registeredFilters[$filterName] = $filterClass;
    }

    /**
     * Entfernt die Registrierung eines Stream-Filters
     */
    public static function unregister(string $filterName): void
    {
        if (self::isRegistered($filterName)) {
            // Hinweis: stream_filter_unregister existiert nicht in PHP
            // Filter werden automatisch beim Script-Ende entfernt
            unset(self::$registeredFilters[$filterName]);
        }
    }

    /**
     * Prüft, ob ein Filter registriert ist
     */
    public static function isRegistered(string $filterName): bool
    {
        return isset(self::$registeredFilters[$filterName]);
    }

    /**
     * Gibt alle registrierten Filter zurück
     */
    public static function getRegisteredFilters(): array
    {
        return array_keys(self::$registeredFilters);
    }

    /**
     * Gibt die Filter-Klasse zurück
     */
    public static function getFilterClass(string $filterName): ?string
    {
        return self::$registeredFilters[$filterName] ?? null;
    }

    /**
     * Initialisiert alle Standard-Stream-Filter
     */
    public static function initializeDefaults(): void
    {
        if (self::$initialized) {
            return;
        }

        // Komprimierungs-Filter
        self::register('gzip.compress', Filters\GzipCompressFilter::class);
        self::register('gzip.decompress', \Archive\StreamWrapper\Filter\Filters\GzipDecompressFilter::class);

        // Verschlüsselungs-Filter
        self::register('encrypt.aes256', Filters\AES256EncryptFilter::class);
        self::register('decrypt.aes256', \Archive\StreamWrapper\Filter\Filters\AES256DecryptFilter::class);

        // Validierungs-Filter
        self::register('validate.json', Filters\JsonValidationFilter::class);
        self::register('validate.xml', Filters\XmlValidationFilter::class);

        // Transform-Filter
        self::register('transform.base64encode', \Archive\StreamWrapper\Filter\Filters\Base64EncodeFilter::class);
        self::register('transform.base64decode', Filters\Base64DecodeFilter::class);
        self::register('transform.uppercase', Filters\UppercaseFilter::class);
        self::register('transform.lowercase', Filters\LowercaseFilter::class);

        // Logging-Filter
        self::register('log.access', \Archive\StreamWrapper\Filter\Filters\AccessLogFilter::class);
        self::register('log.debug', Filters\DebugLogFilter::class);

        // Caching-Filter
        self::register('cache.write', Filters\CacheWriteFilter::class);
        self::register('cache.read', Filters\CacheReadFilter::class);

        self::$initialized = true;
    }

    /**
     * Entfernt alle Framework-Stream-Filter
     */
    public static function cleanup(): void
    {
        self::$registeredFilters = [];
        self::$initialized = false;
    }

    /**
     * Wendet einen Filter auf einen Stream an
     */
    public static function appendFilter($stream, string $filterName, int $mode = STREAM_FILTER_ALL, array $params = [])
    {
        if (!self::isRegistered($filterName)) {
            throw new StreamWrapperException("Filter not registered: $filterName");
        }

        return stream_filter_append($stream, $filterName, $mode, $params);
    }

    /**
     * Wendet einen Filter am Anfang eines Streams an
     */
    public static function prependFilter($stream, string $filterName, int $mode = STREAM_FILTER_ALL, array $params = [])
    {
        if (!self::isRegistered($filterName)) {
            throw new StreamWrapperException("Filter not registered: $filterName");
        }

        return stream_filter_prepend($stream, $filterName, $mode, $params);
    }

    /**
     * Entfernt einen Filter von einem Stream
     */
    public static function removeFilter($filter): bool
    {
        return stream_filter_remove($filter);
    }

    /**
     * Erstellt eine Filter-Kette für einen Stream
     */
    public static function createFilterChain($stream, array $filters, int $mode = STREAM_FILTER_ALL): array
    {
        $appliedFilters = [];

        foreach ($filters as $filterConfig) {
            $filterName = $filterConfig['name'] ?? $filterConfig;
            $params = $filterConfig['params'] ?? [];

            $filter = self::appendFilter($stream, $filterName, $mode, $params);
            if ($filter) {
                $appliedFilters[] = $filter;
            }
        }

        return $appliedFilters;
    }
}
