<?php
declare(strict_types=1);

namespace Archive\StreamWrapper\Wrappers;

use App\Framework\HttpClient\HttpClient;
use App\Framework\StreamWrapper\Helper\StreamWrapperHelper;
use Archive\StreamWrapper\Context\StreamContext;
use Archive\StreamWrapper\StreamWrapperInterface;

/**
 * Stream-Wrapper für HTTP-Client-Operationen
 * Syntax: http-client://host/path
 */
class HttpStreamWrapper implements StreamWrapperInterface
{
    public $context;
    private string $content = '';
    private int $position = 0;
    private string $mode = 'r';
    private array $parsedUrl = [];
    private ?StreamContext $streamContext = null;

    private HttpClient $httpClient;
    private string $host;
    private string $path;
    private array $headers = [];
    private int $timeout = 30;
    private ?string $auth = null;

    public function stream_open(string $path, string $mode, int $options, ?string &$opened_path): bool
    {
        $this->streamContext = StreamWrapperHelper::initializeContext($this->context);
        $this->parsedUrl = StreamWrapperHelper::parseUrl($path);
        $this->mode = $mode;

        $this->host = $this->parsedUrl['host'];
        $this->path = '/' . ltrim($this->parsedUrl['path'], '/');

        // Optionen aus Context lesen
        if ($this->streamContext) {
            $this->headers = $this->streamContext->getOption('http-client', 'headers', []);
            $this->timeout = $this->streamContext->getOption('http-client', 'timeout', 30);
            $this->auth = $this->streamContext->getOption('http-client', 'auth');
        }

        // HTTP-Client initialisieren
        $this->httpClient = new HttpClient();

        // Bei Lese-Modi HTTP-Request ausführen
        if (str_contains($mode, 'r') || str_contains($mode, '+')) {
            $this->content = $this->loadContent($this->buildUrl());
        }

        return true;
    }

    public function stream_read(int $count): string|false
    {
        return StreamWrapperHelper::streamRead($this->content, $this->position, $count);
    }

    public function stream_write(string $data): int|false
    {
        return StreamWrapperHelper::streamWrite($this->content, $this->position, $data);
    }

    public function stream_tell(): int|false
    {
        return $this->position;
    }

    public function stream_eof(): bool
    {
        return $this->position >= strlen($this->content);
    }

    public function stream_seek(int $offset, int $whence = SEEK_SET): bool
    {
        return StreamWrapperHelper::streamSeek($this->content, $this->position, $offset, $whence);
    }

    public function stream_close(): void
    {
        // Bei Schreib-Modi POST/PUT-Request senden
        if (str_contains($this->mode, 'w') || str_contains($this->mode, 'a') || str_contains($this->mode, '+')) {
            $this->saveContent($this->buildUrl(), $this->content);
        }

        $this->content = '';
        $this->position = 0;
    }

    public function stream_stat(): array|false
    {
        return StreamWrapperHelper::streamStat($this->content);
    }

    public function url_stat(string $path, int $flags): array|false
    {
        return StreamWrapperHelper::createDefaultStat(strlen($this->content));
    }

    // Nicht unterstützte Operationen
    public function mkdir(string $path, int $mode, int $options): bool { return false; }
    public function rmdir(string $path, int $options): bool { return false; }
    public function dir_opendir(string $path, int $options): bool { return false; }
    public function dir_readdir(): string|false { return false; }
    public function dir_rewinddir(): bool { return false; }
    public function dir_closedir(): bool { return false; }
    public function rename(string $path_from, string $path_to): bool { return false; }
    public function unlink(string $path): bool { return false; }

    private function loadContent(string $url): string
    {
        $request = $this->httpClient->get($url);

        if ($this->auth) {
            $request->withHeader('Authorization', $this->auth);
        }

        foreach ($this->headers as $name => $value) {
            $request->withHeader($name, $value);
        }

        $response = $request->timeout($this->timeout)->send();

        return $response->body();
    }

    private function saveContent(string $url, string $content): bool
    {
        $request = $this->httpClient->post($url, $content);

        if ($this->auth) {
            $request->withHeader('Authorization', $this->auth);
        }

        foreach ($this->headers as $name => $value) {
            $request->withHeader($name, $value);
        }

        $response = $request->timeout($this->timeout)->send();

        return $response->successful();
    }

    private function buildUrl(): string
    {
        $scheme = 'https'; // Default zu HTTPS

        if ($this->streamContext) {
            $scheme = $this->streamContext->getOption('http-client', 'scheme', 'https');
        }

        $url = "{$scheme}://{$this->host}{$this->path}";

        if ($this->parsedUrl['query']) {
            $url .= '?' . $this->parsedUrl['query'];
        }

        return $url;
    }
}
