<?php
/**
 * MainWP REST Controller
 *
 * This class handles the REST API
 *
 * @package MainWP\Dashboard
 */

use MainWP\Dashboard\MainWP_DB;
use MainWP\Dashboard\MainWP_Utility;
use MainWP\Dashboard\MainWP_Settings;
use MainWP\Dashboard\MainWP_Notification_Settings;
use MainWP\Dashboard\MainWP_Settings_Indicator;
use MainWP\Dashboard\MainWP_System_Utility;
use MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility;
use MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Admin;
use MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party;
use MainWP\Dashboard\Module\ApiBackups\Api_Backups_Utility;
use MainWP\Dashboard\MainWP_Keys_Manager;
use MainWP\Dashboard\MainWP_Api_Manager;
use MainWP\Dashboard\MainWP_Connect;
use MainWP\Dashboard\MainWP_Logger;
use MainWP\Dashboard\MainWP_Sync;
use MainWP\Dashboard\MainWP_Manage_Sites_View;
use MainWP\Dashboard\MainWP_Uptime_Monitoring_Handle;
use MainWP\Dashboard\MainWP_Uptime_Monitoring_Edit;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}


/**
 * Class MainWP_Rest_Settings_Controller
 *
 * @package MainWP\Dashboard
 */
class MainWP_Rest_Settings_Controller extends MainWP_REST_Controller { //phpcs:ignore -- NOSONAR - multi methods.

    // phpcs:disable Generic.Metrics.CyclomaticComplexity -- complexity.

    /**
     * Protected static variable to hold the single instance of the class.
     *
     * @var mixed Default null
     */
    private static $instance = null;

    /**
     * Route base.
     *
     * @var string
     */
    protected $rest_base = 'settings';

    /**
     * Batch size.
     *
     * @var int
     */
    private static $batch_size = 5;

    /**
     * Constructor.
     */
    public function __construct() {
        $this->db = MainWP_DB::instance();
    }

    /**
     * Method instance()
     *
     * Create public static instance.
     *
     * @static
     * @return static::$instance
     */
    public static function instance() {
        if ( null === static::$instance ) {
            static::$instance = new self();
        }
        return static::$instance;
    }

    /**
     * Method register_routes()
     *
     * Creates the necessary endpoints for the api.
     * Note, for a request to be successful the URL query parameters consumer_key and consumer_secret need to be set and correct.
     */
    public function register_routes() { // phpcs:ignore -- NOSONAR - complex.
        // Global settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/general',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_general_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
                'schema' => array( $this, 'get_public_item_schema' ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/general/edit',
            array(
                'methods'             => 'PUT, PATCH',
                'callback'            => array( $this, 'update_general_settings' ),
                'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                'args'                => $this->get_update_general_allowed_fields(),
                'validate_callback'   => array( $this, 'validate_update_general_params' ),
            ),
        );

        // Advanced settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/advanced',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_advanced_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/advanced/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_advanced_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_update_advanced_allowed_fields(),
                ),
            )
        );

        // Monitoring settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/monitoring',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_monitoring_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/monitoring/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_monitoring_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_update_monitoring_allowed_fields(),
                ),
            )
        );

        // Email settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/emails',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_emails_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/emails/(?P<mail_type>[a-zA-Z0-9\-\.\_]+)/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_emails_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_update_emails_allowed_fields(),
                ),
            )
        );

        // Cost Tracker Settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_cost_tracker_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'edit_cost_tracker_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_cost_tracker_allowed_fields(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/product-types/add',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'add_cost_tracker_product_type' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_add_cost_tracker_product_type_allowed_fields(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/product-types/(?P<slug>[a-zA-Z0-9\-\.\_]+)/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_cost_tracker_product_type' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_edit_cost_tracker_product_type_allowed_fields(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/product-types/(?P<slug>[a-zA-Z0-9\-\.\_]+)/delete',
            array(
                array(
                    'methods'             => WP_REST_Server::DELETABLE,
                    'callback'            => array( $this, 'delete_cost_tracker_product_type' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_allowed_product_type_slug_field(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/payment-methods/add',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'add_cost_tracker_payment_method' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_add_cost_tracker_payment_method_allowed_fields(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/payment-methods/(?P<slug>[a-zA-Z0-9\-\.\_]+)/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_cost_tracker_payment_method' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_edit_cost_tracker_payment_method_allowed_fields(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/cost-tracker/payment-methods/(?P<slug>[a-zA-Z0-9\-\.\_]+)/delete',
            array(
                array(
                    'methods'             => WP_REST_Server::DELETABLE,
                    'callback'            => array( $this, 'delete_cost_tracker_payment_method' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_allowed_payment_method_slug_field(),
                ),
            )
        );

        // Dashboard Insights Settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/dashboard-insights',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_dashboard_insights_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/dashboard-insights/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_dashboard_insights_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_edit_dashboard_insight_allowed_fields(),
                ),
            )
        );

        // Backup API Providers Settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/api-backups',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_api_backup_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/api-backups/(?P<api_slug>[a-zA-Z0-9\-\.\_]+)/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_api_backup_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_edit_api_backup_allowed_fields(),
                ),
            )
        );

        // MainWP Dashboard Tools Settings.
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_tool_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/edit',
            array(
                array(
                    'methods'             => 'PUT, PATCH',
                    'callback'            => array( $this, 'update_tools_settings' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => $this->get_edit_tools_allowed_fields(),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/destroy-sessions',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'destroy_sessions' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/destroy-sessions-status/(?P<destroy_id>[a-zA-Z0-9_.\-]+)',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_destroy_sessions_status' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => array(
                        'destroy_id' => array(
                            'required' => true,
                            'type'     => 'string',
                        ),
                    ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/renew-connections',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'renew_connections' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/renew-connections-status/(?P<renew_id>[a-zA-Z0-9_.\-]+)',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_renew_connection_status' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => array(
                        'renew_id' => array(
                            'required' => true,
                            'type'     => 'string',
                        ),
                    ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/disconnect-all-sites',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'disconnect_all_sites' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/disconnect-all-sites-status/(?P<disconnect_id>[a-zA-Z0-9_.\-]+)',
            array(
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_disconnect_status' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                    'args'                => array(
                        'disconnect_id' => array(
                            'required' => true,
                            'type'     => 'string',
                        ),
                    ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/clear-activation-data',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'clear_activation_data' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/tools/restore-info-messages',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'restore_info_messages' ),
                    'permission_callback' => array( $this, 'get_rest_permissions_check' ),
                ),
            )
        );
    }

    /**
     * Get all general settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_general_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get general settings data.
        $settings = $this->get_general_settings_data();

        // Response data by allowed fields.
        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'view' ),
            )
        );
    }

    /**
     * Update general settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Utility::update_option()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_general_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.

        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Get current user id.
        $user_id = $this->get_user_id();
        if ( is_wp_error( $user_id ) ) {
            return $user_id;
        }

        try {
            // Hepper function to update if present.
            $update_if_present = function ( $key, $option_name, $cast = null ) use ( $body ) {
                return $this->update_option_if_present( $body, $key, $option_name, $cast );
            };

            // Hepper function to update if present.
            $update_use_option = function ( $key, $option_name, $cast = null ) use ( $body, $user_id ) {
                if ( array_key_exists( $key, $body ) ) {
                    $val = $body[ $key ];
                    $val = $this->cast_field_value( $val, $cast );
                    if ( 'mainwp_widgets' === $key ) {
                        $show_widgets = get_user_option( 'mainwp_settings_show_widgets', array() );
                        $val          = array_replace( $show_widgets, (array) $val );
                    }
                    update_user_option( $user_id, $option_name, $val, true );
                }
            };

            // Update option setting.
            $update_if_present( 'time_daily_update', 'mainwp_timeDailyUpdate', 'string' );
            $update_if_present( 'frequency_daily_update', 'mainwp_frequencyDailyUpdate', 'int' );
            $update_if_present( 'date_format', 'date_format', 'string' );
            $update_if_present( 'time_format', 'time_format', 'string' );
            $update_if_present( 'timezone_string', 'gmt_offset', 'string' );
            $update_if_present( 'hide_update_everything', 'mainwp_hide_update_everything', 'int' );
            $update_if_present( 'plugin_automatic_daily_update', 'mainwp_pluginAutomaticDailyUpdate', 'int' );
            $update_if_present( 'theme_automatic_daily_update', 'mainwp_themeAutomaticDailyUpdate', 'int' );
            $update_if_present( 'trans_automatic_daily_update', 'mainwp_transAutomaticDailyUpdate', 'int' );
            $update_if_present( 'automatic_daily_update', 'mainwp_automaticDailyUpdate', 'int' );
            $update_if_present( 'frequency_auto_update', 'mainwp_frequency_AutoUpdate', 'string' );
            $update_if_present( 'time_auto_update', 'mainwp_time_AutoUpdate', 'string' );
            $update_if_present( 'show_language_updates', 'mainwp_show_language_updates', 'int' );
            $update_if_present( 'disable_update_confirmations', 'mainwp_disable_update_confirmations', 'int' );
            $update_if_present( 'check_http_response', 'mainwp_check_http_response', 'int' );
            $update_if_present( 'check_http_response_method', 'mainwp_check_http_response_method', 'string' );
            $update_if_present( 'backup_before_upgrade', 'mainwp_backup_before_upgrade', 'int' );
            $update_if_present( 'backup_before_upgrade_days', 'mainwp_backup_before_upgrade_days', 'int' );
            $update_if_present( 'numberdays_outdate_plugin_theme', 'mainwp_numberdays_Outdate_Plugin_Theme', 'int' );
            $update_if_present( 'dayinweek_auto_update', 'mainwp_dayinweek_AutoUpdate', 'int' );
            $update_if_present( 'dayinmonth_auto_update', 'mainwp_dayinmonth_AutoUpdate', 'int' );
            $update_if_present( 'delay_autoupdate', 'mainwp_delay_autoupdate', 'int' );

            // Update backup settings.
            $update_if_present( 'mainwp_primary_backup', 'mainwp_primaryBackup', 'string' );
            $update_if_present( 'mainwp_enable_legacy_backup_feature', 'mainwp_enableLegacyBackupFeature', 'int' );
            $update_if_present( 'mainwp_backups_on_server', 'mainwp_backupsOnServer', 'string' );
            $update_if_present( 'mainwp_backup_on_external_sources', 'mainwp_backupOnExternalSources', 'string' );
            $update_if_present( 'mainwp_archive_format', 'mainwp_archiveFormat', 'string' );
            $update_if_present( 'mainwp_notification_on_backup_fail', 'mainwp_notificationOnBackupFail', 'int' );
            $update_if_present( 'mainwp_notification_on_backup_start', 'mainwp_notificationOnBackupStart', 'int' );
            $update_if_present( 'mainwp_chunked_backup_tasks', 'mainwp_chunkedBackupTasks', 'int' );

            // Update Sidebar.
            $update_use_option( 'sidebar_position', 'mainwp_sidebarPosition', 'int' );
            $update_use_option( 'mainwp_widgets', 'mainwp_settings_show_widgets', 'array' );

            // Get general settings data.
            $settings = $this->get_general_settings_data();
        } catch ( \Exception $e ) {
            do_action( 'mainwp_debug_log', 'Update general settings error: ' . $e->getMessage() );
            return new WP_Error(
                'rest_invalid_param',
                /* translators: %s: Error message */ sprintf( __( 'Update general settings error: %s', 'mainwp' ), $e->getMessage() ),
            );
        }

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => esc_html__( 'General settings updated successfully.', 'mainwp' ),
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'edit' ),
            )
        );
    }

    /**
     * Get all advanced settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_advanced_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get advanced settings data.
        $settings = $this->get_advanced_settings_data();

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'advanced_view', 'advanced_edit' ),
            )
        );
    }

    /**
     * Update advanced settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Utility::update_option()
     * @uses MainWP_System_Utility::get_open_ssl_sign_algos()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_advanced_settings( $request ) { // phpcs:ignore -- NOSONAR - long method.
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        try {
            // Hepper function to update if present.
            $update_if_present = function ( $key, $option_name, $cast = null ) use ( $body ) {
                return $this->update_option_if_present( $body, $key, $option_name, $cast );
            };

            // Update option setting.
            $update_if_present( 'mainwp_maximum_requests', 'mainwp_maximumRequests', 'int' );
            $update_if_present( 'mainwp_minimum_delay', 'mainwp_minimumDelay', 'int' );
            $update_if_present( 'mainwp_maximum_ip_requests', 'mainwp_maximumIPRequests', 'int' );
            $update_if_present( 'mainwp_minimum_ip_delay', 'mainwp_minimumIPDelay', 'int' );
            $update_if_present( 'mainwp_chunksitesnumber', 'mainwp_chunksitesnumber', 'int' );
            $update_if_present( 'mainwp_chunksleepinterval', 'mainwp_chunksleepinterval', 'int' );
            $update_if_present( 'mainwp_maximum_sync_requests', 'mainwp_maximumSyncRequests', 'int' );
            $update_if_present( 'mainwp_maximum_install_update_requests', 'mainwp_maximumInstallUpdateRequests', 'int' );
            $update_if_present( 'mainwp_maximum_uptime_monitoring_requests', 'mainwp_maximum_uptime_monitoring_requests', 'int' );
            $update_if_present( 'mainwp_optimize', 'mainwp_optimize', 'int' );
            $update_if_present( 'mainwp_wp_cron', 'mainwp_wp_cron', 'int' );
            $update_if_present( 'mainwp_ssl_verify_certificate', 'mainwp_sslVerifyCertificate', 'int' );
            $update_if_present( 'mainwp_verify_connection_method', 'mainwp_verify_connection_method', 'int' );
            $update_if_present( 'mainwp_force_use_ipv4', 'mainwp_forceUseIPv4', 'int' );

            // Update sync data.
            if ( isset( $body['sync_data'] ) ) {
                $syncs_data = $this->safe_json_decode( get_option( 'mainwp_settings_sync_data', array() ) ?? '' );
                $val_sync   = array_replace( $syncs_data, (array) $body['sync_data'] );
                MainWP_Utility::update_option( 'mainwp_settings_sync_data', wp_json_encode( $val_sync ) );
            }

            // Update signature algorithm.
            if ( isset( $body['mainwp_connect_signature_algo'] ) ) {
                $sign_algs     = MainWP_System_Utility::get_open_ssl_sign_algos();
                $val_signature = array_search( $body['mainwp_connect_signature_algo'], $sign_algs, true );
                if ( false === $val_signature ) {
                    $val_signature = defined( 'OPENSSL_ALGO_SHA256' ) ? (int) OPENSSL_ALGO_SHA256 : 1;
                }

                MainWP_Utility::update_option( 'mainwp_connect_signature_algo', $val_signature );
            }

            // Get general settings data.
            $settings = $this->get_advanced_settings_data();
        } catch ( \Exception $e ) {
            do_action( 'mainwp_debug_log', 'Update advanced settings error: ' . $e->getMessage() );
            return new WP_Error(
                'rest_invalid_param',
                /* translators: %s: Error message */ sprintf( __( 'Update advanced settings error: %s', 'mainwp' ), $e->getMessage() ),
            );
        }

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => esc_html__( 'General settings updated successfully.', 'mainwp' ),
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'advanced_edit' ),
            )
        );
    }

    /**
     * Get all monitoring settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_monitoring_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get monitoring settings data.
        $settings = $this->get_monitoring_settings_data();

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'monitoring_view' ),
            )
        );
    }

    /**
     * Update monitoring settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings()
     * @uses MainWP_Uptime_Monitoring_Handle::update_uptime_global_settings()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_monitoring_settings( $request ) { // phpcs:ignore -- NOSONAR - long method.
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Get current settings.
        $current_settings = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();
        $updated_settings = $current_settings;

        // Process setting.
        if ( isset( $body['mainwp_uptime_monitoring_active'] ) ) {
            $updated_settings['active'] = $body['mainwp_uptime_monitoring_active'] ? 1 : 0;
        }
        if ( isset( $body['mainwp_uptime_monitoring_down_confirmation_check'] ) ) {
            $updated_settings['maxretries'] = $body['mainwp_uptime_monitoring_down_confirmation_check'];
        }
        if ( isset( $body['mainwp_uptime_monitoring_up_status_codes'] ) ) {
            $updated_settings['up_status_codes'] = implode( ',', $body['mainwp_uptime_monitoring_up_status_codes'] );
        }
        if ( isset( $body['mainwp_uptime_monitoring_interval'] ) ) {
            $interval_values   = MainWP_Uptime_Monitoring_Edit::get_interval_values( false );
            $interval = array_search( $body['mainwp_uptime_monitoring_interval'], $interval_values, true );
            $updated_settings['interval'] = $interval;
        }
        if ( isset( $body['mainwp_uptime_monitoring_keyword'] ) ) {
            $updated_settings['keyword'] = $body['mainwp_uptime_monitoring_keyword'];
        }
        if ( isset( $body['mainwp_uptime_monitoring_method'] ) ) {
            $updated_settings['method'] = $body['mainwp_uptime_monitoring_method'];
        }
        if ( isset( $body['mainwp_uptime_monitoring_timeout'] ) ) {
            $timeout_values   = MainWP_Uptime_Monitoring_Edit::get_timeout_values( false );
            $timeout = array_search( $body['mainwp_uptime_monitoring_timeout'], $timeout_values, true );
            $updated_settings['timeout'] = $timeout;
        }
        if ( isset( $body['mainwp_uptime_monitoring_type'] ) ) {
            $updated_settings['type'] = $body['mainwp_uptime_monitoring_type'];
        }

        // Save monitoring the updated settings.
        $updated_settings = apply_filters( 'mainwp_uptime_monitoring_update_global_settings', $updated_settings );
        MainWP_Uptime_Monitoring_Handle::update_uptime_global_settings( $updated_settings );

        // Save Health Monitoring.
        if ( isset( $body['mainwp_disable_sites_health_monitoring'] ) ) {
            update_option( 'mainwp_disableSitesHealthMonitoring', (int) $body['mainwp_disable_sites_health_monitoring'] );
        }
        if ( isset( $body['mainwp_sitehealth_threshold'] ) ) {
            update_option( 'mainwp_sitehealthThreshold', (int) $body['mainwp_sitehealth_threshold'] );
        }

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $this->get_monitoring_settings_data(), 'monitoring_view' ),
            )
        );
    }

    /**
     * Get all email settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Notification_Settings::get_notification_types()
     * @uses MainWP_Notification_Settings::get_default_emails_fields()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_emails_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get notification email types.
        $notification_emails = MainWP_Notification_Settings::get_notification_types();
        // Get email settings.
        $emails_settings = get_option( 'mainwp_settings_notification_emails' );
        if ( ! is_array( $emails_settings ) ) {
            $emails_settings = array();
        }

        $settings = array();
        if ( ! empty( $notification_emails ) ) {
            foreach ( $notification_emails as $type => $name ) {
                $options    = isset( $emails_settings[ $type ] ) ? $emails_settings[ $type ] : array();
                $default    = MainWP_Notification_Settings::get_default_emails_fields( $type, '', true );
                $options    = array_merge( $default, $options );
                $record     = array(
                    'type'       => $type,
                    'heading'    => $options['heading'],
                    'subject'    => $options['subject'],
                    'recipients' => $options['recipients'],
                    'disable'    => $options['disable'],
                );
                $settings[] = $this->filter_response_data_by_allowed_fields( $record, 'email_view', 'email_edit' );
            }
        }

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $settings,
            )
        );
    }

    /**
     * Update email settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Utility::update_option()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_emails_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Get mail type.
        $setting = $request->get_param( 'mail_type' );
        if ( empty( $setting ) ) {
            return new WP_Error( 'invalid_mail_type', __( 'Mail type is not exist.', 'mainwp' ) );
        }

        $type = $setting['type'] ?? '';
        if ( empty( $type ) ) {
            return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ) );
        }

        // Get email settings.
        $emails_settings = get_option( 'mainwp_settings_notification_emails' );
        if ( ! is_array( $emails_settings ) ) {
            $emails_settings = array();
        }

        // Update email settings.
        $emails_settings[ $type ]['heading']    = ! empty( $body['heading'] ) ? $body['heading'] : $setting['heading'];
        $emails_settings[ $type ]['recipients'] = ! empty( $body['recipients'] ) ? $body['recipients'] : $setting['recipients'];
        $emails_settings[ $type ]['subject']    = ! empty( $body['subject'] ) ? $body['subject'] : $setting['subject'];
        $emails_settings[ $type ]['disable']    = ! empty( $body['disable'] ) ? $body['disable'] : $setting['disable'];
        MainWP_Utility::update_option( 'mainwp_settings_notification_emails', $emails_settings );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Email settings updated successfully.', 'mainwp' ),
                'data'    => $this->filter_response_data_by_allowed_fields( $emails_settings[ $type ], 'email_edit' ),
            )
        );
    }

    /**
     * Get all cost tracker settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_option()
     * @uses Cost_Tracker_Utility::default_currency_settings()
     * @uses Cost_Tracker_Admin::get_product_types()
     * @uses Cost_Tracker_Admin::get_product_colors()
     * @uses Cost_Tracker_Admin::get_product_type_icons()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_cost_tracker_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get currency settings.
        $selected_currency = Cost_Tracker_Utility::get_instance()->get_option( 'currency', 'USD' );
        $currency_format   = Cost_Tracker_Utility::get_instance()->get_option( 'currency_format', array() );

        // Get default currency format.
        $default         = Cost_Tracker_Utility::default_currency_settings();
        $currency_format = array_merge( $default, $currency_format );

        $currency_position  = $currency_format['currency_position'];
        $thousand_separator = $currency_format['thousand_separator'];
        $decimal_separator  = $currency_format['decimal_separator'];
        $decimals           = $currency_format['decimals'];

        // Get custom  payment methods.
        $custom_payment_methods = Cost_Tracker_Utility::get_instance()->get_option( 'custom_payment_methods', array(), true );

        // Get custom product types.
        $custom_product_types = Cost_Tracker_Admin::get_product_types();

        // Get product colors.
        $product_colors = Cost_Tracker_Admin::get_product_colors();

        // Get product icons.
        $product_types_icons = Cost_Tracker_Admin::get_product_type_icons();

        $product_categories = array();
        if ( ! empty( $product_types_icons ) && is_array( $product_types_icons ) ) {
            foreach ( $product_types_icons as $slug => $icon ) {
                $product_categories[] = array(
                    'slug'  => $slug,
                    'title' => isset( $custom_product_types[ $slug ] ) ? $custom_product_types[ $slug ] : '',
                    'icon'  => $icon,
                    'color' => isset( $product_colors[ $slug ] ) ? $product_colors[ $slug ] : '#34424D',
                );
            }
        }

        $settings = array(
            'currency'           => $selected_currency,
            'currency_position'  => $currency_position,
            'thousand_separator' => $thousand_separator,
            'decimal_separator'  => $decimal_separator,
            'decimals'           => $decimals,
            'product_categories' => $product_categories,
            'payment_methods'    => $custom_payment_methods,
        );

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'cost_tracker_view' ),
            )
        );
    }

    /**
     * Edit cost tracker settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Utility::get_instance()->save_options()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function edit_cost_tracker_settings( $request ) {
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Get all options.
        $all_opts        = Cost_Tracker_Utility::get_instance()->get_all_options();
        $currency_format = $all_opts['currency_format'] ?? array(); // Set old currency format setting.

        // Map body to variables.
        $all_opts['currency']        = ! empty( $body['currency'] ) ? $body['currency'] : $all_opts['currency'];
        $all_opts['currency_format'] = array(
            'currency_position'  => ! empty( $body['currency_position'] ) ? $body['currency_position'] : $currency_format['currency_position'],
            'thousand_separator' => ! empty( $body['thousand_separator'] ) ? $body['thousand_separator'] : $currency_format['thousand_separator'],
            'decimal_separator'  => ! empty( $body['decimal_separator'] ) ? $body['decimal_separator'] : $currency_format['decimal_separator'],
            'decimals'           => ! empty( $body['decimals'] ) ? $body['decimals'] : $currency_format['decimals'],
        );

        // Save options.
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Cost tracker settings updated successfully.', 'mainwp' ),
                'data'    => array(
                    'currency'        => $all_opts['currency'],
                    'currency_format' => $all_opts['currency_format'],
                ),
            )
        );
    }

    /**
     * Add cost tracker product type.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Utility::get_instance()->save_options()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function add_cost_tracker_product_type( $request ) { // phpcs:ignore -- NOSONAR - long method.
        $body = $this->get_request_body( $request );

        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Map body to variables.
        $title = $body['title'];
        $slug  = sanitize_title( $title );
        $color = ! empty( $body['color'] ) ? $body['color'] : '#34424D';
        $icon  = ! empty( $body['icon'] ) ? $body['icon'] : 'deficon:folder open';

        // Map product type.
        $all_opts             = Cost_Tracker_Utility::get_instance()->get_all_options();
        $custom_product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );

        // Check if product type duplicated.
        if ( isset( $custom_product_types[ $slug ] ) ) {
            return new WP_Error( 'duplicate_title', __( 'Duplicate product type. Please choose another one.', 'mainwp' ) );
        }
        // Map product type.
        $custom_product_types[ $slug ]    = $title;
        $all_opts['custom_product_types'] = wp_json_encode( $custom_product_types );

        // Map product type color.
        $product_types_colors             = $this->safe_json_decode( $all_opts['product_types_colors'] ?? '' );
        $product_types_colors[ $slug ]    = $color;
        $all_opts['product_types_colors'] = wp_json_encode( $product_types_colors );

        // Map product type icon.
        $product_types_icons             = $this->safe_json_decode( $all_opts['product_types_icons'] ?? '' );
        $product_types_icons[ $slug ]    = $icon;
        $all_opts['product_types_icons'] = wp_json_encode( $product_types_icons );

        // Save options.
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Product type added successfully.', 'mainwp' ),
                'data'    => array(
                    $slug => array(
                        'title' => $title,
                        'color' => $color,
                        'icon'  => $icon,
                    ),
                ),
            )
        );
    }

    /**
     * Update cost tracker product type.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Utility::get_instance()->save_options()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_cost_tracker_product_type( $request ) { // phpcs:ignore -- NOSONAR - long method.
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        $slug = $request->get_param( 'slug' );
        if ( empty( $slug ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid product type slug.', 'mainwp' ) );
        }

        // Default Product Type.
        $default_product_types = Cost_Tracker_Admin::get_default_product_types();

        // Map body to variables.
        $title = $body['title'];
        $color = ! empty( $body['color'] ) ? $body['color'] : '#34424D';
        $icon  = ! empty( $body['icon'] ) ? $body['icon'] : 'deficon:folder open';

        // Cannot change title if it's a default product type.
        if ( array_key_exists( $slug, $default_product_types ) && $title !== $default_product_types[ $slug ] ) {
            return new WP_Error( 'invalid_title', __( 'Cannot change title of default product type.', 'mainwp' ) );
        }

        // Map product type.
        $all_opts                         = Cost_Tracker_Utility::get_instance()->get_all_options();
        $custom_product_types             = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );
        $custom_product_types[ $slug ]    = $title;
        $all_opts['custom_product_types'] = wp_json_encode( $custom_product_types );

        // Map product type color.
        $product_types_colors             = $this->safe_json_decode( $all_opts['product_types_colors'] ?? '' );
        $product_types_colors[ $slug ]    = $color;
        $all_opts['product_types_colors'] = wp_json_encode( $product_types_colors );

        // Map product type icon.
        $product_types_icons             = $this->safe_json_decode( $all_opts['product_types_icons'] ?? '' );
        $product_types_icons[ $slug ]    = $icon;
        $all_opts['product_types_icons'] = wp_json_encode( $product_types_icons );

        // Save options.
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );
        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Product type updated successfully.', 'mainwp' ),
                'data'    => array(
                    $slug => array(
                        'title' => $title,
                        'color' => $color,
                        'icon'  => $icon,
                    ),
                ),
            )
        );
    }

    /**
     * Delete cost tracker product type.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Utility::get_instance()->save_options()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function delete_cost_tracker_product_type( $request ) { // phpcs:ignore -- NOSONAR - complex.
        $slug = $request->get_param( 'slug' );

        if ( empty( $slug ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid product type slug.', 'mainwp' ) );
        }

        // Default Product Type.
        $default_product_types = Cost_Tracker_Admin::get_default_product_types();
        // Cannot delete a default product type.
        if ( array_key_exists( $slug, $default_product_types ) ) {
            return new WP_Error( 'invalid_title', __( 'Cannot delete of default product type.', 'mainwp' ) );
        }

        // Get all options.
        $all_opts             = Cost_Tracker_Utility::get_instance()->get_all_options();
        $custom_product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );
        $product_types_colors = $this->safe_json_decode( $all_opts['product_types_colors'] ?? '' );
        $product_types_icons  = $this->safe_json_decode( $all_opts['product_types_icons'] ?? '' );

        // Check if product type exists.
        if ( ! isset( $custom_product_types[ $slug ] ) ) {
            return new WP_Error( 'invalid_slug', __( 'Product type does not exist.', 'mainwp' ) );
        }

        // Delete product type.
        unset( $custom_product_types[ $slug ] );
        unset( $product_types_colors[ $slug ] );
        unset( $product_types_icons[ $slug ] );

        $all_opts['custom_product_types'] = wp_json_encode( $custom_product_types );
        $all_opts['product_types_colors'] = wp_json_encode( $product_types_colors );
        $all_opts['product_types_icons']  = wp_json_encode( $product_types_icons );

        // Save options.
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Product type deleted successfully.', 'mainwp' ),
            )
        );
    }

    /**
     * Add cost tracker payment method.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_option()
     * @uses Cost_Tracker_Utility::get_instance()->update_option()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function add_cost_tracker_payment_method( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        $title = $body['title'];
        $slug  = sanitize_title( $title );

        // Get all options.
        $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();

        // Get payment methods.
        $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );

        if ( isset( $payment_methods[ $slug ] ) ) {
            return new WP_Error( 'duplicate_title', __( 'Duplicate payment method. Please choose another one.', 'mainwp' ) );
        }

        // Save payment method.
        $payment_methods[ $slug ]           = $title;
        $all_opts['custom_payment_methods'] = wp_json_encode( $payment_methods );

        // Save options.
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Payment method added successfully.', 'mainwp' ),
                'data'    => array(
                    $slug => $title,
                ),
            )
        );
    }

    /**
     * Edit cost tracker payment method.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Utility::get_instance()->update_option()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_cost_tracker_payment_method( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        $slug = $request->get_param( 'slug' );

        // Get all options.
        $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
        // Get payment methods.
        $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
        if ( ! isset( $payment_methods[ $slug ] ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid payment method slug.', 'mainwp' ) );
        }

        $payment_methods[ $slug ]           = $body['title'];
        $all_opts['custom_payment_methods'] = wp_json_encode( $payment_methods );
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Payment method updated successfully.', 'mainwp' ),
                'data'    => array(
                    $slug => $body['title'],
                ),
            )
        );
    }

    /**
     * Delete cost tracker payment method.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Utility::get_instance()->update_option()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function delete_cost_tracker_payment_method( $request ) { // phpcs:ignore -- NOSONAR - complex.
        $slug = $request->get_param( 'slug' );

        // Get all options.
        $all_opts = Cost_Tracker_Utility::get_instance()->get_all_options();
        // Get payment methods.
        $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
        if ( ! isset( $payment_methods[ $slug ] ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid payment method slug.', 'mainwp' ) );
        }

        unset( $payment_methods[ $slug ] );
        $all_opts['custom_payment_methods'] = wp_json_encode( $payment_methods );
        Cost_Tracker_Utility::get_instance()->save_options( $all_opts );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Payment method deleted successfully.', 'mainwp' ),
            )
        );
    }

    /**
     * Get all dashboard insights settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_dashboard_insights_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        $options  = get_option( 'mainwp_module_log_settings', array() );
        $settings = array(
            'enable_insights_logging' => $options['enabled'] ?? 0,
        );

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'dashboard_insights_view' ),
            )
        );
    }

    /**
     * Update dashboard insights settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_dashboard_insights_settings( $request ) {
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Get Current settings.
        $current_insights_logging = get_option( 'mainwp_module_log_settings', 1 );
        $new_insights_logging     = $current_insights_logging;
        if ( isset( $body['enable_insights_logging'] ) ) {
            $new_insights_logging['enabled'] = $body['enable_insights_logging'];
        }

        // Save settings.
        MainWP_Utility::update_option( 'mainwp_module_log_settings', $new_insights_logging );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Dashboard insights settings updated successfully.', 'mainwp' ),
                'data'    => array(
                    'enable_insights_logging' => $new_insights_logging['enabled'],
                ),
            )
        );
    }

    /**
     * Get all API backup settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_api_backup_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Masked token.
        $masked = static function ( $token ) {
            $token = (string) $token;
            if ( empty( $token ) ) {
                return '';
            }
            return '****' . substr( $token, -4 );
        };

        // Get all API backup settings.
        $defs             = $this->get_api_backup_definitions();
        $api_backups_data = array();

        foreach ( $defs as $slug => $def ) {
            $provider = array(
                'label'   => $def['label'],
                'enabled' => (int) get_option( $def['enabled_option'], 0 ),
            );

            if ( ! empty( $def['options'] ) ) {
                foreach ( $def['options'] as $field => $option_key ) {
                    $provider[ $field ] = get_option( $option_key, '' );
                }
            }

            // Get secrets key.
            $secrets = array();
            if ( ! empty( $def['secrets'] ) ) {
                foreach ( $def['secrets'] as $secret_key => $getter ) {
                    $value                  = is_callable( $getter ) ? call_user_func( $getter ) : '';
                    $secrets[ $secret_key ] = $masked( $value );
                }
            }
            $provider['secrets'] = $secrets;

            // Add provider to API backups data.
            $api_backups_data[ $slug ] = $provider;
        }

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( array( 'api_backups' => $api_backups_data ), 'api_backups_view' ),
            )
        );
    }

    /**
     * Update API backup settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Utility::update_option()
     * @uses Api_Backups_Utility::get_instance()->update_api_key()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_api_backup_settings( $request ) {
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        // Get API slug data.
        $api = $request->get_param( 'api_slug' );
        if ( empty( $api ) ) {
            return new WP_Error( 'invalid_api_slug', __( 'API backup not exists.', 'mainwp' ) );
        }

        $updated = array();
        // Update option if present.
        $update_if_present = function ( $key, $option_name ) use ( $body, &$updated ) {
            // Check if key is set and option name is not empty.
            if ( isset( $body[ $key ] ) && ! empty( $option_name ) ) {
                MainWP_Utility::update_option( $option_name, $body[ $key ] );
                $updated[ $key ] = $body[ $key ];
            }
        };

        // Update secrets if present.
        $update_secrets_api = function ( $slug, $value, $name = 'api_key' ) use ( &$updated ) { //  phpcs:ignore -- NOSONAR - complex.
            if ( ! empty( $slug ) && ! empty( $value ) ) {
                Api_Backups_Utility::get_instance()->update_api_key( $slug, $value );
                $updated[ $name ] = $value;
            }
        };

        // Update api option.
        $update_if_present( 'enabled', $api['enabled_option'] ?? '' );
        $update_if_present( 'account_email', $api['options']['account_email'] ?? '' );
        $update_if_present( 'url', $api['options']['url'] ?? '' );
        $update_if_present( 'site_path', $api['options']['site_path'] ?? '' );
        $update_if_present( 'username', $api['options']['username'] ?? '' );
        $update_if_present( 'company_id', $api['options']['company_id'] ?? '' );

        // Update api key or password.
        $update_secrets_api( $api['slug'] ?? '', $body['secrets']['api_key'] ?? '', 'api_key' );
        $update_secrets_api( $api['slug'] ?? '', $body['password'] ?? '', 'password' );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'API backup settings updated successfully.', 'mainwp' ),
                'data'    => $updated,
            )
        );
    }

    /**
     * Get all tool settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_tool_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Get tool settings.
        $settings = $this->get_tool_settings_data();

        return rest_ensure_response(
            array(
                'success' => 1,
                'data'    => $this->filter_response_data_by_allowed_fields( $settings, 'tool_view' ),
            )
        );
    }

    /**
     * Update tool settings.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function update_tools_settings( $request ) { // phpcs:ignore -- NOSONAR - complex.
        // Check content type.
        $content_type = $this->validate_content_type( $request );
        if ( is_wp_error( $content_type ) ) {
            return $content_type;
        }

        // Get request body.
        $body = $this->get_request_body( $request );
        if ( is_wp_error( $body ) ) {
            return $body;
        }

        $user_id = $this->get_user_id();
        if ( is_wp_error( $user_id ) ) {
            return $user_id;
        }

        // update theme option.
        if ( isset( $body['mainwp_theme'] ) && ! empty( $body['mainwp_theme'] ) ) {
            update_user_option( $user_id, 'mainwp_selected_theme', $body['mainwp_theme'] );
        }

        // Update option.
        $this->update_option_if_present( $body, 'mainwp_theme', 'mainwp_selected_theme', 'string' );
        $this->update_option_if_present( $body, 'guided_tours', 'mainwp_enable_guided_tours', 'bool' );
        $this->update_option_if_present( $body, 'chatbase', 'mainwp_enable_guided_chatbase', 'bool' );
        $this->update_option_if_present( $body, 'guided_video', 'mainwp_enable_guided_video', 'bool' );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Tools settings updated successfully.', 'mainwp' ),
                'data'    => $this->filter_response_data_by_allowed_fields( $this->get_tool_settings_data(), 'tool_view' ),
            )
        );
    }

    /**
     * Destroy sessions.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function destroy_sessions( $request ) {
        $websites = $this->get_websites();
        if ( is_wp_error( $websites ) ) {
            return $websites;
        }

        $destroy_id = uniqid( 'destroy_', true );
        $websites   = array_column( $websites, 'id' );
        set_transient(
            "mainwp_tool_destroy_job_{$destroy_id}",
            array(
                'status'     => 'pending',
                'total'      => count( $websites ),
                'processed'  => 0,
                'failed'     => 0,
                'created_at' => time(),
                'websites'   => $websites,
            ),
            DAY_IN_SECONDS
        );

        // Schedule background task.
        if ( function_exists( 'as_schedule_single_action' ) ) {
            as_schedule_single_action(
                time(),
                'mainwp_cron_destroy_session_batch',
                array( $destroy_id )
            );
        } else {
            wp_schedule_single_event( time(), 'mainwp_cron_destroy_session_batch', array( $destroy_id ) );
            spawn_cron(); // Run cron now.
        }

        // Return status url.
        $status_url = $this->namespace . '/' . $this->rest_base . '/tools/destroy-sessions-status/' . $destroy_id;
        return rest_ensure_response(
            array(
                'success'    => 1,
                'message'    => __( 'Destroy sessions process started in background.', 'mainwp' ),
                'destroy_id' => $destroy_id,
                'status_url' => rest_url( $status_url ),
            )
        );
    }

    /**
     * Get destroy sessions status.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_destroy_sessions_status( $request ) {  // phpcs:ignore -- NOSONAR - complex.

        $destroy_id = $request->get_param( 'destroy_id' ); // Get id from url.
        if ( empty( $destroy_id ) ) {
            return new WP_Error(
                'missing_destroy_id',
                __( 'Destroy ID is required.', 'mainwp' )
            );
        }

        $destroy_data = get_transient( "mainwp_tool_destroy_job_{$destroy_id}" );
        if ( ! $destroy_data ) {
            return new WP_Error(
                'destroy_session_job_not_found',
                __( 'Destroy session job not found.', 'mainwp' )
            );
        }

        return rest_ensure_response(
            array(
                'success'      => 'completed' === $destroy_data['status'] && 0 === $destroy_data['failed'],
                'status'       => $destroy_data['status'],
                'total'        => $destroy_data['total'],
                'processed'    => $destroy_data['processed'],
                'failed'       => $destroy_data['failed'],
                'progress'     => round( ( $destroy_data['processed'] / $destroy_data['total'] ) * 100, 2 ),
                'errors'       => ! empty( $destroy_data['errors'] ) ? array_slice( $destroy_data['errors'], 0, 10 ) : array(),
                'started_at'   => $destroy_data['started_at'] ?? '',
                'completed_at' => $destroy_data['completed_at'] ?? '',
            )
        );
    }

    /**
     * Process destroy session batch.
     *
     * @param string $destroy_id Destroy ID.
     *
     * @uses MainWP_System_Utility::can_edit_website()
     *
     * @return void
     */
    public function process_destroy_session_batch( $destroy_id ) {  // phpcs:ignore -- NOSONAR - complex.
        $destroy_data = get_transient( "mainwp_tool_destroy_job_{$destroy_id}" );
        if ( ! $destroy_data || 'completed' === $destroy_data['status'] ) {
            return;
        }
        $website_ids = $destroy_data['websites'];
        $start_index = $destroy_data['processed'];
        $batch       = array_slice( $website_ids, $start_index, $this->batch_size );

        foreach ( $batch as $website_id ) {
            try {
                $website = $this->get_website_by_id( $website_id, $destroy_data );
                if ( empty( $website ) ) {
                    continue;
                }

                if ( MainWP_System_Utility::can_edit_website( $website ) ) {
                    ++$destroy_data['processed'];
                } else {
                    ++$destroy_data['failed'];
                    ++$destroy_data['processed'];
                    $destroy_data['errors'][] = array(
                        'site_id' => $website_id,
                        'error'   => __( 'You cannot edit this website.', 'mainwp' ),
                    );
                }
            } catch ( \Exception $e ) {
                ++$destroy_data['failed'];
                ++$destroy_data['processed'];
                $destroy_data['errors'][] = array(
                    'site_id' => $website_id,
                    'error'   => $e->getMessage(),
                );
            }
        }

        // Reschedule or completed.
        if ( $destroy_data['processed'] >= $destroy_data['total'] ) {
            $destroy_data['status']       = 'completed';
            $destroy_data['completed_at'] = time();
            delete_transient( "mainwp_tool_destroy_job_{$destroy_id}" ); // Delete transient when completed.
        } elseif ( function_exists( 'as_schedule_single_action' ) ) {
            as_schedule_single_action(
                time() + 3,
                'mainwp_cron_destroy_session_batch',
                array( $destroy_id )
            );
        } else {
            wp_schedule_single_event( time() + 3, 'mainwp_cron_destroy_session_batch', array( $destroy_id ) );
            spawn_cron(); // Run Cron now.
        }

        // Update transient.
        set_transient( "mainwp_tool_destroy_job_{$destroy_id}", $destroy_data, DAY_IN_SECONDS );
    }

    /**
     * Renew connections.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function renew_connections( $request ) {
        $websites = $this->get_websites();
        if ( is_wp_error( $websites ) ) {
            return $websites;
        }

        $renew_id = uniqid( 'renew_', true );
        $websites = array_column( $websites, 'id' );
        set_transient(
            "mainwp_tool_renew_job_{$renew_id}",
            array(
                'status'     => 'pending',
                'total'      => count( $websites ),
                'processed'  => 0,
                'failed'     => 0,
                'created_at' => time(),
                'websites'   => $websites,
            ),
            DAY_IN_SECONDS
        );

        // Schedule background task.
        if ( function_exists( 'as_schedule_single_action' ) ) {
            as_schedule_single_action(
                time(),
                'mainwp_cron_renew_connection_batch',
                array( $renew_id )
            );
        } else {
            wp_schedule_single_event( time(), 'mainwp_cron_renew_connection_batch', array( $renew_id ) );
            spawn_cron(); // Run cron now.
        }

        // Return status url.
        $status_url = $this->namespace . '/' . $this->rest_base . '/tools/renew-connections-status/' . $renew_id;
        return rest_ensure_response(
            array(
                'success'    => 1,
                'message'    => __( 'Renew connection process started in background.', 'mainwp' ),
                'renew_id'   => $renew_id,
                'status_url' => rest_url( $status_url ),
            )
        );
    }

    /**
     * Get renew connection status.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function get_renew_connection_status( $request ) {
        $renew_id = $request->get_param( 'renew_id' ); // Get id from url.

        if ( empty( $renew_id ) ) {
            return new WP_Error(
                'missing_renew_id',
                __( 'Renew ID is required.', 'mainwp' )
            );
        }

        // Get disconnect data.
        $renew_data = get_transient( "mainwp_tool_renew_job_{$renew_id}" );

        if ( ! $renew_data ) {
            return new WP_Error(
                'renew_connection_job_not_found',
                __( 'Renew connection job not found.', 'mainwp' )
            );
        }

        return rest_ensure_response(
            array(
                'success'      => 'completed' === $renew_data['status'] && 0 === $renew_data['failed'],
                'status'       => $renew_data['status'],
                'total'        => $renew_data['total'],
                'processed'    => $renew_data['processed'],
                'failed'       => $renew_data['failed'],
                'progress'     => round( ( $renew_data['processed'] / $renew_data['total'] ) * 100, 2 ),
                'errors'       => ! empty( $renew_data['errors'] ) ? array_slice( $renew_data['errors'], 0, 10 ) : array(),
                'started_at'   => $renew_data['started_at'] ?? '',
                'completed_at' => $renew_data['completed_at'] ?? '',
            )
        );
    }

    /**
     * Process renew connection batch.
     *
     * @param string $renew_id Renew ID.
     *
     * @uses MainWP_Sync::sync_site()
     * @uses MainWP_Connect::fetch_url_authed()
     * @uses MainWP_Manage_Sites_View::m_reconnect_site()
     * @uses MainWP_Logger::instance()->info_for_website()
     */
    public function process_renew_connection_batch( $renew_id ) { // phpcs:ignore -- NOSONAR - complex.
        $renew_data = get_transient( "mainwp_tool_renew_job_{$renew_id}" );
        if ( ! $renew_data || 'completed' === $renew_data['status'] ) {
            return;
        }
        $website_ids = $renew_data['websites'];
        $start_index = $renew_data['processed'];
        $batch       = array_slice( $website_ids, $start_index, $this->batch_size );

        foreach ( $batch as $website_id ) {
            try {
                $website = $this->get_website_by_id( $website_id, $renew_data );
                if ( empty( $website ) ) {
                    continue;
                }

                if ( '' !== $website->sync_errors ) {
                    // try reconnect, if failed.
                    MainWP_Sync::sync_site( $website, true );
                }

                $result = MainWP_Connect::fetch_url_authed( $website, 'renew' );
                if ( is_array( $result ) && isset( $result['result'] ) && 'success' === $result['result'] ) {
                    // reconnect immediately, to renew.
                    if ( MainWP_Manage_Sites_View::m_reconnect_site( $website, false ) ) {
                        MainWP_Logger::instance()->info_for_website( $website, 'renew', 'Renew connection successfully.' );
                        ++$renew_data['processed'];
                    } else {
                        ++$renew_data['failed'];
                        ++$renew_data['processed'];
                        $renew_data['errors'][] = array(
                            'site_id' => $website_id,
                            'error'   => $result['error'] ?? __( 'Try to reconnect site failed', 'mainwp' ),
                        );
                    }
                } else {
                    ++$renew_data['failed'];
                    ++$renew_data['processed'];
                    $renew_data['errors'][] = array(
                        'site_id' => $website_id,
                        'error'   => $result['error'] ?? __( 'Try to disconnect site failed', 'mainwp' ),
                    );
                    MainWP_Logger::instance()->info_for_website( $website, 'renew', 'Try to disconnect site failed.' );
                }
            } catch ( \Exception $e ) {
                ++$renew_data['failed'];
                ++$renew_data['processed'];
                $renew_data['errors'][] = array(
                    'site_id' => $website_id,
                    'error'   => $e->getMessage(),
                );
            }
        }

        // Reschedule or completed.
        if ( $renew_data['processed'] >= $renew_data['total'] ) {
            $renew_data['status']       = 'completed';
            $renew_data['completed_at'] = time();
            delete_transient( "mainwp_tool_renew_job_{$renew_id}" ); // Delete transient when completed.
        } elseif ( function_exists( 'as_schedule_single_action' ) ) {
            as_schedule_single_action(
                time() + 3,
                'mainwp_cron_renew_connection_batch',
                array( $renew_id )
            );
        } else {
            wp_schedule_single_event( time() + 3, 'mainwp_cron_renew_connection_batch', array( $renew_id ) );
            spawn_cron(); // Run Cron now.
        }

        // Update transient.
        set_transient( "mainwp_tool_renew_job_{$renew_id}", $renew_data, DAY_IN_SECONDS );
    }

    /**
     * Disconnect all sites.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function disconnect_all_sites( $request ) {
        $websites = $this->get_websites();
        if ( is_wp_error( $websites ) ) {
            return $websites;
        }

        $disconnect_id = uniqid( 'disconnect_', true );
        set_transient(
            "mainwp_tool_disconnect_job_{$disconnect_id}",
            array(
                'status'     => 'pending',
                'total'      => count( $websites ),
                'processed'  => 0,
                'failed'     => 0,
                'created_at' => time(),
                'websites'   => array_column( $websites, 'id' ),
            ),
            DAY_IN_SECONDS
        );

        // Schedule background task.
        if ( function_exists( 'as_schedule_single_action' ) ) {
            as_schedule_single_action(
                time(),
                'mainwp_cron_disconnect_batch',
                array( $disconnect_id )
            );
        } else {
            wp_schedule_single_event( time(), 'mainwp_cron_disconnect_batch', array( $disconnect_id ) );
            spawn_cron(); // Run cron now.
        }

        // Return status url.
        $status_url = $this->namespace . '/' . $this->rest_base . '/tools/disconnect-status/' . $disconnect_id;
        return rest_ensure_response(
            array(
                'success'       => 1,
                'message'       => __( 'Disconnect process started in background.', 'mainwp' ),
                'disconnect_id' => $disconnect_id,
                'status_url'    => rest_url( $status_url ),
            )
        );
    }

    /**
     * Process disconnect batch.
     *
     * @param string $disconnect_id  Disconnect ID.
     *
     * @uses MainWP_Connect::fetch_url_authed()
     *
     * @return void
     */
    public function process_disconnect_batch( $disconnect_id ) {  // phpcs:ignore -- NOSONAR
        $disconnect_data = get_transient( "mainwp_tool_disconnect_job_{$disconnect_id}" );
        if ( ! $disconnect_data || 'completed' === $disconnect_data['status'] ) {
            return;
        }

        // Check if websites are available.
        if ( empty( $disconnect_data['websites'] ) || ! is_array( $disconnect_data['websites'] ) ) {
            return;
        }

        $website_ids = $disconnect_data['websites'];
        $start_index = $disconnect_data['processed'];
        $batch       = array_slice( $website_ids, $start_index, $this->batch_size );

        foreach ( $batch as $website_id ) {
            try {
                $website = $this->get_website_by_id( $website_id, $disconnect_data );
                if ( empty( $website ) ) {
                    continue;
                }

                $result = MainWP_Connect::fetch_url_authed( $website, 'disconnect' );
                if ( is_array( $result ) && isset( $result['result'] ) && 'success' === $result['result'] ) {
                    ++$disconnect_data['processed'];
                } else {
                    ++$disconnect_data['failed'];
                    ++$disconnect_data['processed'];
                    $disconnect_data['errors'][] = array(
                        'site_id' => $website_id,
                        'error'   => $result['error'] ?? __( 'Unknown error', 'mainwp' ),
                    );
                }
            } catch ( \Exception $e ) {
                ++$disconnect_data['failed'];
                ++$disconnect_data['processed'];
                $disconnect_data['errors'][] = array(
                    'site_id' => $website_id,
                    'error'   => $e->getMessage(),
                );
            }
        }

        if ( $disconnect_data['processed'] >= $disconnect_data['total'] ) {
            $disconnect_data['status']       = 'completed';
            $disconnect_data['completed_at'] = time();
            delete_transient( "mainwp_tool_disconnect_job_{$disconnect_id}" ); // Delete transient when completed.
        } elseif ( function_exists( 'as_schedule_single_action' ) ) {
            as_schedule_single_action(
                time() + 3,
                'mainwp_cron_disconnect_batch',
                array( $disconnect_id )
            );
        } else {
            wp_schedule_single_event( time() + 3, 'mainwp_disconnect_site_batch', array( $disconnect_id ) );
            spawn_cron(); // Run Cron now.
        }

        set_transient( "mainwp_tool_disconnect_job_{$disconnect_id}", $disconnect_data, DAY_IN_SECONDS );
    }

    /**
     * Get disconnect job status.
     *
     * @param WP_REST_Request $request REST request.
     *
     * @return WP_REST_Response|WP_Error Response or error.
     */
    public function get_disconnect_status( $request ) {
        $disconnect_id = $request->get_param( 'disconnect_id' ); // Get id from url.

        if ( empty( $disconnect_id ) ) {
            return new WP_Error(
                'missing_disconnect_id',
                __( 'Disconnect ID is required.', 'mainwp' )
            );
        }

        // Get disconnect data.
        $disconnect_data = get_transient( "mainwp_tool_disconnect_job_{$disconnect_id}" );

        if ( ! $disconnect_data ) {
            return new WP_Error(
                'disconnect_job_not_found',
                __( 'Job not found.', 'mainwp' )
            );
        }

        return rest_ensure_response(
            array(
                'success'      => 'completed' === $disconnect_data['status'] && 0 === $disconnect_data['failed'],
                'status'       => $disconnect_data['status'],
                'total'        => $disconnect_data['total'],
                'processed'    => $disconnect_data['processed'],
                'failed'       => $disconnect_data['failed'],
                'progress'     => round( ( $disconnect_data['processed'] / $disconnect_data['total'] ) * 100, 2 ),
                'errors'       => ! empty( $disconnect_data['errors'] ) ? array_slice( $disconnect_data['errors'], 0, 10 ) : array(),
                'started_at'   => $disconnect_data['started_at'],
                'completed_at' => $disconnect_data['completed_at'] ?? null,
            )
        );
    }

    /**
     * Clear activation data.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @uses MainWP_Keys_Manager::instance()->update_key_value()
     * @uses MainWP_Api_Manager::instance()->get_activation_info()
     * @uses MainWP_Api_Manager::instance()->set_activation_info()
     *
     * @return WP_Error|WP_REST_Response
     */
    public function clear_activation_data( $request ) {  // phpcs:ignore -- NOSONAR - complex.
        // Clear activation data.
        delete_option( 'mainwp_extensions_api_username' );
        delete_option( 'mainwp_extensions_api_password' );
        delete_option( 'mainwp_extensions_api_save_login' );
        delete_option( 'mainwp_extensions_plan_info' );

        // Clear master api key.
        MainWP_Keys_Manager::instance()->update_key_value( 'mainwp_extensions_master_api_key', false );

        // Clear extension api key.
        $new_extensions = array();
        $extensions     = get_option( 'mainwp_extensions', array() );

        if ( is_array( $extensions ) ) {
            foreach ( $extensions as $ext ) {
                if ( isset( $ext['api'] ) && isset( $ext['apiManager'] ) && ! empty( $ext['apiManager'] ) ) {
                    if ( isset( $ext['api_key'] ) ) {
                        $ext['api_key'] = '';
                    }
                    if ( isset( $ext['activation_email'] ) ) {
                        $ext['activation_email'] = '';
                    }
                    if ( isset( $ext['activated_key'] ) ) {
                        $ext['activated_key'] = 'Deactivated';
                    }

                    $act_info = MainWP_Api_Manager::instance()->get_activation_info( $ext['api'] );
                    if ( isset( $act_info['api_key'] ) ) {
                        $act_info['api_key'] = '';
                    }
                    if ( isset( $act_info['activation_email'] ) ) {
                        $act_info['activation_email'] = '';
                    }
                    if ( isset( $act_info['activated_key'] ) ) {
                        $act_info['activated_key'] = 'Deactivated';
                    }
                    MainWP_Api_Manager::instance()->set_activation_info( $ext['api'], $act_info );
                }
                $new_extensions[] = $ext;
            }
        }

        MainWP_Utility::update_option( 'mainwp_extensions', $new_extensions );
        MainWP_Utility::update_option( 'mainwp_extensions_all_activation_cached', '' );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Activation data cleared successfully.', 'mainwp' ),
            )
        );
    }

    /**
     * Restore info messages by clearing the saved notice status.
     *
     * @param WP_REST_Request $request Full details about the request.
     *
     * @return WP_Error|WP_REST_Response
     */
    public function restore_info_messages( $request ) {
        $user_id = $this->get_user_id();
        if ( is_wp_error( $user_id ) ) {
            return $user_id;
        }

        // Delete user option.
        delete_user_option( $user_id, 'mainwp_notice_saved_status' );

        return rest_ensure_response(
            array(
                'success' => 1,
                'message' => __( 'Info messages restored successfully.', 'mainwp' ),
            )
        );
    }

    /**
     * Get allowed fields for general settings.
     *
     * @return array
     */
    public function get_update_general_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        $val_bool        = array( 0, 1 );
        $disable_update  = array( 0, 1, 2 );
        $days_week       = range( 0, 6 );
        $days_month      = range( 0, 31 );
        $delay           = array( 0, 1, 2, 3, 4, 5, 6, 7, 14, 30 );
        $frequency       = array( 'daily', 'weekly', 'monthly' );
        $frequency_daily = range( 1, 12 );
        $http_methods    = array( 'head', 'get' );
        $archive_format  = array( 'zip', 'tar.gz', 'tar.bz2', 'tar' );
        $primary_backup  = array( '', 'module-api-backups' );

        return array(
            'time_daily_update'                   => array(
                'required'          => false,
                'description'       => __( 'Time for daily updates (HH:MM format).', 'mainwp' ),
                'type'              => 'string',
                'validate_callback' => array( $this, 'validate_time_update' ),
                'sanitize_callback' => array( $this, 'sanitize_time_update' ),
            ),
            'frequency_daily_update'              => array(
                'required'          => false,
                'description'       => __( 'Frequency of daily updates (1-12).', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $frequency_daily ),
                'validate_callback' => $this->make_enum_validator( $frequency_daily ),
            ),
            'date_format'                         => array(
                'required'          => false,
                'description'       => __( 'Date format.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_date_format' ),
            ),
            'time_format'                         => array(
                'required'          => false,
                'description'       => __( 'Time format.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_time_format' ),
            ),
            'timezone_string'                     => array(
                'required'          => false,
                'description'       => __( 'Timezone.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => array( $this, 'sanitize_timezone_field' ),
                'validate_callback' => array( $this, 'validate_timezone' ),
            ),
            'sidebar_position'                    => array(
                'required'          => false,
                'description'       => __( 'Sidebar position.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'hide_update_everything'              => array(
                'required'          => false,
                'description'       => __( 'Hide update everything button.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_widgets'                      => array(
                'required'          => false,
                'description'       => __( 'MainWP dashboard widgets.', 'mainwp' ),
                'type'              => 'array',
                'sanitize_callback' => array( $this, 'sanitize_mainwp_widgets' ),
                'validate_callback' => array( $this, 'validate_mainwp_widgets' ),
            ),
            'plugin_automatic_daily_update'       => array(
                'required'          => false,
                'description'       => __( 'Plugin automatic daily update.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'theme_automatic_daily_update'        => array(
                'required'          => false,
                'description'       => __( 'Theme automatic daily update.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'trans_automatic_daily_update'        => array(
                'required'          => false,
                'description'       => __( 'Translation automatic daily update.', 'mainwp' ),
                'type'              => 'array',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'automatic_daily_update'              => array(
                'required'          => false,
                'description'       => __( 'Plugin automatic daily update.', 'mainwp' ),
                'type'              => 'array',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'frequency_auto_update'               => array(
                'required'          => false,
                'description'       => __( 'Frequency of auto updates.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $frequency, 'string' ),
                'validate_callback' => $this->make_enum_validator( $frequency, 'string' ),
            ),
            'time_auto_update'                    => array(
                'required'          => false,
                'description'       => __( 'Auto update time (whole hour, 24h).', 'mainwp' ),
                'type'              => 'string',
                'validate_callback' => array( $this, 'validate_time_update' ),
                'sanitize_callback' => array( $this, 'sanitize_time_update' ),
            ),
            'show_language_updates'               => array(
                'required'          => false,
                'description'       => __( 'Show language updates.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'disable_update_confirmations'        => array(
                'required'          => false,
                'description'       => __( 'Disable update confirmations.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $disable_update ),
                'validate_callback' => $this->make_enum_validator( $disable_update ),
            ),
            'check_http_response'                 => array(
                'required'          => false,
                'description'       => __( 'Check HTTP response after update.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'check_http_response_method'          => array(
                'required'          => false,
                'description'       => __( 'HTTP method for response check.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $http_methods, 'string' ),
                'validate_callback' => $this->make_enum_validator( $http_methods, 'string' ),
            ),
            'backup_before_upgrade'               => array(
                'required'          => false,
                'description'       => __( 'Backup before upgrade.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'backup_before_upgrade_days'          => array(
                'required'          => false,
                'description'       => __( 'Days to check for backup before upgrade.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => 'absint',
            ),
            'numberdays_outdate_plugin_theme'     => array(
                'required'          => false,
                'description'       => __( 'Number of days to consider plugin/theme as outdated.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => 'absint',
            ),
            'dayinweek_auto_update'               => array(
                'required'          => false,
                'description'       => __( 'Day in week for auto updates.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $days_week ),
                'validate_callback' => $this->make_enum_validator( $days_week ),
            ),
            'dayinmonth_auto_update'              => array(
                'required'          => false,
                'description'       => __( 'Day in month for auto updates.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $days_month ),
                'validate_callback' => $this->make_enum_validator( $days_month ),
            ),
            'delay_autoupdate'                    => array(
                'required'          => false,
                'description'       => __( 'Delay automatic updates.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $delay ),
                'validate_callback' => $this->make_enum_validator( $delay ),
            ),
            'mainwp_primary_backup'               => array(
                'required'          => false,
                'description'       => __( 'Primary backup method.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $primary_backup, 'string' ),
                'validate_callback' => $this->make_enum_validator( $primary_backup, 'string' ),
            ),
            'mainwp_enable_legacy_backup_feature' => array(
                'required'          => false,
                'description'       => __( 'Enable legacy backup feature.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_backups_on_server'            => array(
                'required'          => false,
                'description'       => __( 'Backups on server.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'mainwp_backup_on_external_sources'   => array(
                'required'          => false,
                'description'       => __( 'Backup on external sources.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'mainwp_archive_format'               => array(
                'required'          => false,
                'description'       => __( 'Archive format.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $archive_format, 'string' ),
                'validate_callback' => $this->make_enum_validator( $archive_format, 'string' ),
            ),
            'mainwp_notification_on_backup_fail'  => array(
                'required'          => false,
                'description'       => __( 'Notification on backup fail.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_notification_on_backup_start' => array(
                'required'          => false,
                'description'       => __( 'Notification on backup start.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_chunked_backup_tasks'         => array(
                'required'          => false,
                'description'       => __( 'Chunked backup tasks.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
        );
    }

    /**
     * Get allowed fields for advanced settings.
     *
     * @uses MainWP_System_Utility::get_open_ssl_sign_algos()
     *
     * @return array
     */
    public function get_update_advanced_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        $val_bool             = array( 0, 1 );
        $connection_method    = array( 1, 2 );
        $maximum_requests     = range( 1, 20 );
        $minimum_delay        = range( 100, 5000, 100 );
        $maximum_ip_requests  = range( 1, 10 );
        $minimum_ip_delay     = range( 500, 5000, 100 );
        $chunk_sites_number   = range( 1, 30 );
        $chunk_sleep_interval = range( 0, 20 );
        $monitoring_requests  = range( 1, 100 );
        $sign_algs            = MainWP_System_Utility::get_open_ssl_sign_algos();

        return array(
            'mainwp_maximum_requests'                   => array(
                'required'          => false,
                'description'       => __( 'Maximum requests.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $maximum_requests ),
                'validate_callback' => $this->make_enum_validator( $maximum_requests ),
            ),
            'mainwp_minimum_delay'                      => array(
                'required'          => false,
                'description'       => __( 'Minimum delay.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $minimum_delay ),
                'validate_callback' => $this->make_enum_validator( $minimum_delay ),
            ),
            'mainwp_maximum_ip_requests'                => array(
                'required'          => false,
                'description'       => __( 'Maximum IP requests.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $maximum_ip_requests ),
                'validate_callback' => $this->make_enum_validator( $maximum_ip_requests ),
            ),
            'mainwp_minimum_ip_delay'                   => array(
                'required'          => false,
                'description'       => __( 'Minimum IP delay.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $minimum_ip_delay ),
                'validate_callback' => $this->make_enum_validator( $minimum_ip_delay ),
            ),
            'mainwp_chunksitesnumber'                   => array(
                'required'          => false,
                'description'       => __( 'Chunk sites number.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $chunk_sites_number ),
                'validate_callback' => $this->make_enum_validator( $chunk_sites_number ),
            ),
            'mainwp_chunksleepinterval'                 => array(
                'required'          => false,
                'description'       => __( 'Chunk sleep interval.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $chunk_sleep_interval ),
                'validate_callback' => $this->make_enum_validator( $chunk_sleep_interval ),
            ),
            'mainwp_maximum_sync_requests'              => array(
                'required'          => false,
                'description'       => __( 'Maximum sync requests.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $maximum_requests ),
                'validate_callback' => $this->make_enum_validator( $maximum_requests ),
            ),
            'mainwp_maximum_install_update_requests'    => array(
                'required'          => false,
                'description'       => __( 'Maximum install and update requests.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $maximum_requests ),
                'validate_callback' => $this->make_enum_validator( $maximum_requests ),
            ),
            'mainwp_maximum_uptime_monitoring_requests' => array(
                'required'          => false,
                'description'       => __( 'Maximum uptime monitoring requests.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $monitoring_requests ),
                'validate_callback' => $this->make_enum_validator( $monitoring_requests ),
            ),
            'mainwp_optimize'                           => array(
                'required'          => false,
                'description'       => __( 'Optimize data loading.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_wp_cron'                            => array(
                'required'          => false,
                'description'       => __( 'Use WP Cron.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_ssl_verify_certificate'             => array(
                'required'          => false,
                'description'       => __( 'Verify SSL certificate.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_verify_connection_method'           => array(
                'required'          => false,
                'description'       => __( 'Verify connection method.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $connection_method ),
                'validate_callback' => $this->make_enum_validator( $connection_method ),
            ),
            'mainwp_force_use_ipv4'                     => array(
                'required'          => false,
                'description'       => __( 'Force use IPv4.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_connect_signature_algo'             => array(
                'required'          => false,
                'description'       => __( 'OpenSSL signature algorithm.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $sign_algs, 'string' ),
                'validate_callback' => $this->make_enum_validator( $sign_algs, 'string' ),
            ),
            'sync_data'                                 => array(
                'required'          => false,
                'description'       => __( 'Sync data.', 'mainwp' ),
                'type'              => 'array',
                'sanitize_callback' => array( $this, 'sanitize_sync_data' ),
                'validate_callback' => array( $this, 'validate_sync_data' ),
            ),
        );
    }

    /**
     * Get allowed fields for monitoring settings.
     *
     * @return array Allowed fields.
     */
    public function get_update_monitoring_allowed_fields() {
        $val_bool        = array( 0, 1 );
        $threshold       = array( 80, 100 );
        $monitoring_type = array( 'http', 'ping', 'keyword' );
        $timeout_values  = array_values( MainWP_Uptime_Monitoring_Edit::get_timeout_values( false ) );
        $interval_values = array_values( MainWP_Uptime_Monitoring_Edit::get_interval_values( false ) );

        return array(
            'mainwp_uptime_monitoring_active'          => array(
                'required'          => false,
                'description'       => __( 'Active or disable monitoring globally.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_uptime_monitoring_down_confirmation_check' => array(
                'required'          => false,
                'description'       => __( 'Uptime monitoring down confirmation check.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_disable_sites_health_monitoring'   => array(
                'required'          => false,
                'description'       => __( 'Disable sites health monitoring.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'mainwp_sitehealth_threshold'              => array(
                'required'          => false,
                'description'       => __( 'Site health threshold.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $threshold ),
                'validate_callback' => $this->make_enum_validator( $threshold ),
            ),
            'mainwp_uptime_monitoring_type'            => array(
                'required'          => false,
                'description'       => __( 'Uptime monitoring type.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $monitoring_type, 'string' ),
                'validate_callback' => $this->make_enum_validator( $monitoring_type, 'string' ),
            ),
            'mainwp_uptime_monitoring_timeout'         => array(
                'required'          => false,
                'description'       => __( 'Uptime monitoring timeout.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $timeout_values, 'string' ),
                'validate_callback' => $this->make_enum_validator( $timeout_values, 'string' ),
            ),
            'mainwp_uptime_monitoring_interval'        => array(
                'required'          => false,
                'description'       => __( 'Uptime monitoring interval.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $interval_values, 'string' ),
                'validate_callback' => $this->make_enum_validator( $interval_values, 'string' ),
            ),
            'mainwp_uptime_monitoring_keyword'         => array(
                'required'          => false,
                'description'       => __( 'Uptime monitoring keyword.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'mainwp_uptime_monitoring_up_status_codes' => array(
                'required'          => false,
                'description'       => __( 'Uptime monitoring up status codes.', 'mainwp' ),
                'type'              => 'array',
                'sanitize_callback' => array( $this, 'sanitize_uptime_monitoring_status_codes' ),
                'validate_callback' => array( $this, 'validate_uptime_monitoring_status_codes' ),
            ),
        );
    }

    /**
     * Get update emails allowed fields.
     *
     * @return array
     */
    public function get_update_emails_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        $val_bool = array( 0, 1 );
        return array(
            'mail_type'  => array(
                'required'          => true,
                'description'       => __( 'Setting Mail type.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => array( $this, 'sanitize_email_type' ),
                'validate_callback' => array( $this, 'validate_email_type' ),
            ),
            'disable'    => array(
                'required'          => false,
                'description'       => __( 'Disable mail.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
            'heading'    => array(
                'required'          => false,
                'description'       => __( 'Mail name.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'subject'    => array(
                'required'          => false,
                'description'       => __( 'Mail description.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_textarea_field',
            ),
            'recipients' => array(
                'required'          => false,
                'description'       => __( 'Mail recipients.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => function ( $value ) {
                    if ( ! is_email( $value ) ) {
                        return new WP_Error(
                            'invalid_email',
                            /* translators: %s: Email address */ sprintf( __( 'Invalid email address: %s.', 'mainwp' ), $value ),
                        );
                    }
                    return true;
                },
            ),
        );
    }

    /**
     * Get add cost tracker product type allowed fields.
     *
     * @return array
     */
    public function get_add_cost_tracker_product_type_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        return array(
            'title' => array(
                'required'          => true,
                'description'       => __( 'Product type title.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'color' => array(
                'required'          => false,
                'description'       => __( 'Product type color.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_product_type_color' ),
            ),
            'icon'  => array(
                'required'          => false,
                'description'       => __( 'Product type icon.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_product_type_icon' ),
            ),
        );
    }

    /**
     * Get cost tracker allowed fields.
     *
     * @return array
     */
    public function get_cost_tracker_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        $currency_position = array(
            'left',
            'right',
            'left_space',
            'right_space',
        );
        return array(
            'currency'           => array(
                'required'          => false,
                'description'       => __( 'Currency.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_cost_tracker_currency' ),
            ),
            'currency_position'  => array(
                'required'          => false,
                'description'       => __( 'Currency position.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $currency_position, 'string' ),
                'validate_callback' => $this->make_enum_validator( $currency_position, 'string' ),
            ),
            'thousand_separator' => array(
                'required'          => false,
                'description'       => __( 'Thousand separator.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'decimal_separator'  => array(
                'required'          => false,
                'description'       => __( 'Decimal separator.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
        );
    }

    /**
     * Get edit cost tracker product type allowed fields.
     *
     * @return array
     */
    public function get_edit_cost_tracker_product_type_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        return array_merge(
            $this->get_add_cost_tracker_product_type_allowed_fields(),
            $this->get_allowed_product_type_slug_field()
        );
    }

    /**
     * Get allowed product type slug field.
     *
     * @return array
     */
    public function get_allowed_product_type_slug_field() {
        return array(
            'slug' => array(
                'required'          => true,
                'description'       => __( 'Product type slug.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_product_type_slug' ),
            ),
        );
    }

    /**
     * Get add cost tracker payment method allowed fields.
     *
     * @return array
     */
    public function get_add_cost_tracker_payment_method_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        return array(
            'title' => array(
                'required'          => true,
                'description'       => __( 'Payment method title.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ),
        );
    }

    /**
     * Get edit cost tracker payment method allowed fields.
     *
     * @return array
     */
    public function get_edit_cost_tracker_payment_method_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        return array_merge(
            $this->get_allowed_payment_method_slug_field(),
            $this->get_add_cost_tracker_payment_method_allowed_fields()
        );
    }

    /**
     * Get allowed payment method slug field.
     *
     * @return array
     */
    public function get_allowed_payment_method_slug_field() {
        return array(
            'slug' => array(
                'required'          => true,
                'description'       => __( 'Payment method slug.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'validate_callback' => array( $this, 'validate_payment_method_slug' ),
            ),
        );
    }

    /**
     * Get edit dashboard insights allowed fields.
     *
     * @return array
     */
    public function get_edit_dashboard_insight_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        $val_bool = array( 0, 1 );
        return array(
            'enable_insights_logging' => array(
                'required'          => false,
                'description'       => __( 'Enable insights logging.', 'mainwp' ),
                'type'              => 'integer',
                'sanitize_callback' => $this->make_enum_sanitizer( $val_bool ),
                'validate_callback' => $this->make_enum_validator( $val_bool ),
            ),
        );
    }

    /**
     * Get edit api backup allowed fields.
     *
     * @return array
     */
    public function get_edit_api_backup_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        return array_merge(
            $this->get_allowed_api_slug_field(),
            array(
                'username' => array(
                    'required'          => false,
                    'description'       => __( 'API username.', 'mainwp' ),
                    'type'              => 'string',
                    'sanitize_callback' => 'sanitize_text_field',
                ),
                'password' => array(
                    'required'          => false,
                    'description'       => __( 'API password.', 'mainwp' ),
                    'type'              => 'string',
                    'sanitize_callback' => 'sanitize_text_field',
                ),
            )
        );
    }

    /**
     * Get allowed API slug field.
     *
     * @return array
     */
    public function get_allowed_api_slug_field() {
        return array(
            'api_slug'      => array(
                'required'          => true,
                'description'       => __( 'API slug.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => array( $this, 'sanitize_api_slug' ),
                'validate_callback' => array( $this, 'validate_api_slug' ),
            ),
            'enabled'       => array(
                'type'              => 'boolean',
                'required'          => false,
                'description'       => __( 'Enable/Disable the provider.', 'mainwp' ),
                'sanitize_callback' => 'rest_sanitize_boolean',
                'validate_callback' => 'rest_is_boolean',
            ),
            'url'           => array(
                'type'              => 'string',
                'required'          => false,
                'description'       => __( 'Server URL (for cPanel).', 'mainwp' ),
                'sanitize_callback' => 'sanitize_url',
            ),
            'site_path'     => array(
                'type'              => 'string',
                'required'          => false,
                'description'       => __( 'Site path (for cPanel).', 'mainwp' ),
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'username'      => array(
                'type'              => 'string',
                'required'          => false,
                'description'       => __( 'Username (for cPanel).', 'mainwp' ),
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'password'      => array(
                'type'              => 'string',
                'required'          => false,
                'description'       => __( 'Password (for cPanel).', 'mainwp' ),
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'account_email' => array(
                'type'              => 'string',
                'required'          => false,
                'description'       => __( 'Account email (for Cloudways).', 'mainwp' ),
                'sanitize_callback' => 'sanitize_email',
                'validate_callback' => 'is_email',
            ),
            'company_id'    => array(
                'type'              => 'string',
                'required'          => false,
                'description'       => __( 'Company ID (for kinsta).', 'mainwp' ),
                'sanitize_callback' => 'sanitize_text_field',
            ),
            'secrets'       => array(
                'type'        => 'object',
                'required'    => false,
                'description' => __( 'Secrets (Cpanel not used).', 'mainwp' ),
                'properties'  => array(
                    'api_key' => array(
                        'type'              => 'string',
                        'required'          => true,
                        'description'       => __( 'API key (for kinsta).', 'mainwp' ),
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
            ),
        );
    }

    /**
     * Get edit tools allowed fields.
     *
     * @return array
     */
    public function get_edit_tools_allowed_fields() { // phpcs:ignore -- NOSONAR - long method.
        $themes = array( 'default', 'default-2024', 'classic', 'dark', 'wpadmin', 'minimalistic' );
        return array(
            'mainwp_theme' => array(
                'required'          => false,
                'description'       => __( 'MainWP theme.', 'mainwp' ),
                'type'              => 'string',
                'sanitize_callback' => $this->make_enum_sanitizer( $themes, 'string' ),
                'validate_callback' => $this->make_enum_validator( $themes, 'string' ),
            ),
            'guided_tours' => array(
                'required'          => false,
                'description'       => __( 'Enable guided tours.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => 'rest_sanitize_boolean',
                'validate_callback' => 'rest_is_boolean',
            ),
            'chatbase'     => array(
                'required'          => false,
                'description'       => __( 'Enable chatbase.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => 'rest_sanitize_boolean',
                'validate_callback' => 'rest_is_boolean',
            ),
            'guided_video' => array(
                'required'          => false,
                'description'       => __( 'Enable youtube embeds.', 'mainwp' ),
                'type'              => 'boolean',
                'sanitize_callback' => 'rest_sanitize_boolean',
                'validate_callback' => 'rest_is_boolean',
            ),
        );
    }

    /**
     * Sanitize API slug.
     *
     * @param string $value API slug.
     *
     * @return string
     */
    public function sanitize_api_slug( $value ) {
        if ( empty( $value ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid API slug.', 'mainwp' ) );
        }

        // Sanitize field.
        $value       = $this->sanitize_field( $value );
        $api_backups = $this->get_api_backup_definitions(); // Get API backup definitions.
        if ( ! array_key_exists( $value, $api_backups ) ) {
            return new WP_Error( 'invalid_slug', __( 'API slug not exists.', 'mainwp' ) );
        }
        $api_backups[ $value ]['slug'] = $value; // Add slug to API backup definition.
        return $api_backups[ $value ];
    }

    /**
     * Validate API slug.
     *
     * @param string          $value API slug.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_api_slug( $value, $request ) {
        if ( empty( $value ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid API slug.', 'mainwp' ) );
        }

        $value = $this->sanitize_field( $value );

        // Check if API slug exists.
        $api_backups = $this->get_api_backup_definitions();
        if ( ! array_key_exists( $value, $api_backups ) ) {
            return new WP_Error( 'invalid_slug', __( 'API slug not exists.', 'mainwp' ) );
        }

        return true;
    }

    /**
     * Validate currency.
     *
     * @param string          $value Currency.
     * @param WP_REST_Request $request Request object.
     *
     * @uses Cost_Tracker_Utility::get_currency_symbol()
     *
     * @return bool|WP_Error
     */
    public function validate_cost_tracker_currency( $value, $request ) {
        if ( empty( $value ) ) {
            return true;
        }

        $value  = $this->sanitize_field( $value ); // Sanitize field.
        $symbol = Cost_Tracker_Utility::get_currency_symbol( $value ); // Get currency symbol.
        if ( empty( $symbol ) ) {
            return new WP_Error( 'invalid_currency', __( 'Invalid currency.', 'mainwp' ) );
        }
        return true;
    }
    /**
     * Validate product type color.
     *
     * @param string          $value Product type color.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_product_type_color( $value, $request ) {
        if ( empty( $value ) ) {
            return true;
        }

        $value = $this->sanitize_field( $value );
        if ( ! preg_match( '/^#([A-Fa-f0-9]{6})$/', $value ) ) {
            return new WP_Error( 'invalid_color', __( 'Invalid color. Color must be in the format "#RRGGBB".', 'mainwp' ) );
        }
        return true;
    }

    /**
     * Validate product type icon.
     *
     * @param string          $value Product type icon.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_product_type_icon( $value, $request ) {
        if ( empty( $value ) ) {
            return true;
        }

        $value = $this->sanitize_field( $value );
        if ( ! preg_match( '/^[a-z0-9_\-]+:[a-z0-9_\-\s]+$/i', $value ) ) {
            return new WP_Error(
                'invalid_icon',
                __( 'Invalid icon. Icon must be in the format "icon_type:icon_name".', 'mainwp' )
            );
        }
        return true;
    }

    /**
     * Validate product type slug.
     *
     * @param string          $value Product type slug.
     * @param WP_REST_Request $request Request object.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     * @uses Cost_Tracker_Admin::get_default_product_types()
     *
     * @return bool|WP_Error
     */
    public function validate_product_type_slug( $value, $request ) {
        if ( empty( $value ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid product type slug.', 'mainwp' ) );
        }

        $value         = $this->sanitize_field( $value );
        $all_opts      = Cost_Tracker_Utility::get_instance()->get_all_options();
        $product_types = $this->safe_json_decode( $all_opts['custom_product_types'] ?? '' );

        // Add default product types if is edit.
        if ( in_array( $request->get_method(), array( 'PUT', 'PATCH' ) ) ) {
            $product_types = array_merge( $product_types, Cost_Tracker_Admin::get_default_product_types() );
        }

        if ( ! isset( $product_types[ $value ] ) ) {
            return new WP_Error( 'invalid_slug', __( 'Product type does not exist.', 'mainwp' ) );
        }

        return true;
    }

    /**
     * Validate payment method slug.
     *
     * @param string          $value Payment method slug.
     * @param WP_REST_Request $request Request object.
     *
     * @uses Cost_Tracker_Utility::get_instance()->get_all_options()
     *
     * @return bool|WP_Error
     */
    public function validate_payment_method_slug( $value, $request ) { // phpcs:ignore -- NOSONAR - long method.
        if ( empty( $value ) ) {
            return new WP_Error( 'invalid_slug', __( 'Invalid payment method slug.', 'mainwp' ) );
        }

        $value           = $this->sanitize_field( $value );
        $all_opts        = Cost_Tracker_Utility::get_instance()->get_all_options();
        $payment_methods = $this->safe_json_decode( $all_opts['custom_payment_methods'] ?? '' );
        if ( ! isset( $payment_methods[ $value ] ) ) {
            return new WP_Error( 'invalid_slug', __( 'Payment method does not exist.', 'mainwp' ) );
        }

        return true;
    }

    /**
     * Sanitize mail type.
     *
     * @param string $value Email type.
     *
     * @uses MainWP_Notification_Settings::get_default_emails_fields()
     *
     * @return string|WP_Error
     */
    public function sanitize_email_type( $value ) { // phpcs:ignore -- NOSONAR - long method.
        if ( empty( $value ) ) {
            return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ) );
        }

        // Sanitize email type.
        $value = $this->sanitize_field( $value );

        // Get default email settings.
        $email_setting = MainWP_Notification_Settings::get_default_emails_fields( $value, '', true );
        if ( empty( $email_setting ) ) {
            return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ) );
        }

        return array_merge( $email_setting, array( 'type' => $value ) );
    }

    /**
     * Validate mail type.
     *
     * @param string          $value Email type.
     * @param WP_REST_Request $request Request object.
     *
     * @uses MainWP_Notification_Settings::get_notification_types()
     *
     * @return bool|WP_Error
     */
    public function validate_email_type( $value, $request ) { // phpcs:ignore -- NOSONAR - long method.
        if ( empty( $value ) ) {
            return new WP_Error( 'invalid_mail_type', __( 'Invalid email type.', 'mainwp' ) );
        }

        $value = $this->sanitize_field( $value );
        // Get notification email types.
        $notification_emails = MainWP_Notification_Settings::get_notification_types();

        if ( ! array_key_exists( $value, $notification_emails ) ) {
            return new WP_Error( 'invalid_mail_type', __( 'Email type does not exist.', 'mainwp' ) );
        }

        return true;
    }

    /**
     * Validate frequency daily update.
     *
     * @param int             $value Frequency daily update.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_frequency_daily_update( $value, $request ) {
        if ( '' === $value || null === $value ) {
            return true;
        }

        $int_value = (int) $this->sanitize_field( $value );
        if ( $int_value < 1 || $int_value > 12 ) {
            return new WP_Error( 'invalid_frequency_daily_update', __( 'Invalid frequency daily update. Use 1-12.', 'mainwp' ) );
        }
        return true;
    }

    /**
     * Validate date format.
     *
     * @param string          $value Date format.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_date_format( $value, $request ) {
        if ( empty( $value ) ) {
            return true;
        }

        $value = $this->sanitize_field( $value );
        // No numbers allowed.
        if ( preg_match( '/\d/', $value ) ) {
            return new WP_Error(
                'invalid_date_format_numeric',
                __( 'Invalid date format: should not contain digits. Use format characters like F j, Y.', 'mainwp' ),
            );
        }

        // Allows only valid PHP date() format characters and some basic separators.
        if ( ! preg_match( '/^[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU\-\.,:\/\s\\\\]+$/', $value ) ) {
            return new WP_Error(
                'invalid_date_format',
                __( 'Invalid date format. Use valid PHP date format characters like F j, Y.', 'mainwp' ),
            );
        }

        // Check rendering works.
        $date = date_i18n( $value, time() );
        if ( false === $date || '' === $date ) {
            return new WP_Error(
                'invalid_date_format_render',
                __( 'Invalid or unsupported date format.', 'mainwp' ),
            );
        }

        return true;
    }

    /**
     * Validate time format.
     *
     * @param string $value Time format.
     *
     * @return bool|WP_Error
     */
    public function validate_time_format( $value ) {
        if ( empty( $value ) ) {
            return true;
        }

        $value = $this->sanitize_field( $value );
        // No numbers allowed.
        if ( preg_match( '/\d/', $value ) ) {
            return new WP_Error(
                'invalid_time_format_numeric',
                __( 'Invalid time format: should not contain digits. Use format characters like g:i a.', 'mainwp' ),
            );
        }

        // Allows only valid PHP date() format characters and some basic separators.
        if ( ! preg_match( '/^[gGhHisAa\-\.,:\/\s\\\\]+$/', $value ) ) {
            return new WP_Error(
                'invalid_time_format',
                __( 'Invalid time format. Use valid PHP time format characters like g:i a or H:i.', 'mainwp' ),
            );
        }

        // Check rendering works.
        $time = date_i18n( $value, time() );
        if ( false === $time || '' === $time ) {
            return new WP_Error(
                'invalid_time_format_render',
                __( 'Invalid or unsupported time format.', 'mainwp' ),
            );
        }

        return true;
    }

    /**
     * Sanitize timezone field.
     *
     * @param string $value Timezone.
     *
     * @return string|WP_Error
     */
    public function sanitize_timezone_field( $value ) {
        if ( null === $value || '' === $value ) {
            return '';
        }

        $raw = $this->sanitize_field( $value );

        // Check time UTC eg: "UTC±H", "UTC±H:MM" .
        if ( preg_match( '/^UTC(?:([+-])(0?\d|1[0-4])(?::(00|30))?)?$/i', $raw, $m ) ) {
            $sign    = ( '-' === $m[1] ) ? -1 : 1;
            $hours   = isset( $m[2] ) ? (int) $m[2] : 0;
            $minutes = isset( $m[3] ) ? (int) $m[3] : 0;

            $offset = $sign * ( $hours + ( $minutes / 60.0 ) );
            return round( $offset, 2 );
        }

        $all = timezone_identifiers_list();
        if ( in_array( $raw, $all, true ) ) {
            // Check timezone.
            try {
                $tz = new DateTimeZone( $raw );
            } catch ( Exception $e ) {
                return new WP_Error(
                    'invalid_timezone_string',
                    __( 'Invalid timezone. Use a valid format like "UTC+0" or its equivalent name, e.g. "Europe/London".', 'mainwp' ),
                );
            }

            // Convert to UTC offset.
            $ts = time();
            $dt = new DateTime( '@' . $ts );
            $dt->setTimezone( $tz );
            $offset_seconds = $tz->getOffset( $dt );
            $offset_hours   = $offset_seconds / 3600.0;

            return round( $offset_hours, 2 );
        }

        return new WP_Error(
            'invalid_timezone_string',
            __( 'Invalid timezone. Use a valid format like "UTC+0" or its equivalent name, e.g. "Europe/London".', 'mainwp' ),
        );
    }

    /**
     * Validate timezone.
     *
     * @param string          $value Timezone.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_timezone( $value, $request ) {
        if ( null === $value || '' === $value ) {
            return true;
        }

        $value = $this->sanitize_field( $value );

        // eg: UTC, UTC+0, UTC+0:00, UTC+0:30 ,UTC-0:30 ...
        if ( preg_match( '/^UTC(?:([+-])(0?\d|1[0-4])(?::(00|30))?)?$/i', $value ) ) {
            return true;
        }

        // Get list timezone.
        $valid_timezones = timezone_identifiers_list();

        // Check timezone is valid.
        if ( in_array( $value, $valid_timezones, true ) ) {
            return true;
        }

        return new WP_Error(
            'invalid_timezone_string',
            __( 'Invalid timezone. Use a valid format like UTC+0 or its equivalent name, e.g. "Europe/London".', 'mainwp' ),
        );
    }

    /**
     * Sanitize mainwp widgets.
     *
     * @param array $value MainWP widgets.
     *
     * @return array|WP_Error
     */
    public function sanitize_mainwp_widgets( $value ) { // phpcs:ignore -- NOSONAR - complex.
        if ( ! is_array( $value ) ) {
            return new WP_Error(
                'invalid_mainwp_widgets_type',
                __( 'mainwp_widgets must be an object.', 'mainwp' )
            );
        }

        $existing = get_user_option( 'mainwp_settings_show_widgets', array() );
        if ( ! is_array( $existing ) ) {
            $existing = array();
        }

        // Sanitize field data.
        $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );

        foreach ( $values as $k => $v ) {
            if ( array_key_exists( $k, $existing ) ) {
                $existing[ $k ] = ( 1 === (int) $v ) ? 1 : 0;
            }
        }

        return $existing;
    }

    /**
     * Validate mainwp widgets.
     *
     * @param array           $value MainWP widgets.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_mainwp_widgets( $value, $request ) { // phpcs:ignore -- NOSONAR - complex.
        if ( empty( $value ) ) {
            return true;
        }

        if ( ! is_array( $value ) ) {
            return new WP_Error(
                'invalid_mainwp_widgets_type',
                __( 'mainwp_widgets must be an object.', 'mainwp' ),
            );
        }

        // Sanitize field data.
        $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );

        $widgets = get_user_option( 'mainwp_settings_show_widgets', array() );
        $allowed = array_keys( $widgets );
        $keys    = array_keys( $values );

        $invalid_keys = array_values( array_diff( $keys, $allowed ) );

        if ( ! empty( $invalid_keys ) ) {
            return new WP_Error(
                'invalid_mainwp_widgets_keys',
                sprintf(
                    /* translators: 1: invalid keys, 2: allowed keys */
                    __( 'Invalid widget keys: %1$s. Allowed keys: %2$s.', 'mainwp' ),
                    esc_html( implode( ', ', $invalid_keys ) ),
                    esc_html( implode( ', ', $allowed ) )
                ),
            );
        }

        foreach ( $values as $k => $v ) {
            if ( is_array( $v ) || is_object( $v ) ) {
                return new WP_Error(
                    'invalid_mainwp_widgets_value_type',
                    /* translators: %s: Widget key name */ sprintf( __( 'Value for "%s" must be 0 or 1.', 'mainwp' ), esc_html( $k ) ),
                );
            }
            $int = (int) $v;
            if ( 0 !== $int && 1 !== $int ) {
                return new WP_Error(
                    'invalid_mainwp_widgets_value',
                    /* translators: %s: Widget key name */ sprintf( __( 'Invalid value for "%s". Allowed: 0 or 1.', 'mainwp' ), esc_html( $k ) ),
                );
            }
        }

        return true;
    }

    /**
     * Sanitize uptime monitoring status codes.
     *
     * @param array $value Status codes array.
     *
     * @return array|WP_Error
     */
    public function sanitize_uptime_monitoring_status_codes( $value ) {
        if ( empty( $value ) ) {
            return array();
        }

        if ( ! is_array( $value ) ) {
            return new WP_Error(
                'invalid_status_codes_type',
                __( 'Status codes must be an array.', 'mainwp' )
            );
        }

        // Parse ID list to ensure all values are integers.
        $codes = wp_parse_id_list( $value );

        // Remove duplicates and sort.
        $codes = array_unique( array_map( 'intval', $codes ) );
        sort( $codes );

        return $codes;
    }

    /**
     * Validate uptime monitoring status codes.
     *
     * @param array           $value Status codes array.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_uptime_monitoring_status_codes( $value, $request ) { // phpcs:ignore -- NOSONAR
        if ( empty( $value ) ) {
            return true; // Allow empty array.
        }

        if ( ! is_array( $value ) ) {
            return new WP_Error(
                'invalid_status_codes_type',
                __( 'Status codes must be an array.', 'mainwp' ),
                array( 'status' => 400 )
            );
        }

        // Get valid HTTP status codes.
        $http_error_codes = array_keys( MainWP_Utility::get_http_codes() );
        $status_codes     = wp_parse_id_list( $value );

        // Validate each status code.
        foreach ( $status_codes as $code ) {
            $code_int = (int) $code;
            if ( ! in_array( $code_int, $http_error_codes, true ) ) {
                return new WP_Error(
                    'invalid_status_code',
                    sprintf(
                        /* translators: 1: invalid status code, 2: allowed codes list */
                        __( 'Invalid HTTP status code: %1$d. Allowed codes: %2$s.', 'mainwp' ),
                        $code_int,
                        esc_html( implode( ', ', $http_error_codes ) )
                    ),
                    array( 'status' => 400 )
                );
            }
        }

        return true;
    }

    /**
     * Sanitize sync data.
     *
     * @param array $value Sync data.
     *
     * @return array|WP_Error
     */
    public function sanitize_sync_data( $value ) { // phpcs:ignore -- NOSONAR - complex.
        if ( ! is_array( $value ) ) {
            return new WP_Error(
                'invalid_sync_data_type',
                __( 'Sync data must be an object.', 'mainwp' )
            );
        }

        $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );
        // Sync data.
        $sync_data          = get_option( 'mainwp_settings_sync_data', array() );
        $sync_data_settings = $this->safe_json_decode( $sync_data ?? '' );
        if ( ! is_array( $sync_data_settings ) ) {
            $sync_data_settings = array();
        }

        foreach ( $values as $k => $v ) {
            if ( array_key_exists( $k, $sync_data_settings ) ) {
                $sync_data_settings[ $k ] = ( 1 === (int) $v ) ? 1 : 0;
            }
        }

        return $sync_data_settings;
    }

    /**
     * Validate sync data.
     *
     * @param array           $value Sync data.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_sync_data( $value, $request ) { // phpcs:ignore -- NOSONAR - complex.
        if ( empty( $value ) ) {
            return true;
        }

        if ( ! is_array( $value ) ) {
            return new WP_Error(
                'invalid_sync_data_type',
                __( 'Sync data must be an object.', 'mainwp' )
            );
        }
        // Sanitize field data.
        $values = array_map( 'sanitize_text_field', wp_unslash( $value ) );
        // Sync data.
        $sync_data          = get_option( 'mainwp_settings_sync_data', array() );
        $sync_data_settings = $this->safe_json_decode( $sync_data ?? '' );
        $allowed            = array_keys( $sync_data_settings );
        $keys               = array_keys( $values );
        $invalid_keys       = array_values( array_diff( $keys, $allowed ) );

        if ( ! empty( $invalid_keys ) ) {
            return new WP_Error(
                'invalid_sync_data_type',
                sprintf(
                    /* translators: 1: invalid keys, 2: allowed keys */
                    __( 'Invalid sync data keys: %1$s. Allowed keys: %2$s.', 'mainwp' ),
                    esc_html( implode( ', ', $invalid_keys ) ),
                    esc_html( implode( ', ', $allowed ) )
                ),
            );
        }

        foreach ( $values as $k => $v ) {
            if ( is_array( $v ) || is_object( $v ) ) {
                return new WP_Error(
                    'invalid_sync_data_type',
                    /* translators: %s: Sync data key name */ sprintf( __( 'Value for "%s" must be 0 or 1.', 'mainwp' ), esc_html( $k ) ),
                );
            }
            $int = (int) $v;
            if ( 0 !== $int && 1 !== $int ) {
                return new WP_Error(
                    'invalid_sync_data_type',
                    /* translators: %s: Sync data key name */ sprintf( __( 'Invalid value for "%s". Allowed: 0 or 1.', 'mainwp' ), esc_html( $k ) ),
                );
            }
        }

        return true;
    }

    /**
     * Sanitize time update.
     *
     * @param string $value Time.
     *
     * @return string|WP_Error
     */
    public function sanitize_time_update( $value ) {
        if ( empty( $value ) ) {
            return empty( $value );
        }

        $value = $this->sanitize_field( trim( (string) $value ) );
        if ( ! preg_match( '/^(?:[01]?\d|2[0-3]):[0-5]\d$/', $value ) ) {
            return new WP_Error(
                'invalid_time_update',
                __( 'Invalid time. Use whole hours in 24h format like 0:00, 9:00, 23:00, etc...', 'mainwp' ),
            );
        }

        return $value;
    }

    /**
     * Validate time update.
     *
     * @param string          $value Time.
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_time_update( $value, $request ) {
        if ( empty( $value ) ) {
            return true;
        }

        $value = $this->sanitize_field( trim( (string) $value ) );
        if ( preg_match( '/^(?:[01]?\d|2[0-3]):[0-5]\d$/', $value ) ) {
            return true;
        }

        return new WP_Error(
            'invalid_time_update',
            __( 'Invalid time. Use whole hours in 24h format like 0:00, 9:00, 23:00, etc...', 'mainwp' ),
        );
    }

    /**
     * Validate update general params.
     *
     * @param WP_REST_Request $request Request object.
     *
     * @return bool|WP_Error
     */
    public function validate_update_general_params( $request ) { // phpcs:ignore -- NOSONAR - complex.
        $primary_backup = $request->get_param( 'mainwp_primary_backup' );
        $backup_feature = $request->get_param( 'mainwp_enable_legacy_backup_feature' );

        // Validate mainwp_primary_backup and mainwp_enable_legacy_backup_feature relationship.
        if ( null !== $primary_backup || null !== $backup_feature ) {
            if ( null === $primary_backup ) {
                $primary_backup = get_option( 'mainwp_primaryBackup' );
            }

            if ( null === $backup_feature ) {
                $backup_feature = get_option( 'mainwp_enableLegacyBackupFeature' );
            }

            $primary_backup_value = $primary_backup;
            if ( is_array( $primary_backup ) && isset( $primary_backup['value'] ) ) {
                $primary_backup_value = $primary_backup['value'];
            }

            if ( 'module-api-backups' === $primary_backup_value && ( null !== $backup_feature && '0' !== (string) $backup_feature && 0 !== (int) $backup_feature ) ) {
                // When primary backup is module-api-backups, legacy feature must be 0.
                return new WP_Error(
                    'invalid_backup_config',
                    __( 'When mainwp_primary_backup is "module-api-backups", mainwp_enable_legacy_backup_feature must be disabled (0).', 'mainwp' )
                );
            } elseif ( '' === $primary_backup_value && ( null !== $backup_feature && '1' !== (string) $backup_feature && 1 !== (int) $backup_feature ) ) {
                // When primary backup is not module-api-backups, legacy feature must be 1.
                return new WP_Error(
                    'invalid_backup_config',
                    __( 'When mainwp_primary_backup is not "module-api-backups", mainwp_enable_legacy_backup_feature must be enabled (1).', 'mainwp' )
                );
            }
        }

        return true;
    }

    /**
     * Get request body.
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return array|WP_Error
     */
    private function get_request_body( $request ) {
        // Get request body filed.
        $body = $request->get_body_params();
        if ( ! empty( $body ) && is_array( $body ) ) {
            return $body;
        }

        // Get request body from body.
        $body = $request->get_json_params();
        if ( ! empty( $body ) && is_array( $body ) ) {
            return $body;
        }

        // Get request body from raw.
        $body = $request->get_body();
        if ( ! empty( $body ) && is_string( $body ) ) {
            $body = json_decode( $body, true );
            if ( ! is_array( $body ) ) {
                return array();
            }
            return $body;
        }
        // Return error.
        return new WP_Error(
            'empty_body',
            __( 'Request body is empty.', 'mainwp' ),
        );
    }

    /**
     * Validate content type.
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return bool|WP_Error
     */
    private function validate_content_type( $request ) {
        $content_type = (string) $request->get_header( 'content-type' );
        if ( 'application/json' !== $content_type ) {
            return new WP_Error(
                'invalid_content_type',
                __( 'Invalid content type. Expected application/json.', 'mainwp' ),
            );
        }
        return true;
    }


    /**
     * Get site by id or domain.
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_Error|Object Item.
     */
    public function get_request_item( $request ) {
        $value = $request['id_domain'];
        $by    = 'domain';
        if ( is_numeric( $value ) ) {
            $by = 'id';
        } else {
            $value = urldecode( $value );
        }
        return $this->get_site_by( $by, $value );
    }

    /**
     * Get all websites.
     *
     * @uses MainWP_DB::instance()->get_sites()
     *
     * @return array|WP_Error
     */
    private function get_websites() {
        $websites = MainWP_DB::instance()->get_sites();
        if ( empty( $websites ) ) {
            return new WP_Error(
                'no_website_found',
                __( 'No website found.', 'mainwp' )
            );
        }
        return $websites;
    }

    /**
     * Get website by id.
     *
     * @param int   $website_id Website ID.
     * @param array $process_data Process data.
     *
     * @uses MainWP_DB::instance()->get_website_by_id()
     *
     * @return object|null
     */
    private function get_website_by_id( $website_id, &$process_data ) {
        $website = MainWP_DB::instance()->get_website_by_id( $website_id );
        if ( empty( $website ) ) {
            ++$process_data['failed'];
            ++$process_data['processed'];
            $process_data['errors'][] = array(
                'site_id' => $website_id,
                'error'   => __( 'Website not found.', 'mainwp' ),
            );
            return null;
        }
        return $website;
    }

    /**
     * Get user ID.
     *
     * @return int|WP_Error
     */
    protected function get_user_id() {
        $user_id = get_current_user_id();

        // Validate user ID.
        if ( empty( $user_id ) ) {
            return new WP_Error(
                'invalid_user',
                __( 'User not authenticated.', 'mainwp' ),
            );
        }
        return $user_id;
    }

    /**
     * Cast field value to type.
     *
     * @param mixed  $val  Value to cast.
     * @param string $type Type to cast to.
     *
     * @return mixed
     */
    protected function cast_field_value( $val, $type ) {
        switch ( $type ) {
            case 'int':
                $val = (int) $val;
                break;
            case 'bool':
                $val = (int) ( (bool) $val );
                break;
            case 'array':
                $val = is_array( $val ) ? $val : array();
                break;
            case 'string':
                $val = (string) $val;
                break;
            default:
                break;
        }
        return $val;
    }

    /**
     * Update option if present.
     *
     * @param array  $body        Request body.
     * @param string $key         Key to check.
     * @param string $option_name Option name.
     * @param string $cast        Type to cast to.
     *
     * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
     *
     * @return bool|WP_Error
     */
    protected function update_option_if_present( $body, $key, $option_name, $cast = null ) {
        if ( array_key_exists( $key, $body ) ) {
            $val = $body[ $key ];
            $val = $this->cast_field_value( $val, $cast );
            MainWP_Utility::update_option( $option_name, $val );
            return true;
        }
        // translators: %s: Missing key.
        return new WP_Error( 'missing_key', sprintf( __( 'Missing key %s.', 'mainwp' ), esc_html( $key ) ), );
    }

    /**
     * Format date.
     *
     * @param int    $date Date.
     * @param string $format Date format.
     *
     * @return string
     */
    protected function format_date( int $date, $format = 'F j, Y' ) {
        return gmdate( $format, (int) $date );
    }

    /**
     * Safe json decode.
     *
     * @param mixed $json JSON to decode.
     *
     * @return array
     */
    protected function safe_json_decode( $json ) {
        if ( empty( $json ) ) {
            return array();
        }
        $arr = json_decode( (string) $json, true );
        return is_array( $arr ) ? $arr : array();
    }

    /**
     * Build api data.
     *
     * @uses Api_Backups_3rd_Party::get_cloudways_api_key()
     * @uses Api_Backups_3rd_Party::get_gridpane_api_key()
     * @uses Api_Backups_3rd_Party::get_vultr_api_key()
     * @uses Api_Backups_3rd_Party::get_linode_api_key()
     * @uses Api_Backups_3rd_Party::get_digitalocean_api_key()
     * @uses Api_Backups_3rd_Party::get_cpanel_api_key()
     * @uses Api_Backups_3rd_Party::get_plesk_api_key()
     * @uses Api_Backups_3rd_Party::get_kinsta_api_key()
     *
     * @return array<string,array{
     *   label: string,
     *   enabled_option: string,
     *   options?: array<string,string>,
     *   secrets?: array<string, callable>
     * }>
     */
    protected function get_api_backup_definitions() {
        return array(
            'cloudways'    => array(
                'label'          => 'Cloudways',
                'enabled_option' => 'mainwp_enable_cloudways_api',
                'options'        => array(
                    'account_email' => 'mainwp_cloudways_api_account_email',
                ),
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_cloudways_api_key' ),
                ),
            ),
            'gridpane'     => array(
                'label'          => 'GridPane',
                'enabled_option' => 'mainwp_enable_gridpane_api',
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_gridpane_api_key' ),
                ),
            ),
            'vultr'        => array(
                'label'          => 'Vultr',
                'enabled_option' => 'mainwp_enable_vultr_api',
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_vultr_api_key' ),
                ),
            ),
            'linode'       => array(
                'label'          => 'Akamai (Linode)',
                'enabled_option' => 'mainwp_enable_linode_api',
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_linode_api_key' ),
                ),
            ),
            'digitalocean' => array(
                'label'          => 'DigitalOcean',
                'enabled_option' => 'mainwp_enable_digitalocean_api',
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_digitalocean_api_key' ),
                ),
            ),
            'cpanel'       => array(
                'label'          => 'cPanel (WP Toolkit)',
                'enabled_option' => 'mainwp_enable_cpanel_api',
                'options'        => array(
                    'url'       => 'mainwp_cpanel_url',
                    'site_path' => 'mainwp_cpanel_site_path',
                    'username'  => 'mainwp_cpanel_account_username',
                ),
            ),
            'plesk'        => array(
                'label'          => 'Plesk',
                'enabled_option' => 'mainwp_enable_plesk_api',
                'options'        => array(
                    'url' => 'mainwp_plesk_api_url',
                ),
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_plesk_api_key' ),
                ),
            ),
            'kinsta'       => array(
                'label'          => 'Kinsta',
                'enabled_option' => 'mainwp_enable_kinsta_api',
                'options'        => array(
                    'account_email' => 'mainwp_kinsta_api_account_email',
                    'company_id'    => 'mainwp_kinsta_company_id',
                ),
                'secrets'        => array(
                    'api_key' => array( Api_Backups_3rd_Party::class, 'get_kinsta_api_key' ),
                ),
            ),
        );
    }

    /**
     * Get tool settings data.
     *
     * @uses MainWP_Settings::get_instance()->get_current_user_theme()
     *
     * @return array<string,mixed> Tool settings data.
     */
    protected function get_tool_settings_data() {
        return array(
            'mainwp_theme' => MainWP_Settings::get_instance()->get_current_user_theme(),
            'guided_tours' => get_option( 'mainwp_enable_guided_tours', 0 ),
            'chatbase'     => get_option( 'mainwp_enable_guided_chatbase', 0 ),
            'guided_video' => get_option( 'mainwp_enable_guided_video', 0 ),
        );
    }

    /**
     * Get general settings data.
     *
     * @uses MainWP_Settings_Indicator::get_defaults_value()
     *
     * @return array
     */
    protected function get_general_settings_data() {
        // Default Setting.
        $default_setting = MainWP_Settings_Indicator::get_defaults_value();
        $show_widgets    = get_user_option( 'mainwp_settings_show_widgets', array() );

        // Map settings.
        $gmt_offset = (float) get_option( 'gmt_offset', 0 );
        $tz_sign    = $gmt_offset >= 0 ? '+' : '-';
        $tz_value   = (string) abs( $gmt_offset );
        $tz_string  = sprintf( 'UTC%s%s', $tz_sign, $tz_value );

        // Primary backup.
        $primary_backup = get_option( 'mainwp_primaryBackup' );

        // Get primary backup methods.
        $primary_methods        = array();
        $primary_methods        = apply_filters_deprecated( 'mainwp-getprimarybackup-methods', array( $primary_methods ), '4.0.7.2', 'mainwp_getprimarybackup_methods' );  // @deprecated Use 'mainwp_getprimarybackup_methods' instead. NOSONAR - not IP.
        $primary_backup_methods = apply_filters( 'mainwp_getprimarybackup_methods', $primary_methods );

        if ( ! is_array( $primary_backup_methods ) ) {
            $primary_backup_methods = array();
        }

        // Get selected backup method.
        $backup_method = array_filter(
            $primary_backup_methods,
            function ( $method ) use ( $primary_backup ) {
                return $method['value'] === $primary_backup;
            }
        );

        if ( empty( $backup_method ) ) {
            $backup_method = array(
                'value' => '',
                'title' => 'Native backups',
            );
        }

        $enable_legacy_backup = get_option( 'mainwp_enableLegacyBackupFeature' );
        return array(
            // General settings.
            'time_daily_update'                   => get_option( 'mainwp_timeDailyUpdate', $default_setting['mainwp_timeDailyUpdate'] ),
            'frequency_daily_update'              => (int) get_option( 'mainwp_frequencyDailyUpdate', $default_setting['mainwp_frequencyDailyUpdate'] ),
            'date_format'                         => get_option( 'date_format', $default_setting['date_format'] ),
            'time_format'                         => get_option( 'time_format', $default_setting['time_format'] ),
            'timezone_string'                     => $tz_string,
            'sidebar_position'                    => get_user_option( ' mainwp_sidebarPosition', $default_setting['sidebar_position'] ),
            'hide_update_everything'              => get_option( 'mainwp_hide_update_everything', $default_setting['mainwp_hide_update_everything'] ),
            'mainwp_widgets'                      => $show_widgets,
            'plugin_automatic_daily_update'       => (int) get_option( 'mainwp_pluginAutomaticDailyUpdate', $default_setting['mainwp_pluginAutomaticDailyUpdate'] ),
            'theme_automatic_daily_update'        => (int) get_option( 'mainwp_themeAutomaticDailyUpdate', $default_setting['mainwp_themeAutomaticDailyUpdate'] ),
            'trans_automatic_daily_update'        => (int) get_option( 'mainwp_transAutomaticDailyUpdate', 0 ),
            'automatic_daily_update'              => (int) get_option( 'mainwp_automaticDailyUpdate', $default_setting['mainwp_automaticDailyUpdate'] ),
            'frequency_auto_update'               => get_option( 'mainwp_frequency_AutoUpdate', $default_setting['mainwp_frequency_AutoUpdate'] ),
            'time_auto_update'                    => get_option( 'mainwp_time_AutoUpdate', $default_setting['mainwp_time_AutoUpdate'] ),
            'show_language_updates'               => (int) get_option( 'mainwp_show_language_updates', $default_setting['mainwp_show_language_updates'] ),
            'disable_update_confirmations'        => (int) get_option( 'mainwp_disable_update_confirmations', $default_setting['mainwp_disable_update_confirmations'] ),
            'check_http_response'                 => (int) get_option( 'mainwp_check_http_response', $default_setting['mainwp_check_http_response'] ),
            'check_http_response_method'          => get_option( 'mainwp_check_http_response_method', $default_setting['mainwp_check_http_response_method'] ),
            'backup_before_upgrade'               => (int) get_option( 'mainwp_backup_before_upgrade', $default_setting['mainwp_backup_before_upgrade'] ),
            'backup_before_upgrade_days'          => (int) get_option( 'mainwp_backup_before_upgrade_days', $default_setting['mainwp_backup_before_upgrade_days'] ),
            'numberdays_outdate_plugin_theme'     => (int) get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', $default_setting['mainwp_numberdays_Outdate_Plugin_Theme'] ),
            'dayinweek_auto_update'               => (int) get_option( 'mainwp_dayinweek_AutoUpdate', $default_setting['mainwp_dayinweek_AutoUpdate'] ),
            'dayinmonth_auto_update'              => (int) get_option( 'mainwp_dayinmonth_AutoUpdate', $default_setting['mainwp_dayinmonth_AutoUpdate'] ),
            'delay_autoupdate'                    => (int) get_option( 'mainwp_delay_autoupdate', $default_setting['mainwp_delay_autoupdate'] ),
            'mainwp_primary_backup'               => $backup_method,
            'mainwp_enable_legacy_backup_feature' => $enable_legacy_backup,
            'mainwp_backups_on_server'            => get_option( 'mainwp_backupsOnServer' ),
            'mainwp_backup_on_external_sources'   => get_option( 'mainwp_backupOnExternalSources' ),
            'mainwp_archive_format'               => get_option( 'mainwp_archiveFormat' ),
            'mainwp_notification_on_backup_fail'  => get_option( 'mainwp_notificationOnBackupFail' ),
            'mainwp_notification_on_backup_start' => get_option( 'mainwp_notificationOnBackupStart' ),
            'mainwp_chunked_backup_tasks'         => get_option( 'mainwp_chunkedBackupTasks' ),
        );
    }

    /**
     * Get advanced settings data.
     *
     * @uses MainWP_Settings_Indicator::get_defaults_value()
     * @uses MainWP_System_Utility::get_open_ssl_sign_algos()
     *
     * @return array
     */
    protected function get_advanced_settings_data() {
        // Default Setting.
        $default_setting = MainWP_Settings_Indicator::get_defaults_value();
        // Sync data.
        $sync_data          = get_option( 'mainwp_settings_sync_data', array() );
        $sync_data_settings = $this->safe_json_decode( $sync_data ?? '' );
        // Signature algorithm.
        $sign_algs      = MainWP_System_Utility::get_open_ssl_sign_algos();
        $signature_algo = (int) get_option( 'mainwp_connect_signature_algo', $default_setting['mainwp_connect_signature_algo'] );

        return array(
            'mainwp_maximum_requests'                   => (int) get_option( 'mainwp_maximumRequests', $default_setting['mainwp_maximumRequests'] ),
            'mainwp_minimum_delay'                      => (int) get_option( 'mainwp_minimumDelay', $default_setting['mainwp_minimumDelay'] ),
            'mainwp_maximum_ip_requests'                => (int) get_option( 'mainwp_maximumIPRequests', $default_setting['mainwp_maximumIPRequests'] ),
            'mainwp_minimum_ip_delay'                   => (int) get_option( 'mainwp_minimumIPDelay', $default_setting['mainwp_minimumIPDelay'] ),
            'mainwp_chunksitesnumber'                   => (int) get_option( 'mainwp_chunksitesnumber', 10 ),
            'mainwp_chunksleepinterval'                 => (int) get_option( 'mainwp_chunksleepinterval', 5 ),
            'mainwp_maximum_sync_requests'              => (int) get_option( 'mainwp_maximumSyncRequests', $default_setting['mainwp_maximumSyncRequests'] ),
            'mainwp_maximum_install_update_requests'    => (int) get_option( 'mainwp_maximumInstallUpdateRequests', $default_setting['mainwp_maximum_install_update_requests'] ),
            'mainwp_maximum_uptime_monitoring_requests' => (int) get_option( 'mainwp_maximum_uptime_monitoring_requests', $default_setting['mainwp_maximum_uptime_monitoring_requests'] ),
            'mainwp_optimize'                           => (int) get_option( 'mainwp_optimize', $default_setting['mainwp_optimize'] ),
            'mainwp_wp_cron'                            => (int) get_option( 'mainwp_wp_cron', $default_setting['mainwp_wp_cron'] ),
            'mainwp_ssl_verify_certificate'             => (int) get_option( 'mainwp_sslVerifyCertificate', $default_setting['mainwp_ssl_verify_certificate'] ),
            'mainwp_verify_connection_method'           => (int) get_option( 'mainwp_verify_connection_method', $default_setting['mainwp_verify_connection_method'] ),
            'mainwp_connect_signature_algo'             => isset( $sign_algs[ $signature_algo ] ) ? $sign_algs[ $signature_algo ] : $default_setting['mainwp_connect_signature_algo'],
            'mainwp_force_use_ipv4'                     => (int) get_option( 'mainwp_forceUseIPv4', $default_setting['mainwp_forceUseIPv4'] ),
            'sync_data'                                 => $sync_data_settings,
        );
    }

    /**
     * Get monitoring settings data.
     *
     * @uses MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings()
     * @uses MainWP_Uptime_Monitoring_Edit::get_interval_values()
     * @uses MainWP_Uptime_Monitoring_Edit::get_timeout_values()
     *
     * @return array
     */
    protected function get_monitoring_settings_data() {
        $monitoring_settings = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();

        // Get interval values.
        $interval_values   = MainWP_Uptime_Monitoring_Edit::get_interval_values( false );
        $interval = $monitoring_settings['interval'] ?? 60;
        $interval          = isset( $interval_values[ $interval ] ) ? $interval_values[ $interval ] : $interval_values[60];

        // Get timeout values.
        $timeout_values   = MainWP_Uptime_Monitoring_Edit::get_timeout_values( false );
        $timeout = $monitoring_settings['timeout'] ?? 60;
        $timeout          = isset( $timeout_values[ $timeout ] ) ? $timeout_values[ $timeout ] : $timeout_values[60];

        return array(
            'mainwp_uptime_monitoring_active'          => (int) $monitoring_settings['active'] ?? 0,
            'mainwp_uptime_monitoring_interval'        => $interval,
            'mainwp_uptime_monitoring_method'          => $monitoring_settings['method'] ?? 'head',
            'mainwp_uptime_monitoring_timeout'         => $timeout,
            'mainwp_uptime_monitoring_type'            => $monitoring_settings['type'] ?? 'http',
            'mainwp_uptime_monitoring_up_status_codes' => explode( ',', $monitoring_settings['up_status_codes'] ) ?? array(),
            'mainwp_uptime_monitoring_down_confirmation_check' => (int) $monitoring_settings['maxretries'] ?? 1,
            'mainwp_uptime_monitoring_keyword'         => $monitoring_settings['keyword'] ?? '',
            'mainwp_disable_sites_health_monitoring'   => (int) get_option( 'mainwp_disableSitesHealthMonitoring', 1 ),
            'mainwp_sitehealth_threshold'              => (int) get_option( 'mainwp_sitehealthThreshold', 80 ),
        );
    }

    /**
     * Get the API keys schema, conforming to JSON Schema.
     *
     * @since  5.2
     * @return array
     */
    public function get_item_schema() {  // phpcs:ignore -- NOSONAR - long schema.
        return array(
            '$schema'    => 'http://json-schema.org/draft-04/schema#',
            'title'      => 'settings',
            'type'       => 'object',
            'properties' => array(
                'time_daily_update'                        => array(
                    'type'        => 'string',
                    'description' => __( 'Time for daily updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'frequency_daily_update'                   => array(
                    'type'        => 'integer',
                    'description' => __( 'Frequency of daily updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'date_format'                              => array(
                    'type'        => 'string',
                    'description' => __( 'Date format.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'time_format'                              => array(
                    'type'        => 'string',
                    'description' => __( 'Time format.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'timezone_string'                          => array(
                    'type'        => 'string',
                    'description' => __( 'Timezone string.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'sidebar_position'                         => array(
                    'type'        => 'integer',
                    'description' => __( 'Plugin automatic daily update enabled.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'hide_update_everything'                   => array(
                    'type'        => 'integer',
                    'description' => __( 'Hide update everything.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_widgets'                           => array(
                    'type'        => 'array',
                    'description' => __( 'MainWP widgets.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                    'items'       => array(
                        'type' => 'integer',
                    ),
                ),
                'plugin_automatic_daily_update'            => array(
                    'type'        => 'integer',
                    'description' => __( 'Plugin automatic daily update enabled.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'theme_automatic_daily_update'             => array(
                    'type'        => 'integer',
                    'description' => __( 'Theme automatic daily update enabled.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'trans_automatic_daily_update'             => array(
                    'type'        => 'integer',
                    'description' => __( 'Translation automatic daily update enabled.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'automatic_daily_update'                   => array(
                    'type'        => 'integer',
                    'description' => __( 'Automatic daily update enabled.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'frequency_auto_update'                    => array(
                    'type'        => 'string',
                    'description' => __( 'Frequency of auto updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'time_auto_update'                         => array(
                    'type'        => 'string',
                    'description' => __( 'Time for auto updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'show_language_updates'                    => array(
                    'type'        => 'integer',
                    'description' => __( 'Show language updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'disable_update_confirmations'             => array(
                    'type'        => 'integer',
                    'description' => __( 'Disable update confirmations.', 'mainwp' ),
                    'context'     => array( 'view' ),
                ),
                'check_http_response'                      => array(
                    'type'        => 'integer',
                    'description' => __( 'Check HTTP response after update.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'check_http_response_method'               => array(
                    'type'        => 'string',
                    'description' => __( 'HTTP method for response check.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'backup_before_upgrade'                    => array(
                    'type'        => 'integer',
                    'description' => __( 'Backup before upgrade enabled.', 'mainwp' ),
                    'context'     => array( 'view' ),
                ),
                'backup_before_upgrade_days'               => array(
                    'type'        => 'integer',
                    'description' => __( 'Days to check for backup before upgrade.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'numberdays_outdate_plugin_theme'          => array(
                    'type'        => 'integer',
                    'description' => __( 'Number of days to consider plugin/theme as outdated.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'dayinweek_auto_update'                    => array(
                    'type'        => 'integer',
                    'description' => __( 'Day in week for auto updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'dayinmonth_auto_update'                   => array(
                    'type'        => 'integer',
                    'description' => __( 'Day in month for auto updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'delay_autoupdate'                         => array(
                    'type'        => 'integer',
                    'description' => __( 'Delay for auto updates.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_maximum_requests'                  => array(
                    'type'        => 'integer',
                    'description' => __( 'Maximum requests.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_minimum_delay'                     => array(
                    'type'        => 'integer',
                    'description' => __( 'Minimum delay.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_maximum_ip_requests'               => array(
                    'type'        => 'integer',
                    'description' => __( 'Maximum IP requests.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_minimum_ip_delay'                  => array(
                    'type'        => 'integer',
                    'description' => __( 'Minimum IP delay.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_chunksitesnumber'                  => array(
                    'type'        => 'integer',
                    'description' => __( 'Chunk sites number.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_chunksleepinterval'                => array(
                    'type'        => 'integer',
                    'description' => __( 'Chunk sleep interval.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_maximum_sync_requests'             => array(
                    'type'        => 'integer',
                    'description' => __( 'Maximum sync requests.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_maximum_install_update_requests'   => array(
                    'type'        => 'integer',
                    'description' => __( 'Maximum install and update requests.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_maximum_uptime_monitoring_requests' => array(
                    'type'        => 'integer',
                    'description' => __( 'Maximum uptime monitoring requests.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_optimize'                          => array(
                    'type'        => 'integer',
                    'description' => __( 'Optimize data loading.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_wp_cron'                           => array(
                    'type'        => 'integer',
                    'description' => __( 'Use WP Cron.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_ssl_verify_certificate'            => array(
                    'type'        => 'integer',
                    'description' => __( 'Verify SSL certificate.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_verify_connection_method'          => array(
                    'type'        => 'integer',
                    'description' => __( 'Verify connection method.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_connect_signature_algo'            => array(
                    'type'        => 'integer',
                    'description' => __( 'OpenSSL signature algorithm.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'mainwp_force_use_ipv4'                    => array(
                    'type'        => 'integer',
                    'description' => __( 'Force use IPv4.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                ),
                'sync_data'                                => array(
                    'type'        => 'array',
                    'description' => __( 'Sync data.', 'mainwp' ),
                    'context'     => array( 'advanced_view', 'advanced_edit' ),
                    'items'       => array(
                        'type' => 'string',
                    ),
                ),
                'heading'                                  => array(
                    'type'        => 'string',
                    'description' => __( 'Mail heading.', 'mainwp' ),
                    'context'     => array( 'email_view', 'email_edit' ),
                ),
                'type'                                     => array(
                    'type'        => 'string',
                    'description' => __( 'Type.', 'mainwp' ),
                    'context'     => array( 'email_view' ),
                ),
                'subject'                                  => array(
                    'type'        => 'string',
                    'description' => __( 'Mail subject.', 'mainwp' ),
                    'context'     => array( 'email_view', 'email_edit' ),
                ),
                'recipients'                               => array(
                    'type'        => 'string',
                    'description' => __( 'Recipients.', 'mainwp' ),
                    'context'     => array( 'email_view', 'email_edit' ),
                ),
                'disable'                                  => array(
                    'type'        => 'integer',
                    'description' => __( 'Disable.', 'mainwp' ),
                    'context'     => array( 'email_view', 'email_edit' ),
                ),
                'currency'                                 => array(
                    'type'        => 'string',
                    'description' => __( 'Currency.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                ),
                'currency_position'                        => array(
                    'type'        => 'string',
                    'description' => __( 'Currency position.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                ),
                'thousand_separator'                       => array(
                    'type'        => 'string',
                    'description' => __( 'Thousand separator.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                ),
                'decimal_separator'                        => array(
                    'type'        => 'string',
                    'description' => __( 'Decimal separator.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                ),
                'decimals'                                 => array(
                    'type'        => 'integer',
                    'description' => __( 'Decimals.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                ),
                'product_categories'                       => array(
                    'type'        => 'array',
                    'description' => __( 'Product categories.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                    'items'       => array(
                        'type' => 'object',
                    ),
                ),
                'payment_methods'                          => array(
                    'type'        => 'array',
                    'description' => __( 'Payment methods.', 'mainwp' ),
                    'context'     => array( 'cost_tracker_view' ),
                    'items'       => array(
                        'type' => 'string',
                    ),
                ),
                'enable_insights_logging'                  => array(
                    'type'        => 'integer',
                    'description' => __( 'Enable insights logging.', 'mainwp' ),
                    'context'     => array( 'dashboard_insights_view' ),
                ),
                'api_backups'                              => array(
                    'type'        => 'array',
                    'description' => __( 'API backups.', 'mainwp' ),
                    'context'     => array( 'api_backups_view' ),
                    'items'       => array(
                        'type' => 'object',
                    ),
                ),
                'mainwp_theme'                             => array(
                    'type'        => 'string',
                    'description' => __( 'MainWP theme.', 'mainwp' ),
                    'context'     => array( 'tool_view' ),
                ),
                'guided_tours'                             => array(
                    'type'        => 'integer',
                    'description' => __( 'Usetiful (Interactiive Guides & Tips).', 'mainwp' ),
                    'context'     => array( 'tool_view' ),
                ),
                'chatbase'                                 => array(
                    'type'        => 'integer',
                    'description' => __( 'Chatbase (AI-Powered Chat Support).', 'mainwp' ),
                    'context'     => array( 'tool_view' ),
                ),
                'guided_video'                             => array(
                    'type'        => 'integer',
                    'description' => __( 'Youtube Embeds (Video Tutorials).', 'mainwp' ),
                    'context'     => array( 'tool_view' ),
                ),
                'mainwp_disable_sites_health_monitoring'   => array(
                    'type'        => 'integer',
                    'description' => __( 'Disable sites health monitoring.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_sitehealth_threshold'              => array(
                    'type'        => 'integer',
                    'description' => __( 'Site health threshold.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_active'          => array(
                    'type'        => 'integer',
                    'description' => __( 'Uptime monitoring active.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_interval'        => array(
                    'type'        => 'integer',
                    'description' => __( 'Uptime monitoring interval.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_method'          => array(
                    'type'        => 'string',
                    'description' => __( 'Uptime monitoring method.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_timeout'         => array(
                    'type'        => 'integer',
                    'description' => __( 'Uptime monitoring timeout.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_type'            => array(
                    'type'        => 'string',
                    'description' => __( 'Uptime monitoring type.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_up_status_codes' => array(
                    'type'        => 'array',
                    'description' => __( 'Uptime monitoring up status codes.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_down_confirmation_check' => array(
                    'type'        => 'integer',
                    'description' => __( 'Uptime monitoring down confirmation check.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_uptime_monitoring_keyword'         => array(
                    'type'        => 'string',
                    'description' => __( 'Uptime monitoring keyword.', 'mainwp' ),
                    'context'     => array( 'monitoring_view' ),
                ),
                'mainwp_primary_backup'                    => array(
                    'type'        => 'object',
                    'description' => __( 'Primary backup.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_enable_legacy_backup_feature'      => array(
                    'type'        => 'integer',
                    'description' => __( 'Enable legacy backup feature.', 'mainwp' ),
                    'context'     => array( 'view' ),
                ),
                'mainwp_backups_on_server'                 => array(
                    'type'        => 'integer',
                    'description' => __( 'Backups on server.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_backup_on_external_sources'        => array(
                    'type'        => 'integer',
                    'description' => __( 'Backups on external sources.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_archive_format'                    => array(
                    'type'        => 'string',
                    'description' => __( 'Archive format.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_notification_on_backup_fail'       => array(
                    'type'        => 'integer',
                    'description' => __( 'Notification on backup fail.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_notification_on_backup_start'      => array(
                    'type'        => 'integer',
                    'description' => __( 'Notification on backup start.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
                'mainwp_chunked_backup_tasks'              => array(
                    'type'        => 'integer',
                    'description' => __( 'Chunked backup tasks.', 'mainwp' ),
                    'context'     => array( 'view', 'edit' ),
                ),
            ),
        );
    }
}
