<?php

namespace WPUltimateSecurity\UltimateSecurity\Presentation\API\Routes;

use WPUltimateSecurity\UltimateSecurity\Infrastructure\Security\Capabilities;
use WPUltimateSecurity\UltimateSecurity\Support\Validation\ProFeatureMiddleware;

/**
 * Abstract Route Registrar
 *
 * Base class for REST API route registrars providing common functionality.
 *
 * @package WPUltimateSecurity\UltimateSecurity\Presentation\API\Routes
 * @since 2.0.0
 */
abstract class AbstractRouteRegistrar implements RouteRegistrarInterface
{
    /**
     * The REST API namespace.
     *
     * @var string
     */
    protected const NAMESPACE = 'ultimate-security/v1';

    /**
     * {@inheritDoc}
     */
    public function getNamespace(): string
    {
        return static::NAMESPACE;
    }

    /**
     * Register a route with common defaults.
     *
     * @param string          $route      The route path.
     * @param array           $args       Route arguments.
     * @param string|callable $permission Permission callback or capability.
     *
     * @return bool
     */
    protected function route(string $route, array $args, string|callable $permission = 'manage_options'): bool
    {
        // Set default permission callback
        if (!isset($args['permission_callback'])) {
            $args['permission_callback'] = $this->getPermissionCallback($permission);
        }

        return register_rest_route($this->getNamespace(), $route, $args);
    }

    /**
     * Register a GET route.
     *
     * @param string          $route      The route path.
     * @param callable        $callback   The callback function.
     * @param string|callable $permission Permission callback or capability.
     * @param array           $args       Additional route arguments.
     *
     * @return bool
     */
    protected function get(
        string $route,
        callable $callback,
        string|callable $permission = 'manage_options',
        array $args = []
    ): bool {
        return $this->route($route, array_merge([
            'methods' => 'GET',
            'callback' => $callback,
        ], $args), $permission);
    }

    /**
     * Register a POST route.
     *
     * @param string          $route      The route path.
     * @param callable        $callback   The callback function.
     * @param string|callable $permission Permission callback or capability.
     * @param array           $args       Additional route arguments.
     *
     * @return bool
     */
    protected function post(
        string $route,
        callable $callback,
        string|callable $permission = 'manage_options',
        array $args = []
    ): bool {
        return $this->route($route, array_merge([
            'methods' => 'POST',
            'callback' => $callback,
        ], $args), $permission);
    }

    /**
     * Register a DELETE route.
     *
     * @param string          $route      The route path.
     * @param callable        $callback   The callback function.
     * @param string|callable $permission Permission callback or capability.
     * @param array           $args       Additional route arguments.
     *
     * @return bool
     */
    protected function delete(
        string $route,
        callable $callback,
        string|callable $permission = 'manage_options',
        array $args = []
    ): bool {
        return $this->route($route, array_merge([
            'methods' => 'DELETE',
            'callback' => $callback,
        ], $args), $permission);
    }

    /**
     * Register a PUT route.
     *
     * @param string          $route      The route path.
     * @param callable        $callback   The callback function.
     * @param string|callable $permission Permission callback or capability.
     * @param array           $args       Additional route arguments.
     *
     * @return bool
     */
    protected function put(
        string $route,
        callable $callback,
        string|callable $permission = 'manage_options',
        array $args = []
    ): bool {
        return $this->route($route, array_merge([
            'methods' => 'PUT',
            'callback' => $callback,
        ], $args), $permission);
    }

    /**
     * Get a permission callback from a capability or callable.
     *
     * @param string|callable $permission The permission.
     *
     * @return callable
     */
    protected function getPermissionCallback(string|callable $permission): callable
    {
        if (is_callable($permission)) {
            return $permission;
        }

        // Use Capabilities class if it's one of our custom capabilities
        if (str_starts_with($permission, 'ultimate_security_')) {
            return fn() => Capabilities::currentUserCan($permission);
        }

        // Default WordPress capability check
        return fn() => current_user_can($permission);
    }

    /**
     * Create a Pro-required permission callback.
     *
     * @param string|callable $basePermission Base permission.
     * @param string          $feature        Pro feature identifier.
     *
     * @return callable
     */
    protected function requirePro(string|callable $basePermission, string $feature): callable
    {
        return ProFeatureMiddleware::requirePro($basePermission, $feature);
    }

    /**
     * Standard permission: manage_options.
     *
     * @return callable
     */
    protected function adminOnly(): callable
    {
        return fn() => current_user_can('manage_options');
    }

    /**
     * Standard permission: logged in user.
     *
     * @return callable
     */
    protected function loggedInOnly(): callable
    {
        return fn() => is_user_logged_in();
    }

    /**
     * Standard permission: public access.
     *
     * @return callable
     */
    protected function publicAccess(): callable
    {
        return fn() => true;
    }
}
