<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Distributed;

final class DistributedWorkerRegistry
{
    /** @var array<string, DistributedWorkerRecord> */
    private array $workers = [];

    public static function fromArray(array $items): self
    {
        $registry = new self();

        foreach ($items as $item) {
            if (is_array($item)) {
                $registry->register(DistributedWorkerRecord::fromArray($item));
            }
        }

        return $registry;
    }

    public function register(DistributedWorkerRecord $record): void
    {
        $this->workers[$record->nodeId() . ':' . $record->workerId()] = $record;
    }

    public function heartbeat(string $nodeId, string $workerId, string $status = DistributedWorkerRecord::IDLE, int $activeJobs = 0): bool
    {
        $key = $nodeId . ':' . $workerId;

        if (!isset($this->workers[$key])) {
            return false;
        }

        $this->workers[$key] = $this->workers[$key]->heartbeat($status, $activeJobs);

        return true;
    }

    public function all(): array
    {
        return array_values($this->workers);
    }

    public function count(): int
    {
        return count($this->workers);
    }

    public function statistics(): array
    {
        $stats = [
            'workers' => count($this->workers),
            'nodes' => 0,
            'idle' => 0,
            'busy' => 0,
            'offline' => 0,
            'capacity' => 0,
            'activeJobs' => 0,
            'availableCapacity' => 0,
        ];

        $nodes = [];

        foreach ($this->workers as $worker) {
            $nodes[$worker->nodeId()] = true;
            $data = $worker->toArray();

            $status = (string) ($data['status'] ?? DistributedWorkerRecord::IDLE);
            if (array_key_exists($status, $stats)) {
                $stats[$status]++;
            }

            $stats['capacity'] += (int) ($data['capacity'] ?? 0);
            $stats['activeJobs'] += (int) ($data['activeJobs'] ?? 0);
            $stats['availableCapacity'] += (int) ($data['availableCapacity'] ?? 0);
        }

        $stats['nodes'] = count($nodes);

        return $stats;
    }

    public function toArray(): array
    {
        return array_map(static fn (DistributedWorkerRecord $record): array => $record->toArray(), $this->all());
    }
}
