<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event;

use PpPhp\Core\Platform\Event\Contracts\EventInterface;

final class EventEnvelope
{
    private array $handledBy = [];
    private array $errors = [];

    public function __construct(
        private readonly EventInterface $event,
        private readonly string $id = '',
        private readonly string $dispatchedAt = ''
    ) {}

    public function event(): EventInterface
    {
        return $this->event;
    }

    public function id(): string
    {
        return $this->id !== '' ? $this->id : sha1($this->event->name() . '|' . $this->event->occurredAt() . '|' . spl_object_id($this));
    }

    public function dispatchedAt(): string
    {
        return $this->dispatchedAt !== '' ? $this->dispatchedAt : date('c');
    }

    public function markHandled(string $listener): void
    {
        $this->handledBy[] = $listener;
    }

    public function addError(string $listener, string $message): void
    {
        $this->errors[] = [
            'listener' => $listener,
            'message' => $message,
        ];
    }

    public function handledBy(): array
    {
        return $this->handledBy;
    }

    public function errors(): array
    {
        return $this->errors;
    }

    public function ok(): bool
    {
        return $this->errors === [];
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id(),
            'dispatchedAt' => $this->dispatchedAt(),
            'event' => method_exists($this->event, 'toArray') ? $this->event->toArray() : [
                'name' => $this->event->name(),
                'payload' => $this->event->payload(),
                'metadata' => $this->event->metadata(),
                'occurredAt' => $this->event->occurredAt(),
            ],
            'handledBy' => $this->handledBy,
            'errors' => $this->errors,
            'ok' => $this->ok(),
        ];
    }
}
