<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Streaming\Topic;

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

    private StreamTopicRegistry $registry;
    private StreamTopicStore $store;

    private function __construct(private readonly string $basePath)
    {
        $this->registry = new StreamTopicRegistry();
        $this->store = new StreamTopicStore($basePath);
        $this->hydrate();
    }

    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 create(string $topic, int $priority = 0, int $partitions = 1, array $headers = []): StreamTopicMetadata
    {
        $record = $this->registry->create($topic, $priority, $partitions, $headers);
        $this->save();

        return $record;
    }

    public function pause(string $topic): bool
    {
        $ok = $this->registry->pause($topic);
        $this->save();

        return $ok;
    }

    public function resume(string $topic): bool
    {
        $ok = $this->registry->resume($topic);
        $this->save();

        return $ok;
    }

    public function archive(string $topic): bool
    {
        $ok = $this->registry->archive($topic);
        $this->save();

        return $ok;
    }

    public function hydrate(): void
    {
        $snapshot = $this->store->load();

        if ($snapshot->topics() !== [] || $snapshot->partitions() !== []) {
            $this->registry = StreamTopicRegistry::fromArray($snapshot->topics(), $snapshot->partitions());
        }
    }

    public function snapshot(): StreamTopicSnapshot
    {
        return new StreamTopicSnapshot(
            $this->registry->toArray(),
            $this->registry->partitionsToArray(),
            $this->registry->statistics(),
            date('c')
        );
    }

    public function save(): StreamTopicSnapshot
    {
        return $this->store->save($this->snapshot());
    }

    public function clear(): void
    {
        $this->registry = new StreamTopicRegistry();
        $this->store->reset();
    }

    public function registry(): StreamTopicRegistry { return $this->registry; }
    public function store(): StreamTopicStore { return $this->store; }

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

        return [
            'topics' => $snapshot->topics(),
            'partitions' => $snapshot->partitions(),
            '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;
    }
}
