<?php

declare(strict_types=1);

namespace App\Framework\Filesystem\Traits;

use App\Framework\Filesystem\Exceptions\FileNotFoundException;
use App\Framework\Filesystem\Exceptions\FileReadException;
use App\Framework\Filesystem\Exceptions\FileWriteException;

/**
 * Trait für Compression Storage-Operationen
 *
 * Implementiert automatische Komprimierung für große Dateien,
 * ideal für Analytics-Daten, Logs und Archive.
 */
trait CompressibleStorageTrait
{
    public function putCompressed(string $path, string $content, string $algorithm = 'gzip'): void
    {
        $compressedContent = match ($algorithm) {
            'gzip' => gzencode($content),
            'deflate' => gzdeflate($content),
            'bzip2' => bzcompress($content),
            default => throw new \InvalidArgumentException("Unsupported compression algorithm: {$algorithm}")
        };

        if ($compressedContent === false) {
            throw new FileWriteException($path);
        }

        $this->put($path . '.' . $algorithm, $compressedContent);
    }

    public function getCompressed(string $path): string
    {
        // Automatische Erkennung der Komprimierung basierend auf Dateiendung
        $pathInfo = pathinfo($path);
        $algorithm = $pathInfo['extension'] ?? '';

        if (! in_array($algorithm, ['gzip', 'gz', 'deflate', 'bzip2', 'bz2'])) {
            throw new \InvalidArgumentException("Cannot detect compression algorithm from path: {$path}");
        }

        if (! $this->exists($path)) {
            throw new FileNotFoundException($path);
        }

        $compressedContent = $this->get($path);

        $content = match ($algorithm) {
            'gzip', 'gz' => gzdecode($compressedContent),
            'deflate' => gzinflate($compressedContent),
            'bzip2', 'bz2' => bzdecompress($compressedContent),
            default => throw new \InvalidArgumentException("Unsupported compression algorithm: {$algorithm}")
        };

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

        return $content;
    }

    public function compress(string $path, string $algorithm = 'gzip'): void
    {
        if (! $this->exists($path)) {
            throw new FileNotFoundException($path);
        }

        $content = $this->get($path);
        $compressedPath = $path . '.' . $algorithm;

        $this->putCompressed($path, $content, $algorithm);
        $this->delete($path);

        // Komprimierte Datei zurück zum ursprünglichen Pfad verschieben
        $this->copy($compressedPath, $path);
        $this->delete($compressedPath);
    }

    public function decompress(string $path): void
    {
        $content = $this->getCompressed($path);

        // Entferne Komprimierungs-Extension
        $pathInfo = pathinfo($path);
        $algorithm = $pathInfo['extension'] ?? '';
        $decompressedPath = $pathInfo['dirname'] . '/' . $pathInfo['filename'];

        $this->put($decompressedPath, $content);
        $this->delete($path);
    }

    public function isCompressed(string $path): bool
    {
        if (! $this->exists($path)) {
            return false;
        }

        $pathInfo = pathinfo($path);
        $extension = $pathInfo['extension'] ?? '';

        return in_array($extension, ['gzip', 'gz', 'deflate', 'bzip2', 'bz2']);
    }

    public function getAvailableAlgorithms(): array
    {
        $algorithms = [];

        if (function_exists('gzencode')) {
            $algorithms[] = 'gzip';
        }

        if (function_exists('gzdeflate')) {
            $algorithms[] = 'deflate';
        }

        if (function_exists('bzcompress')) {
            $algorithms[] = 'bzip2';
        }

        return $algorithms;
    }
}
