<?php

declare(strict_types=1);

namespace PhpWA\Client;

use PhpWA\Exception\ProtocolException;
use PhpWA\Exception\OutgoingMessageRejectedException;
use PhpWA\Protocol\Binary\BinaryNode;

final class OutgoingAckProcessor
{
    /** @var string */ private $accountId;
    /** @var OutgoingStanzaStore */ private $outgoing;

    public function __construct(string $accountId, OutgoingStanzaStore $outgoing)
    {
        if ($accountId === '' || strlen($accountId) > 512 || preg_match('//u', $accountId) !== 1) {
            throw new \InvalidArgumentException('Outgoing ACK account ID is invalid.');
        }
        $this->accountId = $accountId; $this->outgoing = $outgoing;
    }

    /** Returns false for stanzas outside the outgoing message ACK contract. */
    public function process(BinaryNode $node): bool
    {
        if ($node->tag() !== 'ack' || $node->attribute('class') !== 'message') { return false; }
        $id = $node->attribute('id');
        if ($id === null || preg_match('/\A[A-Za-z0-9._:-]{1,256}\z/D', $id) !== 1) {
            throw new ProtocolException('Outgoing message ACK has an invalid ID.');
        }
        $error = $node->attribute('error');
        if ($error !== null && $error !== '0') {
            // ACK error — единственная безопасная диагностическая деталь этого
            // протокольного отказа. Не добавляем в исключение payload или JID.
            $this->outgoing->reject($this->accountId, $id);
            throw new OutgoingMessageRejectedException($error);
        }
        $this->outgoing->complete($this->accountId, $id);
        return true;
    }
}
