<?php
declare(strict_types=1);

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

final class ProjectionReadModel
{
    public function __construct(
        private readonly string $projectionId,
        private readonly array $rows = [],
        private readonly string $updatedAt = ''
    ) {}

    public static function fromArray(array $data): self
    {
        return new self(
            (string) ($data['projectionId'] ?? ''),
            (array) ($data['rows'] ?? []),
            (string) ($data['updatedAt'] ?? '')
        );
    }

    public function projectionId(): string { return $this->projectionId; }
    public function rows(): array { return $this->rows; }
    public function count(): int { return count($this->rows); }

    public function apply(array $event): self
    {
        $aggregateId = (string) ($event['aggregateId'] ?? '');
        if ($aggregateId === '') {
            return $this;
        }

        $rows = $this->rows;
        $current = (array) ($rows[$aggregateId] ?? []);

        $rows[$aggregateId] = array_replace_recursive($current, [
            'aggregateId' => $aggregateId,
            'aggregateType' => (string) ($event['aggregateType'] ?? ''),
            'version' => (int) ($event['aggregateVersion'] ?? 0),
            'lastEventType' => (string) ($event['eventType'] ?? ''),
            'lastSequence' => (int) ($event['sequence'] ?? 0),
            'state' => array_replace_recursive((array) ($current['state'] ?? []), (array) ($event['payload'] ?? [])),
            'updatedAt' => date('c'),
        ]);

        return new self($this->projectionId, $rows, date('c'));
    }

    public function clear(): self
    {
        return new self($this->projectionId, [], date('c'));
    }

    public function toArray(): array
    {
        return [
            'projectionId' => $this->projectionId,
            'rows' => $this->rows,
            'updatedAt' => $this->updatedAt !== '' ? $this->updatedAt : date('c'),
        ];
    }
}
