<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Worker;

use Throwable;
use PpPhp\Core\Platform\Event\Dispatcher\Execution\DispatcherWorker;
use PpPhp\Core\Platform\Event\Queue\DeferredEvent;
use PpPhp\Core\Platform\Event\Worker\Contracts\WorkerInterface;

final class DispatcherWorkerAdapter implements WorkerInterface
{
    private WorkerStatus $status;
    private int $handled = 0;
    private int $failed = 0;

    public function __construct(
        private readonly string $workerId = '',
        private readonly string $workerName = 'dispatcher-worker',
        private readonly DispatcherWorker $dispatcherWorker = new DispatcherWorker()
    ) {
        $this->status = WorkerStatus::idle();
    }

    public function id(): string
    {
        return $this->workerId !== '' ? $this->workerId : WorkerIdentifier::next();
    }

    public function name(): string
    {
        return $this->workerName;
    }

    public function status(): WorkerStatus
    {
        return $this->status;
    }

    public function start(): void
    {
        $this->status = WorkerStatus::running();
    }

    public function stop(): void
    {
        $this->status = WorkerStatus::stopped();
    }

    public function handle(DeferredEvent $event, ?callable $handler = null): WorkerResult
    {
        $this->start();

        try {
            $result = $this->dispatcherWorker->handle($event, $handler);
            $this->handled++;
            $this->status = WorkerStatus::idle();

            return $result->ok()
                ? WorkerResult::success($this->id(), $event->eventName())
                : WorkerResult::failed($this->id(), $event->eventName(), 'dispatcher result failed');
        } catch (Throwable $e) {
            $this->failed++;
            $this->status = WorkerStatus::failed();

            return WorkerResult::failed($this->id(), $event->eventName(), $e->getMessage());
        }
    }

    public function heartbeat(): array
    {
        return [
            'workerId' => $this->id(),
            'status' => $this->status->state(),
            'handled' => $this->handled,
            'failed' => $this->failed,
            'timestamp' => date('c'),
        ];
    }
}
