<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Rules\Repository;

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

    /** @var array<string, RuleRepositoryEntry> */
    private array $entries = [];
    private RuleRepositoryStore $store;

    private function __construct(private readonly string $basePath)
    {
        $this->store = new RuleRepositoryStore($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 register(RuleRepositoryEntry $entry): RuleRepositoryEntry
    {
        $this->entries[$entry->entryId()] = $entry;
        $this->save();
        return $entry;
    }

    public function deactivate(string $entryId): bool
    {
        $entry = $this->entries[$entryId] ?? null;
        if ($entry === null) {
            return false;
        }

        $this->entries[$entryId] = $entry->deactivate();
        $this->save();
        return true;
    }

    public function registry(): RuleRegistry
    {
        return new RuleRegistry(array_values($this->entries));
    }

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

        foreach ($snapshot->entries() as $entry) {
            if (is_array($entry)) {
                $e = RuleRepositoryEntry::fromArray($entry);
                $this->entries[$e->entryId()] = $e;
            }
        }
    }

    public function snapshot(): RuleRepositorySnapshot
    {
        $entries = array_map(static fn (RuleRepositoryEntry $entry): array => $entry->toArray(), array_values($this->entries));

        return new RuleRepositorySnapshot($entries, RuleRepositoryStatistics::from($entries), date('c'));
    }

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

    public function clear(): void
    {
        $this->entries = [];
        $this->store->reset();
    }

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

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

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

    private static function detectBasePath(): string
    {
        $candidate = dirname(__DIR__, 4);
        $real = realpath($candidate);
        return $real !== false ? $real : $candidate;
    }
}
