<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Sourcing\Snapshot;

final class SnapshotCollection
{
    /** @var array<string, AggregateSnapshot> */
    private array $snapshots = [];

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

        foreach ($items as $item) {
            if (is_array($item)) {
                $snapshot = AggregateSnapshot::fromArray($item);
                $collection->put($snapshot);
            }
        }

        return $collection;
    }

    public function put(AggregateSnapshot $snapshot): void
    {
        $this->snapshots[$snapshot->aggregateId() . ':' . $snapshot->version()] = $snapshot;
    }

    public function latest(string $aggregateId): ?AggregateSnapshot
    {
        $latest = null;

        foreach ($this->snapshots as $snapshot) {
            if ($snapshot->aggregateId() !== $aggregateId) {
                continue;
            }

            if ($latest === null || $snapshot->version() > $latest->version()) {
                $latest = $snapshot;
            }
        }

        return $latest;
    }

    public function byAggregate(string $aggregateId): array
    {
        $items = array_values(array_filter(
            $this->snapshots,
            static fn (AggregateSnapshot $snapshot): bool => $snapshot->aggregateId() === $aggregateId
        ));

        usort($items, static fn (AggregateSnapshot $a, AggregateSnapshot $b): int => $a->version() <=> $b->version());

        return $items;
    }

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

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

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