<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Sourcing\Verification;

use PpPhp\Core\Platform\Event\Sourcing\Aggregate\Validation\AggregateRepositoryVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Command\Validation\CommandBusVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Compaction\Validation\EventCompactionVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Domain\Validation\DomainEventDispatcherVerifier;
use PpPhp\Core\Platform\Event\Sourcing\EventStore\Validation\EventStoreVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Projection\Validation\ProjectionVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Query\Validation\QueryRuntimeVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Saga\Validation\SagaVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Snapshot\Validation\SnapshotVerifier;
use PpPhp\Core\Platform\Event\Sourcing\Versioning\Validation\EventVersioningVerifier;

final class EventSourcingRuntimeVerifier
{
    public function __construct(private readonly string $basePath) {}

    public function verify(): EventSourcingRuntimeReport
    {
        $checks = [];

        $checks[] = $this->runCheck('eventStore', fn (): array => (new EventStoreVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('aggregateRepository', fn (): array => (new AggregateRepositoryVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('snapshotRuntime', fn (): array => (new SnapshotVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('projectionRuntime', fn (): array => (new ProjectionVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('queryRuntime', fn (): array => (new QueryRuntimeVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('commandBus', fn (): array => (new CommandBusVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('domainEventDispatch', fn (): array => (new DomainEventDispatcherVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('sagaProcessManager', fn (): array => (new SagaVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('eventVersioning', fn (): array => (new EventVersioningVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('eventCompaction', fn (): array => (new EventCompactionVerifier())->verify($this->basePath));

        return EventSourcingRuntimeReport::fromChecks($checks);
    }

    private function runCheck(string $name, callable $callback): EventSourcingRuntimeCheck
    {
        try {
            $result = $callback();
            $ok = (bool) ($result['ok'] ?? false);
            $summary = (array) ($result['summary'] ?? []);

            return $ok
                ? EventSourcingRuntimeCheck::pass($name, $name . ' verified', $summary)
                : EventSourcingRuntimeCheck::fail($name, $name . ' failed', ['issues' => $result['issues'] ?? [], 'summary' => $summary]);
        } catch (\Throwable $exception) {
            return EventSourcingRuntimeCheck::fail($name, $exception->getMessage(), [
                'exception' => get_class($exception),
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
            ]);
        }
    }
}
