<?php

declare(strict_types=1);

namespace ShieldX\Api;

defined('ABSPATH') || exit;

use ShieldX\Core\Plugin;

final class StatusController
{
    /** @var Plugin */
    private $plugin;

    public function __construct(Plugin $plugin)
    {
        $this->plugin = $plugin;
    }

    public function register(): void
    {
        register_rest_route('shield-x/v2', '/status', [
            'methods' => 'GET',
            'callback' => [$this, 'status'],
            'permission_callback' => [$this, 'canRead'],
        ]);

        register_rest_route('shield-x/v2', '/lockdown', [
            'methods' => 'GET',
            'callback' => [$this, 'lockdown'],
            'permission_callback' => [$this, 'canRead'],
        ]);

        register_rest_route('shield-x/v2', '/lockdown/preview', [
            'methods' => 'POST',
            'callback' => [$this, 'lockdownPreview'],
            'permission_callback' => [$this, 'canWrite'],
        ]);

        register_rest_route('shield-x/v2', '/lockdown/enable', [
            'methods' => 'POST',
            'callback' => [$this, 'lockdownEnable'],
            'permission_callback' => [$this, 'canWrite'],
        ]);

        register_rest_route('shield-x/v2', '/lockdown/disable', [
            'methods' => 'POST',
            'callback' => [$this, 'lockdownDisable'],
            'permission_callback' => [$this, 'canWrite'],
        ]);

        register_rest_route('shield-x/v2', '/lockdown/policy', [
            'methods' => 'POST',
            'callback' => [$this, 'lockdownPolicy'],
            'permission_callback' => [$this, 'canWrite'],
        ]);
    }

    public function canRead(): bool
    {
        $capability = defined('SHIELDX_MANAGE_CAPABILITY') ? (string) SHIELDX_MANAGE_CAPABILITY : 'manage_options';

        return current_user_can($capability);
    }

    /**
     * @param mixed $request
     */
    public function canWrite($request): bool
    {
        if (!$this->canRead()) {
            return false;
        }

        if (!function_exists('wp_verify_nonce')) {
            return false;
        }

        $nonce = $this->requestNonce($request);

        return $nonce !== '' && wp_verify_nonce($nonce, 'wp_rest') !== false;
    }

    public function status()
    {
        $response = rest_ensure_response($this->plugin->status());
        if (is_object($response) && method_exists($response, 'header')) {
            $response->header('Cache-Control', 'private, max-age=5');
        }

        return $response;
    }

    public function lockdown()
    {
        return rest_ensure_response($this->plugin->lockdownStatus());
    }

    /**
     * @param mixed $request
     */
    public function lockdownPreview($request)
    {
        return rest_ensure_response($this->plugin->previewLockdown($this->requestPolicy($request)));
    }

    /**
     * @param mixed $request
     */
    public function lockdownEnable($request)
    {
        $payload = $this->requestPayload($request);

        return rest_ensure_response($this->plugin->applyLockdown(
            $this->requestPolicy($request),
            !empty($payload['confirm']),
            true,
            'wp_rest',
            $this->requestNonce($request)
        ));
    }

    public function lockdownDisable()
    {
        return rest_ensure_response($this->plugin->revertLockdown(true));
    }

    /**
     * @param mixed $request
     */
    public function lockdownPolicy($request)
    {
        return rest_ensure_response($this->plugin->saveLockdownPolicy($this->requestPolicy($request)));
    }

    /**
     * @param mixed $request
     * @return array<string,mixed>
     */
    private function requestPolicy($request): array
    {
        $payload = $this->requestPayload($request);
        $policy = isset($payload['policy']) && is_array($payload['policy']) ? $payload['policy'] : $payload;

        return is_array($policy) ? $policy : [];
    }

    /**
     * @param mixed $request
     * @return array<string,mixed>
     */
    private function requestPayload($request): array
    {
        if (is_object($request) && method_exists($request, 'get_json_params')) {
            $params = $request->get_json_params();
            if (is_array($params) && !empty($params)) {
                return $params;
            }
        }

        if (is_object($request) && method_exists($request, 'get_params')) {
            $params = $request->get_params();
            if (is_array($params)) {
                return $params;
            }
        }

        return [];
    }

    /**
     * @param mixed $request
     */
    private function requestNonce($request): string
    {
        if (is_object($request) && method_exists($request, 'get_header')) {
            $header = $request->get_header('X-WP-Nonce');
            if (is_scalar($header) && trim((string) $header) !== '') {
                return trim((string) $header);
            }
        }

        $payload = $this->requestPayload($request);
        foreach (['_wpnonce', '_ajax_nonce'] as $key) {
            if (isset($payload[$key]) && is_scalar($payload[$key])) {
                return trim((string) $payload[$key]);
            }
        }

        return '';
    }
}
