<?php
/**
 * Route Authentication Middleware
 *
 * Provides unified authentication and authorization for REST API routes.
 * Integrates with FleekDash V2.2 consolidated authentication system.
 *
 * @package FleekDash\Libs\API
 * @since 2.2.0
 */

namespace FleekDash\Libs\API;

use Throwable;

/**
 * Class RouteAuthMiddleware
 *
 * Unified permission callbacks for REST API routes.
 * Replaces inconsistent auth patterns with a single, secure approach.
 *
 * Usage:
 * ```php
 * Route::get('endpoint', [Controller::class, 'method'])
 *     ->permission(RouteAuthMiddleware::authenticated());
 * ```
 *
 * @package FleekDash\Libs\API
 */
class RouteAuthMiddleware
{
    /**
     * Create a permission callback for the specified authentication level
     *
     * @param string $level Authentication level: 'public', 'authenticated', 'admin', 'capability'
     * @param string|null $capability Required capability (only for level='capability')
     * @return callable Permission callback function
     */
    public static function require($level = 'authenticated', $capability = null)
    {
        return function ($request = null) use ($level, $capability) {
            if ($level === 'public') {
                return true;
            }

            return self::evaluateProtectedRoute($request, (string) $level, $capability);
        };
    }

    /**
     * @param mixed $request
     */
    private static function evaluateProtectedRoute($request, string $level, ?string $capability): bool|\WP_Error
    {
        try {
            $requestObj = $request instanceof \WP_REST_Request ? $request : null;

            return self::runPermissionChecks($requestObj, $level, $capability);
        } catch (Throwable $e) {
            self::logAuthException($e);

            return new \WP_Error(
                'rest_internal_error',
                'Authentication system error',
                ['status' => 500],
            );
        }
    }

    private static function runPermissionChecks(?\WP_REST_Request $request, string $level, ?string $capability): bool|\WP_Error
    {
        $authLevel = $level === 'admin' ? 'admin' : 'authenticated';
        $authCheck = \FleekDash\Core\AuthMiddleware::check($authLevel);

        $result = true;

        if (empty($authCheck['authenticated'])) {
            self::logAuthDeniedIfNeeded($level, $authCheck);

            $result = new \WP_Error(
                'rest_forbidden',
                $authCheck['reason'] ?? 'Authentication required',
                ['status' => $level === 'admin' ? 403 : 401],
            );
        } elseif (
            !\FleekDash\Core\AuthMiddleware::validateRestNonceForMutation($request)
        ) {
            $result = new \WP_Error(
                'rest_cookie_invalid_nonce',
                'Invalid or missing REST nonce',
                ['status' => 403],
            );
        } elseif (
            $level === 'capability'
            && $capability !== null
            && $capability !== ''
            && !\current_user_can($capability)
        ) {
            self::logCapabilityFailureIfNeeded($capability);

            $result = new \WP_Error(
                'rest_forbidden',
                sprintf('Capability "%s" is required', $capability),
                ['status' => 403],
            );
        }

        return $result;
    }

    private static function shouldLogDebugErrors(): bool
    {
        return defined('WP_DEBUG')
            && WP_DEBUG
            && defined('WP_DEBUG_LOG')
            && WP_DEBUG_LOG
            && \function_exists('fleekdash_log_error');
    }

    /**
     * @param array<string, mixed> $authCheck
     */
    private static function logAuthDeniedIfNeeded(string $level, array $authCheck): void
    {
        if (!self::shouldLogDebugErrors()) {
            return;
        }

        $route = $_SERVER['REQUEST_URI'] ?? 'unknown';
        \fleekdash_log_error(sprintf(
            'FleekDash API: Access denied to %s - Level: %s, Reason: %s',
            $route,
            $level,
            $authCheck['reason'] ?? 'unknown',
        ));
    }

    private static function logCapabilityFailureIfNeeded(string $capability): void
    {
        if (!self::shouldLogDebugErrors()) {
            return;
        }

        $route = $_SERVER['REQUEST_URI'] ?? 'unknown';
        $userId = \get_current_user_id();
        \fleekdash_log_error(sprintf(
            'FleekDash API: Capability check failed - Route: %s, User: %d, Required: %s',
            $route,
            $userId,
            $capability,
        ));
    }

    private static function logAuthException(Throwable $e): void
    {
        if (!self::shouldLogDebugErrors()) {
            return;
        }

        \fleekdash_log_error('FleekDash API: AuthMiddleware exception - ' . $e->getMessage());
    }

    /**
     * Public route - no authentication required
     *
     * @return callable Permission callback
     */
    public static function public()
    {
        return self::require('public');
    }

    /**
     * Authenticated route - requires logged-in user
     *
     * @return callable Permission callback
     */
    public static function authenticated()
    {
        return self::require('authenticated');
    }

    /**
     * Admin route - requires admin-level access
     *
     * @return callable Permission callback
     */
    public static function admin()
    {
        return self::require('admin');
    }

    /**
     * Capability-based route - requires specific WordPress capability
     *
     * @param string $capability WordPress capability (e.g., 'manage_options', 'edit_posts')
     * @return callable Permission callback
     */
    public static function capability($capability)
    {
        return self::require('capability', $capability);
    }
}
