<?php
declare(strict_types=1);

namespace Archive\StreamWrapper;

use App\Framework\StreamWrapper\StreamWrapperRegistry;

/**
 * Factory für die einfache Erstellung und Nutzung von Stream-Wrappern
 */
final class StreamWrapperFactory
{
    /**
     * Initialisiert alle Stream-Wrapper und Filter
     */
    public static function initialize(): void
    {
        StreamWrapperRegistry::initializeDefaults();
        \Archive\StreamWrapper\Filter\StreamFilterRegistry::initializeDefaults();
    }

    /**
     * Erstellt eine Cache-Stream-URL
     */
    public static function cache(string $key, ?string $namespace = null): string
    {
        $host = $namespace ?? 'default';
        return "cache://{$host}/{$key}";
    }

    /**
     * Erstellt eine Config-Stream-URL
     */
    public static function config(string $key, string $source = 'default'): string
    {
        return "config://{$source}/{$key}";
    }

    /**
     * Erstellt eine Log-Stream-URL
     */
    public static function log(string $filename, string $channel = 'default'): string
    {
        return "log://{$channel}/{$filename}";
    }


    /**
     * Erstellt eine Database-Stream-URL
     */
    public static function database(string $table, string $operation = 'select', array $params = [], string $connection = 'default'): string
    {
        $url = "db://{$connection}/{$table}/{$operation}";

        if (!empty($params)) {
            $url .= '?' . http_build_query($params);
        }

        return $url;
    }

    /**
     * Erstellt eine HTTP-Client-Stream-URL
     */
    public static function httpClient(string $host, string $path = ''): string
    {
        return "http-client://{$host}/{$path}";
    }

    /**
     * Liest Daten von einer Stream-URL
     */
    public static function read(string $url, array $contextOptions = []): string|false
    {
        if (!empty($contextOptions)) {
            $context = stream_context_create($contextOptions);
            return file_get_contents($url, false, $context);
        }

        return file_get_contents($url);
    }

    /**
     * Schreibt Daten zu einer Stream-URL
     */
    public static function write(string $url, string $data, array $contextOptions = []): int|false
    {
        if (!empty($contextOptions)) {
            $context = stream_context_create($contextOptions);
            return file_put_contents($url, $data, 0, $context);
        }

        return file_put_contents($url, $data);
    }

    /**
     * Prüft, ob eine Stream-URL existiert
     */
    public static function exists(string $url): bool
    {
        return file_exists($url);
    }

    /**
     * Kopiert zwischen Stream-URLs
     */
    public static function copy(string $from, string $to): bool
    {
        return copy($from, $to);
    }

    /**
     * Löscht eine Stream-URL
     */
    public static function delete(string $url): bool
    {
        return unlink($url);
    }

    /**
     * Erstellt einen Stream mit Filtern
     */
    public static function createFilteredStream(string $url, string $mode, array $filters = [], array $contextOptions = [])
    {
        return \Archive\StreamWrapper\Filter\StreamFilterFactory::createFilteredStream($url, $mode, $filters, $contextOptions);
    }

    /**
     * Wendet Filter auf einen bestehenden Stream an
     */
    public static function applyFilters($stream, array $filters, int $mode = STREAM_FILTER_ALL): array
    {
        return \Archive\StreamWrapper\Filter\StreamFilterFactory::applyFilters($stream, $filters, $mode);
    }

    /**
     * Liest von einer URL mit angewendeten Filtern
     */
    public static function readWithFilters(string $url, array $filters = [], array $contextOptions = []): string|false
    {
        $stream = self::createFilteredStream($url, 'r', $filters, $contextOptions);
        if (!$stream) {
            return false;
        }

        $content = stream_get_contents($stream);
        fclose($stream);

        return $content;
    }

    /**
     * Schreibt zu einer URL mit angewendeten Filtern
     */
    public static function writeWithFilters(string $url, string $data, array $filters = [], array $contextOptions = []): int|false
    {
        $stream = self::createFilteredStream($url, 'w', $filters, $contextOptions);
        if (!$stream) {
            return false;
        }

        $result = fwrite($stream, $data);
        fclose($stream);

        return $result;
    }
}
