<?php

declare(strict_types=1);

namespace App\Framework\Filesystem;

use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\Filesystem\Serializers\CsvSerializer;
use App\Framework\Filesystem\Serializers\JsonSerializer;
use App\Framework\Filesystem\Serializers\PhpSerializer;
use App\Framework\Filesystem\ValueObjects\FilesystemConfig;

/**
 * Filesystem-System Initializer
 *
 * Registriert alle Filesystem-Komponenten im DI-Container
 * entsprechend der Framework-Konventionen.
 */
final readonly class FilesystemInitializer
{
    #[Initializer]
    public function initializeFilesystem(Container $container): void
    {
        // Filesystem Config
        $container->singleton(FilesystemConfig::class, function () {
            return new FilesystemConfig(
                defaultStorage: $_ENV['FILESYSTEM_DEFAULT_STORAGE'] ?? 'local',
                storages: [
                    'local' => [
                        'type' => 'file',
                        'path' => $_ENV['FILESYSTEM_LOCAL_PATH'] ?? '/var/www/html/storage',
                    ],
                    'temp' => [
                        'type' => 'file',
                        'path' => $_ENV['FILESYSTEM_TEMP_PATH'] ?? '/tmp',
                    ],
                    'analytics' => [
                        'type' => 'file',
                        'path' => $_ENV['ANALYTICS_DATA_PATH'] ?? '/var/www/html/storage/analytics',
                    ],
                ],
                enableCompression: filter_var($_ENV['FILESYSTEM_COMPRESSION'] ?? 'false', FILTER_VALIDATE_BOOLEAN),
                enableAtomicWrites: filter_var($_ENV['FILESYSTEM_ATOMIC_WRITES'] ?? 'true', FILTER_VALIDATE_BOOLEAN),
                enableFileLocking: filter_var($_ENV['FILESYSTEM_FILE_LOCKING'] ?? 'true', FILTER_VALIDATE_BOOLEAN)
            );
        });

        // Serializers
        $container->singleton(JsonSerializer::class, function () {
            return new JsonSerializer();
        });

        $container->singleton(PhpSerializer::class, function () {
            return new PhpSerializer();
        });

        $container->singleton(CsvSerializer::class, function () {
            return new CsvSerializer();
        });

        // SerializerRegistry
        $container->singleton(SerializerRegistry::class, function (Container $container) {
            $registry = new SerializerRegistry();

            // Register all serializers
            $registry->register('json', $container->get(JsonSerializer::class), setAsDefault: true);
            $registry->register('php', $container->get(PhpSerializer::class));
            $registry->register('csv', $container->get(CsvSerializer::class));

            return $registry;
        });

        // FileValidator - Default Validator (always cached for performance)
        $container->singleton(FileValidator::class, function () {
            $validator = FileValidator::createDefault();

            // Always use caching for optimal performance
            // Disable only for debugging: FILESYSTEM_DISABLE_CACHE=true
            $disableCache = filter_var($_ENV['FILESYSTEM_DISABLE_CACHE'] ?? 'false', FILTER_VALIDATE_BOOLEAN);

            if ($disableCache) {
                return $validator;
            }

            return new CachedFileValidator(
                validator: $validator,
                cacheTtl: 60,        // Sensible default: 1 minute
                maxCacheSize: 100    // Sensible default: 100 entries
            );
        });

        // FileValidator - Upload Validator (always cached)
        $container->singleton('filesystem.validator.upload', function () {
            $validator = FileValidator::forUploads();

            $disableCache = filter_var($_ENV['FILESYSTEM_DISABLE_CACHE'] ?? 'false', FILTER_VALIDATE_BOOLEAN);

            if ($disableCache) {
                return $validator;
            }

            return new CachedFileValidator(validator: $validator);
        });

        // FileValidator - Image Validator (always cached)
        $container->singleton('filesystem.validator.image', function () {
            $validator = FileValidator::forImages();

            $disableCache = filter_var($_ENV['FILESYSTEM_DISABLE_CACHE'] ?? 'false', FILTER_VALIDATE_BOOLEAN);

            if ($disableCache) {
                return $validator;
            }

            return new CachedFileValidator(validator: $validator);
        });

        // Storage Instances
        $this->registerStorages($container);

        // Filesystem Manager
        $container->singleton(FilesystemManager::class, function (Container $container) {
            $config = $container->get(FilesystemConfig::class);
            $registry = $container->get(SerializerRegistry::class);

            // Use SerializerRegistry in FilesystemManager
            $manager = new FilesystemManager(
                defaultStorageName: $config->defaultStorage,
                serializerRegistry: $registry
            );

            // Registriere alle konfigurierten Storages
            foreach ($config->getAvailableStorages() as $storageName) {
                $storage = $container->get("filesystem.storage.{$storageName}");
                $manager->registerStorage($storageName, $storage);
            }

            return $manager;
        });
    }

    private function registerStorages(Container $container): void
    {
        // Always enable storage caching for optimal performance
        // Disable only for debugging: FILESYSTEM_DISABLE_CACHE=true
        $disableCache = filter_var($_ENV['FILESYSTEM_DISABLE_CACHE'] ?? 'false', FILTER_VALIDATE_BOOLEAN);
        $enableStorageCache = !$disableCache;

        // Default Storage - nutzt PathProvider aus Container
        $container->singleton(Storage::class, function (Container $container) use ($enableStorageCache) {
            $pathProvider = $container->get(\App\Framework\Core\PathProvider::class);
            $storage = new FileStorage('/', pathProvider: $pathProvider);

            // Wrap with CachedFileStorage for performance
            if ($enableStorageCache) {
                return new CachedFileStorage($storage, basePath: '/');
            }

            return $storage;
        });

        $container->singleton(FileStorage::class, function (Container $container) use ($enableStorageCache) {
            $pathProvider = $container->get(\App\Framework\Core\PathProvider::class);
            $storage = new FileStorage('/', pathProvider: $pathProvider);

            // Wrap with CachedFileStorage for performance
            if ($enableStorageCache) {
                return new CachedFileStorage($storage, basePath: '/');
            }

            return $storage;
        });

        // Named Storages - nutzen PathProvider aus Container
        $container->singleton('filesystem.storage.local', function (Container $container) use ($enableStorageCache) {
            $config = $container->get(FilesystemConfig::class);
            $storageConfig = $config->getStorageConfig('local');
            $pathProvider = $container->get(\App\Framework\Core\PathProvider::class);

            $storage = new FileStorage($storageConfig['path'], pathProvider: $pathProvider);

            if ($enableStorageCache) {
                return new CachedFileStorage($storage, basePath: $storageConfig['path']);
            }

            return $storage;
        });

        $container->singleton('filesystem.storage.temp', function (Container $container) use ($enableStorageCache) {
            $config = $container->get(FilesystemConfig::class);
            $storageConfig = $config->getStorageConfig('temp');
            $pathProvider = $container->get(\App\Framework\Core\PathProvider::class);

            $storage = new FileStorage($storageConfig['path'], pathProvider: $pathProvider);

            if ($enableStorageCache) {
                return new CachedFileStorage($storage, basePath: $storageConfig['path']);
            }

            return $storage;
        });

        $container->singleton('filesystem.storage.analytics', function (Container $container) use ($enableStorageCache) {
            $config = $container->get(FilesystemConfig::class);
            $storageConfig = $config->getStorageConfig('analytics');
            $pathProvider = $container->get(\App\Framework\Core\PathProvider::class);

            $storage = new FileStorage($storageConfig['path'], pathProvider: $pathProvider);

            if ($enableStorageCache) {
                return new CachedFileStorage($storage, basePath: $storageConfig['path']);
            }

            return $storage;
        });
    }
}
