<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Queue;

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

final class DeferredEvent
{
    public function __construct(
        private readonly string $id,
        private readonly string $eventName,
        private readonly array $payload = [],
        private readonly array $metadata = [],
        private readonly string $state = QueueState::PENDING,
        private readonly string $queuedAt = '',
        private readonly int $attempts = 0
    ) {}

    public static function fromEvent(EventInterface|string $event, array $payload = [], array $metadata = []): self
    {
        if ($event instanceof EventInterface) {
            return new self(
                QueueIdentifier::next(),
                $event->name(),
                $event->payload(),
                $event->metadata() + $metadata
            );
        }

        return new self(QueueIdentifier::next(), $event, $payload, $metadata);
    }

    public static function fromArray(array $data): self
    {
        return new self(
            (string) ($data['id'] ?? QueueIdentifier::next()),
            (string) ($data['eventName'] ?? ''),
            (array) ($data['payload'] ?? []),
            (array) ($data['metadata'] ?? []),
            (string) ($data['state'] ?? QueueState::PENDING),
            (string) ($data['queuedAt'] ?? ''),
            (int) ($data['attempts'] ?? 0)
        );
    }

    public function id(): string { return $this->id; }
    public function eventName(): string { return $this->eventName; }
    public function payload(): array { return $this->payload; }
    public function metadata(): array { return $this->metadata; }
    public function state(): string { return $this->state; }
    public function attempts(): int { return $this->attempts; }
    public function queuedAt(): string { return $this->queuedAt !== '' ? $this->queuedAt : date('c'); }

    public function event(): Event
    {
        return new Event($this->eventName, $this->payload, $this->metadata);
    }

    public function withState(string $state): self
    {
        return new self($this->id, $this->eventName, $this->payload, $this->metadata, $state, $this->queuedAt(), $this->attempts);
    }

    public function incrementAttempts(): self
    {
        return new self($this->id, $this->eventName, $this->payload, $this->metadata, $this->state, $this->queuedAt(), $this->attempts + 1);
    }

    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'eventName' => $this->eventName,
            'payload' => $this->payload,
            'metadata' => $this->metadata,
            'state' => $this->state,
            'queuedAt' => $this->queuedAt(),
            'attempts' => $this->attempts,
        ];
    }
}
