<?php

defined('ABSPATH') or exit('Hey, what are you doing here? You silly human!');

if (! class_exists('Dusky_Ajax')) {
    class Dusky_Ajax
    {
        private static $instance = null;

        public function __construct()
        {
            add_filter('upload_mimes', [$this, 'allow_json_upload']);

            add_action('wp_ajax_dusky_save_settings', [$this, 'dusky_save_settings']);

            add_action('wp_ajax_dusky_get_data', [$this, 'dusky_get_data']);

            add_action('wp_ajax_dusky_import_settings', [$this, 'dusky_import_settings']);
        }

        public function allow_json_upload($mimes)
        {
            $mimes['json'] = 'application/json';
            return $mimes;
        }

        public function dusky_import_settings()
        {
            $nonce = isset($_POST['nonce']) ? sanitize_key(wp_unslash($_POST['nonce'])) : '';

            if (! wp_verify_nonce($nonce, 'dusky_nonce') || ! current_user_can('manage_options')) {
                wp_die("Oops! It seems like you don't have the necessary permissions to perform this action. If you believe this is an error, please contact the site administrator.");
                return false;
            }

            function dusky_sanitize_array($json_data)
            {
                $validated_json_data = [];

                if (is_array($json_data)) {
                    foreach ($json_data as $key => $value) {
                        $sanitized_key = sanitize_text_field($key);

                        if (is_string($value)) {
                            $sanitized_value = sanitize_text_field($value);
                        } elseif (is_array($value)) {
                            // Recursively sanitize nested arrays
                            $sanitized_value = dusky_sanitize_array($value);
                        } elseif (is_bool($value)) {
                            // Use filter_var for boolean validation
                            $sanitized_value = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
                        } elseif (is_numeric($value)) {
                            // Use filter_var for integer validation
                            $sanitized_value = filter_var($value, FILTER_VALIDATE_INT);
                        } else {
                            // For other types, set the sanitized value to null
                            $sanitized_value = null;
                        }

                        // Add the sanitized key-value pair to the result array
                        $validated_json_data[$sanitized_key] = $sanitized_value;
                    }
                }

                return $validated_json_data;
            }

            $json_file_url = isset($_POST['url']) ? esc_url_raw(wp_unslash($_POST['url'])) : '';

            if (filter_var($json_file_url, FILTER_VALIDATE_URL) !== false) {
                $response = wp_remote_get($json_file_url);
                if (is_array($response) && ! is_wp_error($response)) {

                    $body = wp_json_decode($response['body'], true);

                    $imported_data = dusky_sanitize_array($body);

                    if ($imported_data !== null) {
                        // Update the 'dusky_settings' option with the imported data
                        update_option('dusky_settings', $imported_data);

                        $status = ['data' => $imported_data, 'message' => 'Data has been successfully imported'];

                    } else {
                        $status = ['data' => '', 'message' => 'Error: The selected file is not valid JSON data.'];
                    }
                }

                wp_send_json_success($status);
            } else {
                // Handle invalid URL
                wp_send_json_error("Invalid URL provided.");
                wp_die("Invalid URL provided.");
            }
        }

        public function dusky_get_data()
        {
            $dusky_nonce = sanitize_text_field(wp_unslash($_POST['dusky_nonce'] ?? ''));

            if (! wp_verify_nonce($dusky_nonce, 'dusky_nonce') || ! current_user_can('manage_options')) {
                $message = ['message' => __("Oops! It seems like you don't have the necessary permissions to perform this action. If you believe this is an error, please contact the site administrator.", 'dusky-dark-mode')];
                return wp_send_json_error($message, 401);
            }

            $data = isset($_POST['data']) ? sanitize_key(wp_unslash($_POST['data'])) : '';

            if ($data === 'roles') {
                $data = dusky_get_user_roles();
            } elseif ($data === 'menu_slugs') {
                $data = array_map(function ($item) {
                    return [
                        'label' => $item->name,
                        'value' => $item->slug,
                    ];
                }, wp_get_nav_menus());
            } else {
                $data = ['message' =>
                    "No Data Found"];
            }

            wp_send_json_success($data);
        }

        private function validate_and_sanitize($data, $sanitization_callback = null)
        {

            if ((isset($data['input']) || isset($data['checkbox']) || isset($data['adminDarkMode'])) && $sanitization_callback === null) {
                return $this->sanitizeDuskyData($data);
            }

            $sanitized_data = [];
            if ($sanitization_callback === 'sanitize_text_field') {

                $sanitized_data = $this->sanitizeTextAndArray($data, $sanitized_data);

            } elseif ($sanitization_callback === 'checkbox_sanitization_callback') {

                $sanitized_data = $this->sanitize_boolean($data, $sanitized_data);

            }
            return $sanitized_data;
        }

        private function sanitizeDuskyData($data, $_sData = [])
        {
            if (is_array($data)) {
                foreach ($data as $key => $value) {
                    if (is_array($value)) {
                        $_sData[$key] = $this->sanitizeDuskyData($value);
                    } elseif (is_string($value)) {
                        $_sData[$key] = sanitize_text_field(wp_unslash($value));
                    } elseif (is_bool($value)) {
                        $_sData[$key] = filter_var(wp_unslash($value), FILTER_VALIDATE_BOOLEAN);
                    } elseif (is_numeric($value)) {
                        $_sData[$key] = filter_var(wp_unslash($value), FILTER_VALIDATE_INT);
                    } else {
                        $_sData[$key] = null;
                    }
                }
            } elseif (is_string($data)) {
                $_sData = sanitize_text_field(wp_unslash($data));
            } elseif (is_bool($data)) {
                $_sData = filter_var(wp_unslash($data), FILTER_VALIDATE_BOOLEAN);
            } elseif (is_numeric($data)) {
                $_sData = filter_var(wp_unslash($data), FILTER_VALIDATE_INT);
            } else {
                $_sData = null;
            }

            return $_sData;
        }

        private function sanitizeTextAndArray($data, $key)
        {
            if (is_array($data)) {
                foreach ($data as $_key => $value) {
                    if (is_array($value)) {
                        $key[$_key] = $this->sanitizeTextAndArray($value, isset($key[$_key]) && is_array($key[$_key]) ? $key[$_key] : []);
                    } else {
                        $key[$_key] = sanitize_text_field(wp_unslash($value));
                    }
                }
            }

            return $key;
        }

        public function sanitize_boolean($data, $key)
        {
            foreach ($data as $_key => $value) {
                $key[$_key] = filter_var($value, FILTER_VALIDATE_BOOLEAN);
            }
            return $key;
        }

        public function dusky_save_settings()
        {
            $dusky_nonce = isset($_POST['dusky_nonce']) ? sanitize_key(wp_unslash($_POST['dusky_nonce'])) : '';

            if (! wp_verify_nonce($dusky_nonce, 'dusky_nonce') || ! current_user_can('manage_options')) {
                $message = ['message' => __('Unauthorize Request', 'dusky-dark-mode')];
                return wp_send_json_error($message, 401);
            }
            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
            $dusky_settings = isset($_POST['data']) ? $this->validate_and_sanitize(wp_unslash($_POST['data'])) : null;

            $input = $dusky_settings['input'] ?? null;
            $checkbox = $dusky_settings['checkbox'] ?? null;
            $adminDarkMode = $dusky_settings['adminDarkMode'] ?? null;

            $liveEditorData = $dusky_settings['liveEditorData'] ?? null;
            $_dusky_settings = null;
            $_dusky_admin_settings = null;

            // Validation and sanitization functions
            $input_sanitization_callback = 'sanitize_text_field';
            $checkbox_sanitization_callback = 'checkbox_sanitization_callback';

            $editorMode = isset($liveEditorData['editorMode']) ? sanitize_text_field($liveEditorData['editorMode']) : null;
            $pageId = isset($liveEditorData['pageId']) ? sanitize_text_field($liveEditorData['pageId']) : null;

            function DUSKY_validateArrayIndex($array, $key, $default = '')
            {
                return isset($array[$key]) ? $array[$key] : $default;
            }

            if (is_array($adminDarkMode)) {

                $admin_input = [
                    "adminMode"            => DUSKY_validateArrayIndex($adminDarkMode, "adminMode", 'light'),
                    "customToggleSize"     => DUSKY_validateArrayIndex($adminDarkMode, "customToggleSize"),
                    "toggleBottomOffset"   => DUSKY_validateArrayIndex($adminDarkMode, "toggleBottomOffset"),
                    "toggleButton"         => DUSKY_validateArrayIndex($adminDarkMode, "toggleButton"),
                    "toggleCustomPosition" => DUSKY_validateArrayIndex($adminDarkMode, "toggleCustomPosition"),
                    "togglePosition"       => DUSKY_validateArrayIndex($adminDarkMode, "togglePosition"),
                    "toggleSideOffset"     => DUSKY_validateArrayIndex($adminDarkMode, "toggleSideOffset"),
                    "toggleStyle"          => DUSKY_validateArrayIndex($adminDarkMode, "toggleStyle"),
                    "toggleSize"           => DUSKY_validateArrayIndex($adminDarkMode, "toggleSize"),
                ];

                $admin_checkbox = [
                    "adminDark"              => DUSKY_validateArrayIndex($adminDarkMode, "adminDark", true),
                    "blockEditorDarkMode"    => DUSKY_validateArrayIndex($adminDarkMode, "blockEditorDarkMode", false),
                    "classicEditorDarkMode"  => DUSKY_validateArrayIndex($adminDarkMode, "classicEditorDarkMode", false),
                    "flexibleFloatingToggle" => DUSKY_validateArrayIndex($adminDarkMode, "flexibleFloatingToggle", false),
                ];

                $validate_input = (array) $this->validate_and_sanitize($admin_input, $input_sanitization_callback);
                $validate_checkbox = (array) $this->validate_and_sanitize($admin_checkbox, $checkbox_sanitization_callback);

                $_dusky_admin_settings = [
                    'adminDarkMode' => array_merge($validate_input, $validate_checkbox),

                ];

                update_user_meta(get_current_user_id(), 'dusky_admin_settings', $_dusky_admin_settings);
            }

            if (isset($dusky_settings['input']) && isset($dusky_settings['checkbox'])) {

                // Perform validation and sanitization
                $_dusky_settings = [
                    'input'    => $this->validate_and_sanitize($input, $input_sanitization_callback),
                    'checkbox' => $this->validate_and_sanitize($checkbox, $checkbox_sanitization_callback),
                ];
                if ($editorMode === 'current-page' && $pageId) {
                    update_post_meta($pageId, 'dusky_settings', $dusky_settings);
                } else {
                    update_option('dusky_settings', $_dusky_settings);
                }
            }

            wp_send_json_success([$_dusky_settings, $_dusky_admin_settings]);
        }

        public static function instance()
        {

            if (is_null(self::$instance)) {
                self::$instance = new self();
            }
            return self::$instance;
        }
    }
}

Dusky_Ajax::instance();
