<?php

declare(strict_types=1);

namespace Apexl\Io\User\Middleware;

use Apexl\Io\Routing\DeclaresRoutePermission;
use Apexl\Io\User\Interfaces\PermissionInterface;
use Apexl\Io\User\Services\PermissionGate;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * What a route requires, attached to the route that requires it.
 *
 * `$app->get(...)->add(new RoutePermissionMiddleware(Colors::READ__ALL))` says it once and
 * enforces it: there is no registry to keep in step, and no route argument — Slim deprecated
 * those in 4.14.1, they hold strings only (which is why permissions used to be serialized and
 * unserialized on every request), and they are merged into `getArguments()`, where
 * io-validation spreads them into the data a request is validated against.
 *
 * It is still readable, because IoRoute records what is attached to it:
 *
 *     $route->getMiddleware()->find(RoutePermissionMiddleware::class)?->getPermission()
 *
 * which is how the menu declines to offer a page the caller would be refused, and how
 * `routes:dump` prints the permission column.
 *
 * Holds the permission and nothing else. The services needed to judge it are resolved when
 * the route actually runs — once per request, on the one route that matched, rather than
 * three hundred times at registration.
 */
final readonly class RoutePermissionMiddleware implements DeclaresRoutePermission
{
    /**
     * @param PermissionInterface|PermissionInterface[] $permission
     */
    public function __construct(private PermissionInterface|array $permission) {}

    /**
     * @return PermissionInterface|PermissionInterface[]
     */
    public function getPermission(): PermissionInterface|array
    {
        return $this->permission;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        return \Apexl\Io\container()->get(PermissionGate::class)->check($this->permission, $request, $handler);
    }
}
