<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Streaming\Subscriber;

final class StreamSubscriberCollection
{
    /** @var array<string, StreamSubscriber> */
    private array $subscribers = [];

    public static function fromArray(array $items): self
    {
        $collection = new self();

        foreach ($items as $item) {
            if (is_array($item)) {
                $subscriber = StreamSubscriber::fromArray($item);
                $collection->subscribers[$subscriber->subscriberId()] = $subscriber;
            }
        }

        return $collection;
    }

    public function register(string $subscriberId, string $topic): StreamSubscriber
    {
        if (!isset($this->subscribers[$subscriberId])) {
            $this->subscribers[$subscriberId] = StreamSubscriber::register($subscriberId, $topic);
        }

        return $this->subscribers[$subscriberId];
    }

    public function put(StreamSubscriber $subscriber): void
    {
        $this->subscribers[$subscriber->subscriberId()] = $subscriber;
    }

    public function get(string $subscriberId): ?StreamSubscriber
    {
        return $this->subscribers[$subscriberId] ?? null;
    }

    public function receive(string $subscriberId, string $messageId): bool
    {
        if (!isset($this->subscribers[$subscriberId]) || !$this->subscribers[$subscriberId]->active()) {
            return false;
        }

        $this->subscribers[$subscriberId] = $this->subscribers[$subscriberId]->receive($messageId);

        return true;
    }

    public function acknowledge(string $subscriberId, ?string $messageId = null): bool
    {
        if (!isset($this->subscribers[$subscriberId])) {
            return false;
        }

        $this->subscribers[$subscriberId] = $this->subscribers[$subscriberId]->acknowledge($messageId);

        return true;
    }

    public function fail(string $subscriberId, ?string $messageId = null): bool
    {
        if (!isset($this->subscribers[$subscriberId])) {
            return false;
        }

        $this->subscribers[$subscriberId] = $this->subscribers[$subscriberId]->fail($messageId);

        return true;
    }

    public function pause(string $subscriberId): bool
    {
        if (!isset($this->subscribers[$subscriberId])) {
            return false;
        }

        $this->subscribers[$subscriberId] = $this->subscribers[$subscriberId]->pause();

        return true;
    }

    public function resume(string $subscriberId): bool
    {
        if (!isset($this->subscribers[$subscriberId])) {
            return false;
        }

        $this->subscribers[$subscriberId] = $this->subscribers[$subscriberId]->resume();

        return true;
    }

    public function all(): array
    {
        return array_values($this->subscribers);
    }

    public function byTopic(string $topic): array
    {
        return array_values(array_filter($this->subscribers, static fn (StreamSubscriber $subscriber): bool => $subscriber->topic() === $topic));
    }

    public function count(): int
    {
        return count($this->subscribers);
    }

    public function toArray(): array
    {
        return array_map(static fn (StreamSubscriber $subscriber): array => $subscriber->toArray(), $this->all());
    }
}
