<?php

declare(strict_types=1);

namespace Tests\Framework\Filesystem;

use App\Framework\Filesystem\Directory;
use App\Framework\Filesystem\File;
use App\Framework\Filesystem\FileStorage;
use App\Framework\Filesystem\InMemoryStorage;
use App\Framework\Filesystem\PermissionChecker;
use App\Framework\Filesystem\Storage;

it('lädt File-Properties erst bei Bedarf', function () {
    // Test-Storage mit Instrumentierung
    $baseStorage = new InMemoryStorage();
    $storage = new class ($baseStorage) implements Storage {
        public array $accessed = [];

        public function __construct(private InMemoryStorage $baseStorage)
        {
        }

        public function get(string $path): string
        {
            $this->accessed[] = "get:{$path}";

            return $this->baseStorage->get($path);
        }

        public function size(string $path): int
        {
            $this->accessed[] = "size:{$path}";

            return $this->baseStorage->size($path);
        }

        // All other methods delegate to base storage
        public function put(string $path, string $content): void
        {
            $this->baseStorage->put($path, $content);
        }

        public function exists(string $path): bool
        {
            return $this->baseStorage->exists($path);
        }

        public function delete(string $path): void
        {
            $this->baseStorage->delete($path);
        }

        public function copy(string $source, string $destination): void
        {
            $this->baseStorage->copy($source, $destination);
        }

        public function lastModified(string $path): int
        {
            return $this->baseStorage->lastModified($path);
        }

        public function addFile(string $path, string $content): void
        {
            $this->baseStorage->addFile($path, $content);
        }

        public function getMimeType(string $path): string
        {
            return $this->baseStorage->getMimeType($path);
        }

        public function isReadable(string $path): bool
        {
            return $this->baseStorage->isReadable($path);
        }

        public function isWritable(string $path): bool
        {
            return $this->baseStorage->isWritable($path);
        }

        public function listDirectory(string $directory): array
        {
            return $this->baseStorage->listDirectory($directory);
        }

        public function createDirectory(string $path, int $permissions = 0755, bool $recursive = true): void
        {
            $this->baseStorage->createDirectory($path, $permissions, $recursive);
        }

        public function file(string $path): File
        {
            return $this->baseStorage->file($path);
        }

        public function directory(string $path): Directory
        {
            return $this->baseStorage->directory($path);
        }

        public function batch(array $operations): array
        {
            return $this->baseStorage->batch($operations);
        }

        public function getMultiple(array $paths): array
        {
            return $this->baseStorage->getMultiple($paths);
        }

        public function putMultiple(array $files): void
        {
            $this->baseStorage->putMultiple($files);
        }

        public function getMetadataMultiple(array $paths): array
        {
            return $this->baseStorage->getMetadataMultiple($paths);
        }

        public PermissionChecker $permissions {
            get => $this->baseStorage->permissions;
        }

        public \App\Framework\Async\FiberManager $fiberManager {
            get => $this->baseStorage->fiberManager;
        }
    };

    // Testdatei hinzufügen
    $storage->addFile('/test.txt', 'Testinhalt');

    // Lazy File erstellen
    $file = $storage->file('/test.txt');

    // Sollte noch keine Storage-Methoden aufgerufen haben
    expect($storage->accessed)->toBeEmpty();

    // Zugriff auf path sollte kein Laden auslösen
    $path = $file->path;
    expect($storage->accessed)->toBeEmpty();

    // Zugriff auf contents sollte get() auslösen
    $contents = $file->contents;
    expect($storage->accessed)->toContain('get:/test.txt');
    expect($contents)->toBe('Testinhalt');

    // Zugriff auf size sollte size() auslösen
    $size = $file->size;
    expect($storage->accessed)->toContain('size:/test.txt');
    expect($size)->toBe(10); // Länge von 'Testinhalt'
});

it('lädt Directory-Properties erst bei Bedarf', function () {
    // Test-Storage mit Instrumentierung
    $baseStorage = new InMemoryStorage();
    $storage = new class ($baseStorage) implements Storage {
        public array $accessed = [];

        public function __construct(private InMemoryStorage $baseStorage)
        {
        }

        public function listDirectory(string $directory): array
        {
            $this->accessed[] = "list:{$directory}";

            return $this->baseStorage->listDirectory($directory);
        }

        // Delegate all other methods to base storage
        public function get(string $path): string
        {
            return $this->baseStorage->get($path);
        }

        public function put(string $path, string $content): void
        {
            $this->baseStorage->put($path, $content);
        }

        public function exists(string $path): bool
        {
            return $this->baseStorage->exists($path);
        }

        public function delete(string $path): void
        {
            $this->baseStorage->delete($path);
        }

        public function copy(string $source, string $destination): void
        {
            $this->baseStorage->copy($source, $destination);
        }

        public function size(string $path): int
        {
            return $this->baseStorage->size($path);
        }

        public function lastModified(string $path): int
        {
            return $this->baseStorage->lastModified($path);
        }

        public function getMimeType(string $path): string
        {
            return $this->baseStorage->getMimeType($path);
        }

        public function isReadable(string $path): bool
        {
            return $this->baseStorage->isReadable($path);
        }

        public function isWritable(string $path): bool
        {
            return $this->baseStorage->isWritable($path);
        }

        public function createDirectory(string $path, int $permissions = 0755, bool $recursive = true): void
        {
            $this->baseStorage->createDirectory($path, $permissions, $recursive);
        }

        public function file(string $path): File
        {
            return $this->baseStorage->file($path);
        }

        public function directory(string $path): Directory
        {
            return $this->baseStorage->directory($path);
        }

        public function batch(array $operations): array
        {
            return $this->baseStorage->batch($operations);
        }

        public function getMultiple(array $paths): array
        {
            return $this->baseStorage->getMultiple($paths);
        }

        public function putMultiple(array $files): void
        {
            $this->baseStorage->putMultiple($files);
        }

        public function getMetadataMultiple(array $paths): array
        {
            return $this->baseStorage->getMetadataMultiple($paths);
        }

        public function addFile(string $path, string $content): void
        {
            $this->baseStorage->addFile($path, $content);
        }

        public PermissionChecker $permissions {
            get => $this->baseStorage->permissions;
        }

        public \App\Framework\Async\FiberManager $fiberManager {
            get => $this->baseStorage->fiberManager;
        }
    };

    // Testverzeichnis erstellen
    $storage->createDirectory('/test-dir');
    $storage->addFile('/test-dir/file1.txt', 'Datei 1');
    $storage->addFile('/test-dir/file2.txt', 'Datei 2');

    // Lazy Directory erstellen
    $dir = $storage->directory('/test-dir');

    // Sollte noch keine Storage-Methoden aufgerufen haben
    expect($storage->accessed)->toBeEmpty();

    // Zugriff auf path sollte kein Laden auslösen
    $path = $dir->path;
    expect($storage->accessed)->toBeEmpty();

    // Zugriff auf contents sollte listDirectory() auslösen
    $contents = $dir->contents;
    expect($storage->accessed)->toContain('list:/test-dir');
    expect($contents)->toHaveCount(2);
});

it('kann mit echtem FileStorage arbeiten', function () {
    // Dieser Test kann übersprungen werden, wenn keine Schreibrechte im Temp-Verzeichnis vorhanden sind
    $tempDir = sys_get_temp_dir() . '/php-lazy-test-' . uniqid();
    @mkdir($tempDir, 0777, true);
    if (! is_dir($tempDir) || ! is_writable($tempDir)) {
        $this->markTestSkipped('Kein Schreibzugriff im Temp-Verzeichnis');
    }

    try {
        // Echten FileStorage verwenden
        $storage = new FileStorage();

        // Testdatei erstellen
        $testFile = $tempDir . '/test.txt';
        file_put_contents($testFile, 'Lazy Loading Test');

        // Lazy File erstellen
        $file = $storage->file($testFile);

        // Properties testen
        expect($file->path)->toBe($testFile);
        expect($file->contents)->toBe('Lazy Loading Test');
        expect($file->size)->toBe(17); // Länge von 'Lazy Loading Test'
        expect($file->lastModified)->toBeGreaterThan(time() - 10);

        // Directory testen
        $dir = $storage->directory($tempDir);
        expect($dir->exists())->toBeTrue();

        $files = $dir->getFiles();
        expect($files)->toHaveCount(1);
        expect($files[0]->path)->toEndWith('/test.txt');
    } finally {
        // Aufräumen
        @unlink($testFile);
        @rmdir($tempDir);
    }
});
