<?php

namespace WordpressModels\DependencyInjection\RestRouteAttributes;

use WordpressModels\DependencyInjection\HookAttributes\Attributes\Action;
use WordpressModels\Rest\Permissions\RequestPermissionEvaluator;

/**
 * Register rest routes with the WordPress rest api.
 */
class RestRouteInitializer
{

    public function __construct(private RestRouteRegistry $registry)
    {
    }

    #[Action('rest_api_init')]
    public function registerRoutes()
    {
        $routes = $this->registry->getRoutes();

        foreach ($routes as $scopeConfig) {
            $this->registerScopeRoutes($scopeConfig);
        }
    }

    /**
     * @param array $route
     * @param string|callable $scopePermission
     * @param string $namespace
     * @param string $baseRoute
     * @param bool $public
     * @param bool $override
     * @return void
     */
    private function registerRoute(array                $route,
                                   string|callable|null $scopePermission,
                                   string|null          $namespace,
                                   string|null          $baseRoute,
                                   bool|null            $public,
                                   bool|null            $override): void
    {
        $permissionCallback = null;

        // priority: route > scope > global (null)
        $permission = $route['permission'] ?? $scopePermission;

        if ($permission) {
            // if expression is directly callable, use as callback,
            // else wrap expression in RequestPermissionEvaluator
            $permissionCallback = is_callable($permission)
                ? $permission
                : new RequestPermissionEvaluator($permission);
        }

        $routeParts = array_filter([$baseRoute, $route['route']]);
        $fullRoute = join('/', $routeParts);
        register_rest_route($route['namespace'] ?: $namespace, $fullRoute, [
            'methods' => $route['methods'],
            'callback' => $route['callable'],
            'permission_callback' => $permissionCallback,
            'args' => $route['arguments'],
            'show_in_index' => $route['public'] ?? $public,
        ],
            $route['override'] ?? $override
        );
    }

    /**
     * @return void
     */
    private function registerScopeRoutes(array $scopeConfig): void
    {
        $baseRoute = $scopeConfig['baseRoute'];
        $override = $scopeConfig['override'];
        $public = $scopeConfig['public'];
        $namespace = $scopeConfig['namespace'];
        $scopePermission = $scopeConfig['permission'] ?? null;

        foreach ($scopeConfig['routes'] as $route) {
            $this->registerRoute($route, $scopePermission, $namespace, $baseRoute, $public, $override);
        }
    }

}