<?php
declare(strict_types=1);

namespace Archive\StreamWrapper\Filter\Filters;

use Archive\StreamWrapper\Filter\StreamFilterInterface;

/**
 * Stream-Filter für Access-Logging
 */
class AccessLogFilter extends \php_user_filter implements StreamFilterInterface
{
    private string $filterName = 'log.access';
    private array $supportedModes = ['read', 'write'];
    private array $params = [];

    private string $logFile = '';
    private bool $logReadAccess = true;
    private bool $logWriteAccess = true;

    public function onCreate(): bool
    {
        // Parameter aus dem Stream-Context extrahieren
        if (isset($this->params)) {
            $this->params = $this->params;
        }

        $this->logFile = $this->getParam('log_file', sys_get_temp_dir() . '/stream_access.log');
        $this->logReadAccess = $this->getParam('log_read', true);
        $this->logWriteAccess = $this->getParam('log_write', true);

        return true;
    }

    public function onClose(): void
    {
        // Cleanup falls nötig
    }

    public function getFilterName(): string
    {
        return $this->filterName;
    }

    public function getSupportedModes(): array
    {
        return $this->supportedModes;
    }

    public function filter($in, $out, &$consumed, bool $closing): int
    {
        $data = $this->readFromBrigade($in);
        $consumed = strlen($data);

        if (!empty($data)) {
            // Access-Log schreiben
            $this->logAccess($data);

            // Daten unverändert durchreichen
            $this->writeToBrigade($out, $data);
        }

        return PSFS_PASS_ON;
    }

    private function logAccess(string $data): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $size = strlen($data);
        $mode = $this->filtername; // read oder write

        $logEntry = "[{$timestamp}] {$mode} - {$size} bytes\n";

        file_put_contents($this->logFile, $logEntry, FILE_APPEND | LOCK_EX);
    }

    /**
     * Hilfsmethode zum Lesen von Daten aus der Input-Brigade
     */
    private function readFromBrigade($brigade): string
    {
        $data = '';
        while ($bucket = stream_bucket_make_writeable($brigade)) {
            $data .= $bucket->data;
        }
        return $data;
    }

    /**
     * Hilfsmethode zum Schreiben von Daten in die Output-Brigade
     */
    private function writeToBrigade($brigade, string $data): void
    {
        if (!empty($data)) {
            $bucket = stream_bucket_new($this->stream, $data);
            stream_bucket_append($brigade, $bucket);
        }
    }

    /**
     * Gibt einen Parameter zurück
     */
    private function getParam(string $key, $default = null)
    {
        return $this->params[$key] ?? $default;
    }
}
