<?php

declare(strict_types=1);

namespace Core;

use Exception;
use ReflectionFunction;
use ReflectionMethod;

class App
{
    protected array $bindings = [];

    public function bind(string $name, mixed $value): void
    {
        $this->bindings[$name] = $value;
    }

    public function get(string $name): mixed
    {
        return $this->bindings[$name] ?? null;
    }

    public function call(callable|array|string $handler, array $parameters = []): mixed
    {
        if (is_array($handler)) {
            return $this->callMethod($handler, $parameters);
        }

        if (is_callable($handler)) {
            return $this->callFunction($handler, $parameters);
        }

        throw new Exception('Invalid handler.');
    }

    protected function callFunction(callable $handler, array $parameters): mixed
    {
        $reflection = new ReflectionFunction($handler);

        return $reflection->invokeArgs(array_values($parameters));
    }

    protected function callMethod(array $handler, array $parameters): mixed
    {
        [$class, $method] = $handler;

        if (is_string($class)) {
            $class = new $class();
        }

        $reflection = new ReflectionMethod($class, $method);

        return $reflection->invokeArgs($class, array_values($parameters));
    }
}
