<?php

namespace Formatrica\REST;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use WP_Error;
use WP_REST_Request;

/**
 * Small base controller to centralize REST helpers and configuration.
 */
abstract class Base_Rest_Controller implements Rest_Controller
{
    /**
     * Shared REST namespace for all plugin routes.
     */
    protected const NAMESPACE = 'formatrica/v1';

    /**
     * Default permission check for admin-only endpoints.
     * Enforces both capability check and REST nonce verification.
     *
     * @param WP_REST_Request $request
     * @return bool|WP_Error
     */
    public function permissions_check(WP_REST_Request $request)
    {
        if (!current_user_can('manage_options')) {
            return $this->forbidden_error();
        }

        // Verify REST nonce for CSRF protection
        $nonce_result = $this->verify_rest_nonce_or_error($request);
        if ($nonce_result instanceof WP_Error) {
            return $nonce_result;
        }

        return true;
    }

    /**
     * Convenience helper to produce a standardized forbidden WP_Error.
     */
    protected function forbidden_error(string $message = ''): WP_Error
    {
        $message = $message !== '' ? $message : __(
            'You are not allowed to access Formatrica data.',
            'formatrica'
        );

        return new WP_Error(
            'rest_forbidden',
            $message,
            [
                'status' => rest_authorization_required_code(),
            ]
        );
    }

    /**
     * Verify the REST nonce header and return true on success or WP_Error on failure.
     *
     * @return true|WP_Error
     */
    protected function verify_rest_nonce_or_error(WP_REST_Request $request)
    {
        // Accept nonce from standard header or _wpnonce param for flexibility
        $nonce = $request->get_header('x-wp-nonce');
        if (!$nonce) {
            $nonce = (string) $request->get_param('_wpnonce');
        }

        if ($nonce && wp_verify_nonce($nonce, 'wp_rest')) {
            return true;
        }

        // If using alternate auth (e.g., Application Passwords/Bearer), nonce is not required.
        $auth_header = $request->get_header('authorization');
        if (!empty($auth_header)) {
            return true;
        }

        return new WP_Error(
            'rest_forbidden',
            __('Security check failed. Refresh and try again.', 'formatrica'),
            ['status' => 403]
        );
    }

    /**
     * Guard a public endpoint against oversized request bodies (F-03). Rejects
     * on the declared Content-Length first (cheap), then on the actual body
     * size. Bounding the body transitively bounds field count, per-value size,
     * and array-entry count carried in the JSON, so a single request can't
     * exhaust memory/storage/queue/provider work.
     *
     * @param int $max_bytes Hard ceiling for this route (default 1 MB).
     */
    protected function body_too_large(WP_REST_Request $request, int $max_bytes = 1048576): bool
    {
        $declared = (int) $request->get_header('content-length');
        if ($declared > $max_bytes) {
            return true;
        }

        return strlen((string) $request->get_body()) > $max_bytes;
    }

    /**
     * Standard 413 response for an oversized public request body.
     */
    protected function payload_too_large_response(): \WP_REST_Response
    {
        return new \WP_REST_Response([
            'success' => false,
            'message' => __('Request body is too large.', 'formatrica'),
        ], 413);
    }
}
