<?php
declare(strict_types=1);

namespace FreshCloud\Mail\BaseStreamWrappers;

final class StringStream implements StreamWrapperInterface
{
    private string $buffer;
    private int $position = 0;
    private bool $closed = false;

    public function __construct(string $initial = '')
    {
        $this->buffer = $initial;
    }

    public function open(string $path, string $mode): bool
    {
        $this->closed = false;
        if (str_contains($mode, 'w')) {
            $this->buffer = '';
            $this->position = 0;
        }
        return true;
    }

    public function read(int $length): string
    {
        if ($this->closed) {
            throw new \RuntimeException('Stream is closed');
        }
        $result = substr($this->buffer, $this->position, $length);
        $this->position += strlen($result);
        return $result;
    }

    public function write(string $data): int
    {
        if ($this->closed) {
            throw new \RuntimeException('Stream is closed');
        }
        $remainingLength = strlen($data);
        $this->buffer .= $data;
        // Don't advance position - write appends, position stays for read
        return $remainingLength;
    }

    public function close(): void
    {
        $this->closed = true;
    }

    public function tell(): int
    {
        if ($this->closed) {
            throw new \RuntimeException('Stream is closed');
        }
        return $this->position;
    }

    public function seek(int $offset, int $whence = SEEK_SET): bool
    {
        if ($this->closed) {
            throw new \RuntimeException('Stream is closed');
        }
        $newPosition = match ($whence) {
            SEEK_SET => $offset,
            SEEK_CUR => $this->position + $offset,
            SEEK_END => strlen($this->buffer) + $offset,
            default => false,
        };
        if ($newPosition === false || $newPosition < 0 || $newPosition > strlen($this->buffer)) {
            return false;
        }
        $this->position = $newPosition;
        return true;
    }

    public function eof(): bool
    {
        if ($this->closed) {
            return true;
        }
        return $this->position >= strlen($this->buffer);
    }
}