<?php
declare(strict_types=1);

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

final class WorkerHeartbeatStore
{
    public const CACHE_DIR = 'storage/cache/events/workers';
    public const STATE_FILE = 'worker-heartbeats.json';

    public function __construct(
        private readonly string $basePath,
        private readonly WorkerHeartbeatSerializer $serializer = new WorkerHeartbeatSerializer()
    ) {}

    public function stateFile(): string
    {
        return rtrim($this->basePath, DIRECTORY_SEPARATOR) . '/' . self::CACHE_DIR . '/' . self::STATE_FILE;
    }

    public function save(WorkerHeartbeatCollection $collection): WorkerHeartbeatSnapshot
    {
        $snapshot = new WorkerHeartbeatSnapshot(
            $collection->toArray(),
            $this->statistics($collection),
            date('c')
        );

        $file = $this->stateFile();
        if (!is_dir(dirname($file))) {
            mkdir(dirname($file), 0775, true);
        }

        file_put_contents($file, $this->serializer->encode($snapshot));

        return $snapshot;
    }

    public function load(): WorkerHeartbeatSnapshot
    {
        $file = $this->stateFile();

        if (!is_file($file)) {
            return new WorkerHeartbeatSnapshot();
        }

        return $this->serializer->decode((string) file_get_contents($file));
    }

    public function reset(): void
    {
        $file = $this->stateFile();
        if (is_file($file)) {
            unlink($file);
        }
    }

    public function exists(): bool
    {
        return is_file($this->stateFile());
    }

    private function statistics(WorkerHeartbeatCollection $collection): array
    {
        $items = $collection->toArray();
        $running = 0;
        $idle = 0;
        $failed = 0;
        $handled = 0;

        foreach ($items as $heartbeat) {
            $status = (string) ($heartbeat['status'] ?? 'idle');
            $running += $status === 'running' ? 1 : 0;
            $idle += $status === 'idle' ? 1 : 0;
            $failed += $status === 'failed' ? 1 : 0;
            $handled += (int) ($heartbeat['handled'] ?? 0);
        }

        return [
            'workers' => count($items),
            'running' => $running,
            'idle' => $idle,
            'failed' => $failed,
            'handled' => $handled,
        ];
    }
}
