<?php

declare(strict_types=1);

namespace PhpWA\Crypto\Signal;

use InvalidArgumentException;

final class SenderKeyState
{
    public const MAX_MESSAGE_KEYS = 2000;
    /** @var int */ private $keyId;
    /** @var SenderChainKey */ private $chain;
    /** @var string */ private $signingPublic;
    /** @var string|null */ private $signingPrivate;
    /** @var list<SenderMessageKey> */ private $messageKeys;

    /** @param list<SenderMessageKey> $messageKeys */
    public function __construct(int $keyId, SenderChainKey $chain, string $signingPublic, ?string $signingPrivate = null, array $messageKeys = [])
    {
        if ($keyId < 0 || $keyId > 0x7fffffff || ($signingPrivate !== null && strlen($signingPrivate) !== 32) || count($messageKeys) > self::MAX_MESSAGE_KEYS) { throw new InvalidArgumentException('Sender key state is invalid.'); }
        SignalCurve::assertPublicKey($signingPublic);
        if ($signingPrivate !== null) { new SignalKeyPair($signingPublic, $signingPrivate); }
        foreach ($messageKeys as $key) { if (!$key instanceof SenderMessageKey) { throw new InvalidArgumentException('Sender message-key cache is invalid.'); } }
        $this->keyId = $keyId; $this->chain = $chain; $this->signingPublic = $signingPublic; $this->signingPrivate = $signingPrivate; $this->messageKeys = array_values($messageKeys);
    }
    public function keyId(): int { return $this->keyId; }
    public function chain(): SenderChainKey { return $this->chain; }
    public function setChain(SenderChainKey $chain): void { $this->chain = $chain; }
    public function signingPublic(): string { return $this->signingPublic; }
    public function signingPrivate(): ?string { return $this->signingPrivate; }
    /** @return list<SenderMessageKey> */ public function messageKeys(): array { return $this->messageKeys; }
    public function addMessageKey(SenderMessageKey $key): void { $this->messageKeys[] = $key; if (count($this->messageKeys) > self::MAX_MESSAGE_KEYS) { array_shift($this->messageKeys); } }
    public function removeMessageKey(int $iteration): ?SenderMessageKey { foreach ($this->messageKeys as $index => $key) { if ($key->iteration() === $iteration) { array_splice($this->messageKeys, $index, 1); return $key; } } return null; }
}
