<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Distributed\Failover;

final class DistributedNodeHealthRecord
{
    public function __construct(
        private readonly string $nodeId,
        private readonly string $status = DistributedNodeStatus::HEALTHY,
        private readonly int $workers = 0,
        private readonly int $activeJobs = 0,
        private readonly int $capacity = 0,
        private readonly int $ageSeconds = 0,
        private readonly string $reason = '',
        private readonly string $checkedAt = ''
    ) {}

    public static function fromWorkers(string $nodeId, array $workers, DistributedFailoverPolicy $policy): self
    {
        $lastSeen = 0;
        $activeJobs = 0;
        $capacity = 0;

        foreach ($workers as $worker) {
            $seen = strtotime((string) ($worker['lastSeenAt'] ?? ''));
            if ($seen > $lastSeen) {
                $lastSeen = $seen;
            }

            $activeJobs += (int) ($worker['activeJobs'] ?? 0);
            $capacity += (int) ($worker['capacity'] ?? 0);
        }

        $age = $lastSeen > 0 ? max(0, time() - $lastSeen) : PHP_INT_MAX;
        $status = $age > $policy->nodeTimeoutSeconds() ? DistributedNodeStatus::FAILED : DistributedNodeStatus::HEALTHY;
        $reason = $status === DistributedNodeStatus::FAILED ? 'node heartbeat timeout exceeded' : 'node healthy';

        return new self($nodeId, $status, count($workers), $activeJobs, $capacity, $age, $reason, date('c'));
    }

    public static function fromArray(array $data): self
    {
        return new self(
            (string) ($data['nodeId'] ?? ''),
            (string) ($data['status'] ?? DistributedNodeStatus::HEALTHY),
            (int) ($data['workers'] ?? 0),
            (int) ($data['activeJobs'] ?? 0),
            (int) ($data['capacity'] ?? 0),
            (int) ($data['ageSeconds'] ?? 0),
            (string) ($data['reason'] ?? ''),
            (string) ($data['checkedAt'] ?? '')
        );
    }

    public function nodeId(): string { return $this->nodeId; }
    public function status(): string { return $this->status; }
    public function failed(): bool { return $this->status === DistributedNodeStatus::FAILED; }

    public function toArray(): array
    {
        return [
            'nodeId' => $this->nodeId,
            'status' => $this->status,
            'failed' => $this->failed(),
            'workers' => $this->workers,
            'activeJobs' => $this->activeJobs,
            'capacity' => $this->capacity,
            'ageSeconds' => $this->ageSeconds,
            'reason' => $this->reason,
            'checkedAt' => $this->checkedAt !== '' ? $this->checkedAt : date('c'),
        ];
    }
}
