<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Worker;

use PpPhp\Core\Platform\Event\Queue\DeferredEvent;
use PpPhp\Core\Platform\Event\Worker\Contracts\WorkerInterface;
use PpPhp\Core\Platform\Event\Worker\Contracts\WorkerRuntimeInterface;

final class WorkerRuntime implements WorkerRuntimeInterface
{
    private WorkerRegistry $registry;
    private WorkerLifecycle $lifecycle;
    private WorkerStatistics $statistics;

    public function __construct()
    {
        $this->registry = new WorkerRegistry();
        $this->lifecycle = new WorkerLifecycle();
        $this->statistics = new WorkerStatistics();
    }

    public function register(WorkerInterface $worker): void
    {
        $this->registry->register($worker);
        $this->lifecycle->record($worker->id(), 'registered');
    }

    public function workers(): WorkerRegistry
    {
        return $this->registry;
    }

    public function startAll(): void
    {
        foreach ($this->registry->all() as $worker) {
            $worker->start();
            $this->lifecycle->record($worker->id(), 'started');
        }
    }

    public function stopAll(): void
    {
        foreach ($this->registry->all() as $worker) {
            $worker->stop();
            $this->lifecycle->record($worker->id(), 'stopped');
        }
    }

    public function handle(DeferredEvent $event, ?callable $handler = null): WorkerResult
    {
        $worker = $this->registry->all()[0] ?? null;

        if ($worker === null) {
            $worker = new DispatcherWorkerAdapter('worker_default');
            $this->register($worker);
        }

        $result = $worker->handle($event, $handler);
        $this->statistics = $this->statistics->recordResult($result);
        $this->lifecycle->record($worker->id(), $result->ok() ? 'handled' : 'failed');

        return $result;
    }

    public function statistics(): WorkerStatistics
    {
        $stats = new WorkerStatistics();

        foreach ($this->registry->all() as $worker) {
            $stats = $stats->recordWorker($worker->status()->state());
        }

        foreach (($this->statistics->toArray()) as $key => $value) {
            // preserve handled/failed via reconstruction below
        }

        $current = $stats->toArray();
        $runtime = $this->statistics->toArray();

        return new WorkerStatistics(
            $current['workers'] ?? 0,
            $current['running'] ?? 0,
            $current['idle'] ?? 0,
            $current['stopped'] ?? 0,
            $runtime['handled'] ?? 0,
            $runtime['failed'] ?? 0
        );
    }

    public function lifecycle(): WorkerLifecycle
    {
        return $this->lifecycle;
    }

    public function summary(): array
    {
        return [
            'workers' => $this->registry->toArray(),
            'statistics' => $this->statistics()->toArray(),
            'lifecycle' => $this->lifecycle->all(),
        ];
    }
}
