<?php
declare(strict_types=1);

namespace App\Framework\Filesystem;

use App\Framework\Filesystem\Exceptions\DirectoryCreateException;
use App\Framework\Filesystem\Exceptions\DirectoryListException;
use App\Framework\Filesystem\Exceptions\FileCopyException;
use App\Framework\Filesystem\Exceptions\FileDeleteException;
use App\Framework\Filesystem\Exceptions\FileMetadataException;
use App\Framework\Filesystem\Exceptions\FileNotFoundException;
use App\Framework\Filesystem\Exceptions\FileReadException;
use App\Framework\Filesystem\Exceptions\FileWriteException;

final readonly class FileStorage implements Storage
{
    use StorageTrait;

    public function get(string $path): string
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        $content = @file_get_contents($path);
        if ($content === false) {
            throw new FileReadException($path);
        }
        return $content;
    }

    public function put(string $path, string $content): void
    {
        $dir = dirname($path);
        if (!is_dir($dir)) {
            if (!@mkdir($dir, 0777, true) && !is_dir($dir)) {
                throw new DirectoryCreateException($dir);
            }
        }
        if (@file_put_contents($path, $content) === false) {
            throw new FileWriteException($path);
        }
    }

    public function exists(string $path): bool
    {
        return is_file($path);
    }

    public function delete(string $path): void
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        if (!@unlink($path)) {
            throw new FileDeleteException($path);
        }
    }

    public function copy(string $source, string $destination): void
    {
        if (!is_file($source)) {
            throw new FileNotFoundException($source);
        }

        // Stelle sicher, dass das Zielverzeichnis existiert
        $dir = dirname($destination);
        if (!is_dir($dir)) {
            $this->createDirectory($dir);
        }

        if (!@copy($source, $destination)) {
            throw new FileCopyException($source, $destination);
        }
    }

    public function size(string $path): int
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        $size = @filesize($path);
        if ($size === false) {
            throw new FileReadException($path);
        }

        return $size;
    }

    public function lastModified(string $path): int
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        $time = @filemtime($path);
        if ($time === false) {
            throw new FileReadException($path);
        }

        return $time;
    }

    public function getMimeType(string $path): string
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        $mimeType = @mime_content_type($path);
        if ($mimeType === false) {
            throw new FileMetadataException($path);
        }

        return $mimeType;
    }

    public function isReadable(string $path): bool
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        return is_readable($path);
    }

    public function isWritable(string $path): bool
    {
        if (!is_file($path)) {
            throw new FileNotFoundException($path);
        }

        return is_writable($path);
    }

    public function listDirectory(string $directory): array
    {
        if (!is_dir($directory)) {
            throw new DirectoryCreateException($directory);
        }

        $files = @scandir($directory);
        if ($files === false) {
            throw new DirectoryListException($directory);
        }

        // Entferne . und .. Einträge
        $files = array_filter($files, function ($file) {
            return $file !== '.' && $file !== '..';
        });

        // Vollständige Pfade erstellen
        $result = [];
        foreach ($files as $file) {
            $result[] = $directory . DIRECTORY_SEPARATOR . $file;
        }

        return array_values($result);
    }

    public function createDirectory(string $path, int $permissions = 0755, bool $recursive = true): void
    {
        if (is_dir($path)) {
            return; // Verzeichnis existiert bereits
        }

        if (!@mkdir($path, $permissions, $recursive) && !is_dir($path)) {
            throw new DirectoryCreateException($path);
        }
    }
}
