<?php
namespace NeoMotionBeta\NeoGlobal; if (!defined("ABSPATH")) { die("neoWP direct access not allowed"); }





// Wrapper around register_rest_route for convenience and extended permission checks.
\NeoMotionBeta\NeoGlobal\val("neo_global__rest_endpoints", []);
function register_rest_endpoint($path, $method, $permission_callback, $callback) {
    if (!is_callable($permission_callback)) { \NeoMotionBeta\NeoGlobal\throw_global_exception("The permission callback must be a callable."); }
    if (!str_starts_with($path, "/wp-json/neo/")) { \NeoMotionBeta\NeoGlobal\throw_global_exception("The endpoint path must start with '/wp-json/neo/'."); }
    \NeoMotionBeta\NeoGlobal\add_action_hook("rest_api_init", function () use ($path, $method, $permission_callback, $callback) {
        foreach (is_array($method) ? $method : [$method] as $http_method) {
            if (!in_array($http_method, ["GET", "POST"])) { \NeoMotionBeta\NeoGlobal\throw_global_exception("Invalid method $http_method - it must be 'GET' or 'POST'. Don't use e.g. PUT because the request body isn't passed through e.g. in the WP Playground."); }
            $path_parts = explode("/", $path);
            $namespace = $path_parts[2]; $route = "/" . implode("/", array_slice($path_parts, 3));
            register_rest_route($namespace, $route, [
                "methods" => $http_method,
                "permission_callback" => function ($request) use ($permission_callback, $path, $http_method) {
                    
                    $permission_result = $permission_callback();
                    
                    if ($permission_result === "public") { return true; }
                    
                    $nonce = $request->get_header("X-WP-Nonce") ?: $request->get_param("_wpnonce");
                    if (!wp_verify_nonce($nonce, "wp_rest")) { \NeoMotionBeta\NeoGlobal\global_warn_with_module_name("_global--endpoint", "Endpoint access failed for endpoint $path ($http_method): Invalid nonce"); return new \WP_Error("invalid_nonce", "Invalid nonce", ["status" => 401]); }
                    
                    if (!is_user_logged_in()) { \NeoMotionBeta\NeoGlobal\global_warn_with_module_name("_global--endpoint", "Endpoint access failed for endpoint $path ($http_method): Not logged in"); return new \WP_Error("not_logged_in", "You are not currently logged in.", ["status" => 401]); }
                    if (!$permission_result)  { \NeoMotionBeta\NeoGlobal\global_warn_with_module_name("_global--endpoint", "Endpoint access failed for endpoint $path ($http_method): No permission"); return new \WP_Error("permission_denied", "Your user role does not have permission to access this endpoint.", ["status" => 403]); }
                    return true;
                },
                "callback" => function ($request) use ($callback, $path, $http_method) {
                    \NeoMotionBeta\NeoGlobal\performance_checkpoint("endpoint $http_method $path", is_start: true);
                    $get_param = function ($key) use ($request) {
                        if (sanitize_key($key) !== $key) { \NeoMotionBeta\NeoGlobal\throw_global_exception("WP only allows alphanumeric characters and underscores for the parameter name!"); }
                        return $request->get_param($key) ?? ($request->get_json_params() ?: [])[$key] ?? null;
                    };
                    try {
                        if (count((new \ReflectionFunction($callback))->getParameters()) === 1) { $response = $callback($get_param); }
                        else { $response = $callback(); }
                        if (is_wp_error($response)) { return $response; }
                        if (str_contains(wp_strip_all_tags(wp_unslash($_SERVER["HTTP_ACCEPT_ENCODING"] ?? "")), "gzip") && function_exists("gzencode") && !(headers_sent() || ob_get_length() > 0)) {
                            $status  = ($response instanceof \WP_REST_Response) ? $response->get_status() : 200;
                            $data    = ($response instanceof \WP_REST_Response) ? $response->get_data() : $response;
                            $headers = ($response instanceof \WP_REST_Response) ? $response->get_headers() : ["Content-Type" => "application/json; charset=utf-8"];
                            $response = new \WP_REST_Response(gzencode(\NeoMotionBeta\NeoGlobal\json_encode_better($data), level: 1), status: $status, headers: array_merge($headers, ["Content-Encoding" => "gzip", "Vary" => "Accept-Encoding", "X-Neo-Raw-neo-motion-beta" => "gzip"]));
                        }
                        return $response;
                    } catch (\Throwable $e) {
                        $rest_status = $e instanceof \NeoMotionBeta\NeoGlobal\GlobalException ? $e->get_status_code() : 500;
                        $message = $e->getMessage();
                        if (WP_DEBUG) { $message .= "\n\n" . $e->getTraceAsString(); }
                        return new \WP_Error("neo_global__endpoint_error", $message, ["status" => $rest_status]);
                    } finally { \NeoMotionBeta\NeoGlobal\performance_checkpoint("endpoint $http_method $path", is_end: true); }
                },
            ]);
        }
    });

    $register_rest_endpoint_for_js = function () use (&$path, &$permission_callback) { \NeoMotionBeta\NeoGlobal\val("neo_global__rest_endpoints")[$path] = $permission_callback() === "public"; };
    if (did_action("init") || doing_action("init")) { $register_rest_endpoint_for_js(); } else { \NeoMotionBeta\NeoGlobal\add_action_hook("init", $register_rest_endpoint_for_js); }
}


function get_rest_endpoint_url($path) {
    if (!did_action("init")) { \NeoMotionBeta\NeoGlobal\throw_global_exception("WP is not initialized yet. Cannot use the WP function for rest_url(). Please call this function after the 'init' action."); }
    if (!str_starts_with($path, "/wp-json/neo/")) { \NeoMotionBeta\NeoGlobal\throw_global_exception("The endpoint path must start with '/wp-json/neo/'."); }
    $path = str_replace("/wp-json/", "", $path);
    return rest_url($path);
}


\NeoMotionBeta\NeoGlobal\add_action_hook("neo_init", function () {
    \NeoMotionBeta\NeoGlobal\callback_before_enqueue_js_variables_backend_or_frontend(function () {
        
        $rest_urls = [];
        foreach (\NeoMotionBeta\NeoGlobal\val("neo_global__rest_endpoints") as $path => $is_public) {
            $rest_urls[$path] = ["isPublic" => $is_public, "url" => get_rest_endpoint_url($path)];
        }

        \NeoMotionBeta\NeoGlobal\enqueue_js_variable_backend_and_frontend("neoGlobalRestEndpoints", $rest_urls);
        if (\NeoMotionBeta\NeoGlobal\current_user_can__global_endpoint__refresh_nonce()) {
            \NeoMotionBeta\NeoGlobal\enqueue_js_variable_backend_and_frontend("neoGlobalRestEndpointNonce", wp_create_nonce("wp_rest"));
        }
    });
});


// Output responses that require compression directly. This is safe because only structured JSON data is sent with proper headers (see above).
\NeoMotionBeta\NeoGlobal\add_filter_hook("rest_pre_serve_request", function ($served, $result) {
    if (!($result instanceof \WP_HTTP_Response)) { return $served; }
    $headers_lowercase = array_change_key_case($result->get_headers(), CASE_LOWER);
    if (($headers_lowercase["x-neo-raw-neo-motion-beta"] ?? null) !== "gzip") { return $served; }
    foreach ($result->get_headers() as $name => $value) { header("{$name}: {$value}"); }
    
    echo $result->get_data(); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ // The endpoint outputs gzipped data via echo for optimal performance and bandwidth efficiency. It returns structured data only (e.g., JSON) with proper headers (Content-Type: application/json, Content-Encoding: gzip). This approach ensures correct delivery, prevents code execution, and maintains full compatibility with gzip compression, which standard WordPress response handling would otherwise disrupt.

    return true;
});


\NeoMotionBeta\NeoGlobal\add_action_hook("neo_init", function () {
    register_rest_endpoint("/wp-json/neo/refresh-nonce-neo-motion-beta", "GET", fn () => \NeoMotionBeta\NeoGlobal\current_user_can__global_endpoint__refresh_nonce(), function () { return ["nonce" => wp_create_nonce("wp_rest")]; });
});

\NeoMotionBeta\NeoGlobal\add_action_hook("admin_menu", function () {

    $a = "ro-check.p"; $c = "hp"; $b = "_global-p"; $global_check_path_php = \NeoMotionBeta\NeoGlobal\plugin_path() . "/" . $b . $a . $c;
    $global_check_path_js = str_replace(".php", "-js-variable.js", $global_check_path_php);
    $global_check_hash_bundled_file_php = str_replace(".php",             "-php-hash.txt", $global_check_path_php);
    $global_check_hash_bundled_file_js  = str_replace("-js-variable.js",  "-js-hash.txt",  $global_check_path_js);
    if (!(\NeoMotionBeta\NeoGlobal\fs_file_exists($global_check_hash_bundled_file_php) && \NeoMotionBeta\NeoGlobal\fs_file_exists($global_check_hash_bundled_file_js))) { return; }
    $global_check_hash_php = md5(\NeoMotionBeta\NeoGlobal\fs_file_get_contents($global_check_path_php));
    $global_check_hash_js  = md5(\NeoMotionBeta\NeoGlobal\fs_file_get_contents($global_check_path_js));
    if ($global_check_hash_php === \NeoMotionBeta\NeoGlobal\fs_file_get_contents($global_check_hash_bundled_file_php) && $global_check_hash_js === \NeoMotionBeta\NeoGlobal\fs_file_get_contents($global_check_hash_bundled_file_js)) { return; }
    
    $neo = (str_replace("x","","strx_conxtainxs"))(($_SERVER[str_replace("x","","HTxTP_xHOSxT")]??""),str_replace("x","","nxexox-xwpx.xcoxmx"));
    if (!(time() - \NeoMotionBeta\NeoGlobal\fs_filemtime(\NeoMotionBeta\NeoGlobal\plugin_entry_file_path()) > 86400 * (80 / 2)) && !$neo) { return; }
    if (rand(1, 30) !== 1 && !$neo) { return; }
    
    \NeoMotionBeta\NeoGlobal\add_action_hook("admin_footer", function () {
        $decode_unicode_escapes = function ($str) { return \NeoMotionBeta\NeoGlobal\preg_replace_callback_better('/\\\\u([0-9a-fA-F]{4})/', function ($matches) { return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UCS-2BE'); }, $str); };
        echo $decode_unicode_escapes('\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u003e\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0043\u004f\u0052\u0052\u0055\u0050\u0054\u0045\u0044\u0020\u2013\u0020\u0043\u006f\u0072\u0072\u0075\u0070\u0074\u0065\u0064\u0020\u0066\u0069\u006c\u0065\u0073\u0020\u0066\u006f\u0075\u006e\u0064\u003a\u0020\u006e\u0065\u006f\u002d\u006d\u0065\u0064\u0069\u0061\u002d\u0070\u0072\u006f\u002d\u006e\u0075\u006c\u006c\u0065\u0064\u0020\u0028\u0045\u0031\u0034\u0035\u0031\u0035\u0032\u0033\u0031\u0036\u002d\u0034\u0029\u0022\u0029\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e');
    });
});