<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Workflow\Verification;

use PpPhp\Core\Platform\Workflow\Validation\WorkflowVerifier;
use PpPhp\Core\Platform\Workflow\Engine\Validation\WorkflowEngineVerifier;
use PpPhp\Core\Platform\Workflow\HumanTask\Validation\HumanTaskVerifier;
use PpPhp\Core\Platform\Workflow\Timer\Validation\WorkflowTimerVerifier;
use PpPhp\Core\Platform\Workflow\Compensation\Validation\WorkflowCompensationVerifier;

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

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

        $checks[] = $this->runCheck('workflowRuntime', fn (): array => (new WorkflowVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('workflowEngine', fn (): array => (new WorkflowEngineVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('humanTaskRuntime', fn (): array => (new HumanTaskVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('timerRuntime', fn (): array => (new WorkflowTimerVerifier())->verify($this->basePath));
        $checks[] = $this->runCheck('compensationRuntime', fn (): array => (new WorkflowCompensationVerifier())->verify($this->basePath));

        return WorkflowRuntimeReport::fromChecks($checks);
    }

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

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