<?php

declare(strict_types=1);

namespace PhpWA\Transport;

use InvalidArgumentException;
use PhpWA\Exception\ProtocolException;

final class FrameDecoder
{
    /** @var string */ private $buffer = '';
    /** @var int */ private $maxFrameLength;
    /** @var int */ private $maxBufferedBytes;

    public function __construct(int $maxFrameLength = FrameCodec::MAX_WIRE_LENGTH, ?int $maxBufferedBytes = null)
    {
        if ($maxFrameLength < 0 || $maxFrameLength > FrameCodec::MAX_WIRE_LENGTH) {
            throw new InvalidArgumentException('Invalid WhatsApp frame length limit.');
        }
        $this->maxFrameLength = $maxFrameLength;
        $this->maxBufferedBytes = $maxBufferedBytes ?? min(PHP_INT_MAX, max(3, $maxFrameLength + 3));
        if ($this->maxBufferedBytes < 3 || $this->maxBufferedBytes < $maxFrameLength + 3) {
            throw new InvalidArgumentException('Buffered byte limit must fit one complete frame.');
        }
    }

    /** @return list<string> */
    public function feed(string $bytes): array
    {
        if (strlen($this->buffer) + strlen($bytes) > $this->maxBufferedBytes) {
            throw new ProtocolException('Buffered WhatsApp framing data exceeds configured limit.');
        }
        $this->buffer .= $bytes;
        $frames = [];
        while (strlen($this->buffer) >= 3) {
            $length = (ord($this->buffer[0]) << 16) | (ord($this->buffer[1]) << 8) | ord($this->buffer[2]);
            if ($length > $this->maxFrameLength) {
                throw new ProtocolException('Incoming WhatsApp frame exceeds configured limit.');
            }
            if (strlen($this->buffer) < $length + 3) {
                break;
            }
            $frames[] = substr($this->buffer, 3, $length);
            $this->buffer = substr($this->buffer, $length + 3);
        }
        return $frames;
    }

    public function pendingBytes(): int { return strlen($this->buffer); }
    public function reset(): void { $this->buffer = ''; }
}
