<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Worker\Monitoring;

final class WorkerHeartbeatManager
{
    private static ?self $instance = null;

    private WorkerHeartbeatCollection $collection;
    private WorkerHeartbeatStore $store;

    private function __construct(private readonly string $basePath)
    {
        $this->collection = new WorkerHeartbeatCollection();
        $this->store = new WorkerHeartbeatStore($basePath);
    }

    public static function instance(?string $basePath = null): self
    {
        if (self::$instance === null) {
            $basePath ??= self::detectBasePath();
            self::$instance = new self($basePath);
        }

        return self::$instance;
    }

    public static function resetInstance(?string $basePath = null): self
    {
        $basePath ??= self::detectBasePath();
        self::$instance = new self($basePath);
        return self::$instance;
    }

    public function record(string $workerId, string $status = 'idle', int $handled = 0, int $failed = 0, string $lastEvent = ''): WorkerHeartbeat
    {
        $heartbeat = WorkerHeartbeat::record($workerId, $status, $handled, $failed, $lastEvent);
        $this->collection->record($heartbeat);
        return $heartbeat;
    }

    public function collection(): WorkerHeartbeatCollection
    {
        if ($this->collection->count() === 0 && $this->store->exists()) {
            $this->hydrate();
        }

        return $this->collection;
    }

    public function store(): WorkerHeartbeatStore
    {
        return $this->store;
    }

    public function save(): WorkerHeartbeatSnapshot
    {
        return $this->store->save($this->collection);
    }

    public function load(): WorkerHeartbeatSnapshot
    {
        return $this->store->load();
    }

    public function hydrate(): void
    {
        $snapshot = $this->load();
        if ($snapshot->heartbeats() !== []) {
            $this->collection = WorkerHeartbeatCollection::fromArray($snapshot->heartbeats());
        }
    }

    public function clear(): void
    {
        $this->collection->clear();
        $this->store->reset();
    }

    public function summary(): array
    {
        $snapshot = $this->save();

        return [
            'heartbeats' => $snapshot->heartbeats(),
            'statistics' => $snapshot->statistics(),
            'persisted' => $this->store->exists(),
            'stateFile' => $this->store->stateFile(),
        ];
    }

    private static function detectBasePath(): string
    {
        $candidate = dirname(__DIR__, 5);
        $real = realpath($candidate);

        return $real !== false ? $real : $candidate;
    }
}
