<?php

namespace App\Services;

use App\Http\Middleware\ApiAuthenticatedRequest;
use Illuminate\Routing\Route as RoutingRoute;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Route;

/**
 * Single source of truth for which routes are protected by ApiAuthenticatedRequest.
 *
 * Both the ApiUserRouteSeeder (which grants routes to API users) and the admin
 * API-user edit screen (which offers routes to assign) must agree on this set.
 * Resolving it here in one place stops the two from drifting apart.
 */
class ApiAuthenticatedRoutes
{
    /**
     * Names of every route protected by ApiAuthenticatedRequest, however the
     * middleware is attached: the class directly, the kernel alias (apiAuth),
     * or a parameterised alias (e.g. apiAuth:export-map).
     */
    public function names(): Collection
    {
        $names = $this->apiAuthMiddlewareNames();

        return collect(Route::getRoutes())
            ->filter(fn (RoutingRoute $route) => $this->usesApiAuth($route, $names))
            ->map(fn (RoutingRoute $route) => $route->getName())
            ->filter()
            ->values();
    }

    /**
     * Every middleware name that resolves to ApiAuthenticatedRequest: the class
     * itself plus any kernel alias bound to it. Resolving aliases from the router
     * means new aliases are picked up automatically, with no change needed here.
     */
    private function apiAuthMiddlewareNames(): Collection
    {
        return collect(app('router')->getMiddleware())
            ->filter(fn ($class) => $class === ApiAuthenticatedRequest::class)
            ->keys()
            ->push(ApiAuthenticatedRequest::class);
    }

    private function usesApiAuth(RoutingRoute $route, Collection $names): bool
    {
        foreach ($route->gatherMiddleware() as $middleware) {
            // gatherMiddleware() returns raw, unresolved middleware, so strip any
            // parameters ("apiAuth:export-map" -> "apiAuth") before comparing.
            if ($names->contains(explode(':', $middleware)[0])) {
                return true;
            }
        }

        return false;
    }
}
