<?php

declare(strict_types=1);

namespace PhpWA\Client;

use PhpWA\Exception\ProtocolException;
use PhpWA\Protocol\Binary\BinaryNode;
use PhpWA\Runtime\Deadline;

final class BlockingQueryExecutor implements QueryExecutorInterface
{
    /** @var ProtocolConnectionInterface */ private $connection;
    /** @var callable|null */ private $unsolicited;
    /** @var int */ private $maximumInterleavedNodes;
    public function __construct(ProtocolConnectionInterface $connection, ?callable $unsolicited = null, int $maximumInterleavedNodes = 1000)
    {
        if ($maximumInterleavedNodes < 1 || $maximumInterleavedNodes > 10000) { throw new \InvalidArgumentException('Query interleave bound is invalid.'); }
        $this->connection = $connection; $this->unsolicited = $unsolicited; $this->maximumInterleavedNodes = $maximumInterleavedNodes;
    }
    public function query(BinaryNode $request, Deadline $deadline): BinaryNode
    {
        $id = $request->attribute('id');
        if ($request->tag() !== 'iq' || !is_string($id) || $id === '' || strlen($id) > 256) {
            throw new ProtocolException('Blocking query requires an IQ stanza with a bounded ID.');
        }
        $this->connection->send($request, $deadline);
        for ($seen = 0; $seen < $this->maximumInterleavedNodes; $seen++) {
            $node = $this->connection->receive($deadline);
            if ($node->attribute('id') === $id) {
                if ($node->tag() !== 'iq' || $node->attribute('type') === 'error') {
                    throw new ProtocolException('WhatsApp IQ query returned an error response.');
                }
                return $node;
            }
            if ($this->unsolicited === null) {
                throw new ProtocolException('An unsolicited stanza arrived without a configured router.');
            }
            ($this->unsolicited)($node, $deadline);
        }
        throw new ProtocolException('Too many interleaved stanzas while waiting for an IQ response.');
    }
}
