<?php

namespace apexl\Io\includes;

use DI\Container;

/**
 * Relatively crude hook system, will need to be improved
 * Class Hook
 * @package apexl\Io\includes
 */
final class HookManager
{

    //an array of callables, keyed by name
    protected array $registeredCallbacks;
    protected bool $disabled = false;

    public function __construct(private Container $container) {}

    public function disable(): void
    {
        $this->disabled = true;
    }

    public function enable(): void
    {
        $this->disabled = false;
    }

    public function processHook(string $name, mixed $input = null, ...$args): mixed
    {
        $output = $input;

        if ($this->canProcess($name)) {
            foreach ($this->registeredCallbacks[$name] as $callback) {
                $callable = $this->toCallable($callback);
                if ($result = $this->container->call($callable, [$output, ...$args])) {
                    $output = $result;
                }
            }
        }

        return $output;
    }

    private function canProcess(string $name): bool
    {
        return (!$this->isDisabled() && $this->hasCallback($name));
    }

    private function isDisabled(): bool
    {
        return $this->disabled;
    }

    private function hasCallback(string $name): bool
    {
        return isset($this->registeredCallbacks[$name]);
    }

    private function toCallable($callback): callable
    {
        if (is_callable($callback)) {
            return $callback;
        }

        // If the callback is not callable, we will assume that is declared in the 'old' manner
        // of `class:method`, where `method` is a public method of `class`.
        trigger_error(
            'Calling hooks with Class:method is deprecated; Use invokable hooks extending AbstractHook',
            E_USER_DEPRECATED
        );

        return explode(':', $callback);
    }

    public function registerCallback(string $name, $callback): void
    {
        $this->registeredCallbacks[$name][] = $callback;
    }

}

