<?php

/**
 * Plugin Name: Simple AJAX Product Search for WooCommerce
 * Description: Adds a simple AJAX-powered product search overlay to your WooCommerce store.
 * Version: 1.0
 * Author: TFB Global Ltd
 * Text Domain: simple-ajax-product-search-for-woocommerce
 * Requires at least: 5.5
 * Tested up to: 6.8
 * Requires PHP: 7.4
 * Requires Plugins: woocommerce
 * License: GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
if ( !function_exists( 'sapsfwcIncludeTemplate' ) ) {
    function sapsfwcIncludeTemplate(  string $rel_path, array $vars = []  ) : void {
        $path = plugin_dir_path( __FILE__ ) . 'templates/' . ltrim( $rel_path, '/' );
        if ( !file_exists( $path ) ) {
            return;
        }
        extract( $vars, EXTR_SKIP );
        include $path;
    }

}
if ( !function_exists( 'sapsfwc_uninstall_cleanup' ) ) {
    function sapsfwc_uninstall_cleanup() {
        if ( is_multisite() ) {
            $site_ids = get_sites( [
                'fields' => 'ids',
            ] );
            foreach ( $site_ids as $site_id ) {
                switch_to_blog( $site_id );
                sapsfwc_cleanup_site_data();
                restore_current_blog();
            }
        } else {
            sapsfwc_cleanup_site_data();
        }
    }

}
if ( !function_exists( 'sapsfwc_cleanup_site_data' ) ) {
    function sapsfwc_cleanup_site_data() {
        delete_option( 'sapsfwc_settings' );
        delete_option( 'sapsfwc_css_url' );
        $uploads = wp_upload_dir();
        if ( empty( $uploads['error'] ) ) {
            $dir = trailingslashit( $uploads['basedir'] ) . 'simple-ajax-product-search-for-woocommerce';
            if ( is_dir( $dir ) ) {
                foreach ( ( glob( $dir . '/vars-*.css' ) ?: [] ) as $file ) {
                    if ( is_file( $file ) ) {
                        @unlink( $file );
                    }
                }
                @rmdir( $dir );
            }
        }
    }

}
if ( function_exists( 'sapsfwc_fs' ) ) {
    sapsfwc_fs()->set_basename( false, __FILE__ );
    sapsfwc_fs()->add_action( 'after_uninstall', 'sapsfwc_uninstall_cleanup' );
} else {
    if ( !function_exists( 'sapsfwc_fs' ) ) {
        // Create a helper function for easy SDK access.
        function sapsfwc_fs() {
            global $sapsfwc_fs;
            if ( !isset( $sapsfwc_fs ) ) {
                // Include Freemius SDK.
                require_once dirname( __FILE__ ) . '/vendor/freemius/start.php';
                $sapsfwc_fs = fs_dynamic_init( array(
                    'id'               => '19138',
                    'slug'             => 'simple-ajax-product-search-for-woocommerce',
                    'premium_slug'     => 'simple-ajax-product-search-for-woocommerce-pro',
                    'type'             => 'plugin',
                    'public_key'       => 'pk_cd1b60f2847e4d0045a9affb45ad4',
                    'is_premium'       => false,
                    'premium_suffix'   => 'Pro',
                    'is_org_compliant' => true,
                    'has_addons'       => false,
                    'has_paid_plans'   => true,
                    'trial'            => array(
                        'days'               => 3,
                        'is_require_payment' => false,
                    ),
                    'menu'             => array(
                        'slug'    => 'sapsfwc-settings',
                        'contact' => false,
                        'support' => false,
                    ),
                    'is_live'          => true,
                ) );
            }
            return $sapsfwc_fs;
        }

        // Init Freemius.
        sapsfwc_fs();
        // Signal that SDK was initiated.
        do_action( 'sapsfwc_fs_loaded' );
        sapsfwc_fs()->add_action( 'after_uninstall', 'sapsfwc_uninstall_cleanup' );
    }
    define( 'SAPSFWC_MIN_PHP', '7.4' );
    define( 'SAPSFWC_MENU_SLUG', 'sapsfwc-settings' );
    define( 'SAPSFWC_OPT_SETTINGS', 'sapsfwc_settings' );
    define( 'SAPSFWC_OPT_CSS_URL', 'sapsfwc_css_url' );
    define( 'SAPSFWC_SETTINGS_GROUP', 'sapsfwc_settings_group' );
    define( 'SAPSFWC_NONCE_ACTION', 'sapsfwc_nonce' );
    define( 'SAPSFWC_RESET_NONCE', 'sapsfwc_reset_notice' );
    /**
     * @return bool
     */
    function sapsfwcIsEnvCompatible() : bool {
        $is_wc_active = class_exists( 'WooCommerce' ) || in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins', [] ) ), true ) || array_key_exists( 'woocommerce/woocommerce.php', get_site_option( 'active_sitewide_plugins', [] ) );
        return version_compare( PHP_VERSION, SAPSFWC_MIN_PHP, '>=' ) && $is_wc_active;
    }

    /**
     * @return void
     */
    function sapsfwcAdminNotice() : void {
        if ( !current_user_can( 'activate_plugins' ) ) {
            return;
        }
        $wc_active = class_exists( 'WooCommerce' );
        $min_php = SAPSFWC_MIN_PHP;
        $cur_php = PHP_VERSION;
        sapsfwcIncludeTemplate( 'admin/notices/env-compat.php', compact( 'wc_active', 'min_php', 'cur_php' ) );
    }

    add_action( 'admin_notices', 'sapsfwcAdminNotice' );
    require_once plugin_dir_path( __FILE__ ) . 'blocks/simple-ajax-product-search-toggle/render.php';
    class SAPSFWC_Plugin {
        private string $cssOptionKey = 'sapsfwc_css_url';

        private array $defaults = [
            'logo_url'                            => '',
            'logo_width'                          => 200,
            'logo_height'                         => '',
            'background_color'                    => '#ffffff',
            'z_index'                             => 999,
            'height'                              => 85,
            'body_before_background_color'        => 'rgba(36,36,36,0.5)',
            'body_before_blur'                    => '5px',
            'close_button_width'                  => 45,
            'close_button_height'                 => 45,
            'close_button_border_radius'          => 100,
            'close_button_font_size'              => 32,
            'close_button_color'                  => '#ffffff',
            'close_button_hover_color'            => '#ffffff',
            'close_button_background_color'       => '#242424',
            'close_button_hover_background_color' => '#242424',
            'close_button_transform'              => false,
            'toggle_icon_width'                   => 25,
            'toggle_icon_height'                  => 25,
            'toggle_icon_color'                   => '#242424',
            'toggle_hover_icon_color'             => '#242424',
            'toggle_icon_width_mobile'            => 25,
            'toggle_icon_height_mobile'           => 25,
            'toggle_icon_color_mobile'            => '#242424',
            'shortcode_search_icon_margin_right'  => 0,
            'shortcode_search_icon_width'         => 25,
            'shortcode_search_icon_height'        => 25,
            'shortcode_search_icon_color'         => '#ffffff',
            'shortcode_search_hover_icon_color'   => '#ffffff',
            'shortcode_search_icon_width_mobile'  => 25,
            'shortcode_search_icon_height_mobile' => 25,
            'icon_color'                          => '#242424',
            'icon_hover_color'                    => '#0073aa',
            'container_width'                     => 1000,
            'view_results_font_size'              => 18,
            'view_results_font_weight'            => 600,
            'view_results_color'                  => '#0073aa',
            'view_results_hover_color'            => '#0073aa',
            'no_results_background'               => '#e9e9e9',
            'no_results_color'                    => '#242424',
            'loader_color'                        => '#242424',
            'products_per_page'                   => 6,
            'columns'                             => 3,
            'columns_mobile'                      => 2,
            'load_more_enabled'                   => false,
            'search_field_color'                  => '#242424',
            'search_field_font_size'              => 21,
            'search_field_font_weight'            => 400,
            'search_field_border_color'           => '#ccc',
        ];

        public function __construct() {
            add_action( 'admin_menu', [$this, 'registerAdminMenu'] );
            add_action( 'admin_init', [$this, 'registerSettings'] );
            add_action( 'admin_init', [$this, 'maybeResetSettings'] );
            add_action( 'admin_head-nav-menus.php', [$this, 'sapsfwcRegisterMenuToggleMetabox'] );
            add_filter(
                'walker_nav_menu_start_el',
                [$this, 'sapsfwcRenderMenuToggleLink'],
                999,
                4
            );
            add_action( 'admin_enqueue_scripts', [$this, 'enqueueAdminAssets'] );
            add_action(
                'add_option_sapsfwc_settings',
                function ( $option, $value ) {
                    if ( is_array( $value ) ) {
                        $this->regenerateDynamicCss( null, $value, $option );
                    }
                },
                10,
                2
            );
            add_action(
                'update_option_sapsfwc_settings',
                function ( $old, $new, $option ) {
                    if ( is_array( $new ) ) {
                        $this->regenerateDynamicCss( $old, $new, $option );
                    }
                },
                10,
                3
            );
            add_action( 'wp_enqueue_scripts', [$this, 'enqueueScripts'], 99 );
            add_action( 'wp_footer', [$this, 'renderSearchOverlay'] );
            add_action( 'wp_ajax_sapsfwc_products', [$this, 'ajaxGetProducts'] );
            add_action( 'wp_ajax_nopriv_sapsfwc_products', [$this, 'ajaxGetProducts'] );
            add_action( 'init', [$this, 'registerShortcode'] );
            add_action( 'init', [$this, 'registerBlock'] );
            add_action( 'admin_notices', [$this, 'adminSuccessNotice'] );
        }

        /**
         * @param string $rel_path
         * @param array $vars
         * @param bool $return
         * @return string
         */
        private function tpl( string $rel_path, array $vars = [], bool $return = false ) : string {
            $path = plugin_dir_path( __FILE__ ) . 'templates/' . ltrim( $rel_path, '/' );
            if ( !file_exists( $path ) ) {
                return '';
            }
            extract( $vars, EXTR_SKIP );
            if ( $return ) {
                ob_start();
                include $path;
                return ob_get_clean();
            }
            include $path;
            return '';
        }

        /**
         * @return void
         */
        public function registerBlock() : void {
            register_block_type( __DIR__ . '/blocks/simple-ajax-product-search-toggle', [
                'render_callback' => 'sapsfwc_render_toggle_block',
            ] );
        }

        /**
         * @return void
         */
        public function registerAdminMenu() : void {
            add_menu_page(
                __( 'Simple AJAX Product Search For WooCommerce Settings', 'simple-ajax-product-search-for-woocommerce' ),
                __( 'Simple AJAX Search', 'simple-ajax-product-search-for-woocommerce' ),
                'manage_options',
                SAPSFWC_MENU_SLUG,
                [$this, 'renderSettingsPage'],
                'dashicons-search',
                60
            );
        }

        /**
         * @param $hook
         * @return void
         */
        public function enqueueAdminAssets( $hook ) : void {
            if ( $hook !== 'toplevel_page_' . SAPSFWC_MENU_SLUG ) {
                return;
            }
            wp_enqueue_style( 'wp-color-picker' );
            wp_enqueue_script( 'wp-color-picker' );
            wp_register_script(
                'wp-color-picker-alpha',
                plugin_dir_url( __FILE__ ) . 'assets/js/wp-color-picker-alpha.min.js',
                ['wp-color-picker'],
                '3.0.2',
                true
            );
            wp_enqueue_script( 'wp-color-picker-alpha' );
            wp_enqueue_media();
            wp_register_style(
                'sapsfwc-admin-css',
                plugin_dir_url( __FILE__ ) . 'assets/css/admin-styles.css',
                [],
                '1.0'
            );
            wp_register_script(
                'sapsfwc-admin-js',
                plugin_dir_url( __FILE__ ) . 'assets/js/admin-color-picker.js',
                ['wp-color-picker', 'jquery'],
                '1.0',
                true
            );
            wp_register_script(
                'sapsfwc-admin-settings',
                plugin_dir_url( __FILE__ ) . 'assets/js/admin-settings.js',
                ['jquery'],
                '1.0',
                true
            );
            wp_enqueue_style( 'sapsfwc-admin-css' );
            wp_enqueue_script( 'sapsfwc-admin-js' );
            wp_enqueue_script( 'sapsfwc-admin-settings' );
        }

        /**
         * @return void
         */
        public function registerSettings() : void {
            register_setting( SAPSFWC_SETTINGS_GROUP, SAPSFWC_OPT_SETTINGS, [
                'sanitize_callback' => [$this, 'sanitizeSettings'],
            ] );
            add_settings_section(
                'sapsfwc_section_general',
                __( 'General Settings', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_layout',
                __( 'Layout Settings', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_screen',
                __( 'Open Search Screen Styling', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_close',
                __( 'Close Button Styling', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_toggle',
                __( 'Search Toggle Icon Styling', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_field',
                __( 'Search Field Styling', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_results',
                __( 'Results Styling', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            add_settings_section(
                'sapsfwc_section_shortcode',
                __( 'Search Shortcode Icon Styling', 'simple-ajax-product-search-for-woocommerce' ),
                null,
                SAPSFWC_MENU_SLUG
            );
            $sections = [
                'sapsfwc_section_general'   => [
                    'logo_url'          => [
                        'label' => __( 'Logo (URL)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'logo_width'        => [
                        'label' => __( 'Logo Max Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'logo_height'       => [
                        'label' => __( 'Logo Max Height (optional, px)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'load_more_enabled' => [
                        'label' => __( 'Enable "Load More" Button', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                ],
                'sapsfwc_section_layout'    => [
                    'container_width'   => [
                        'label' => __( 'Container Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'products_per_page' => [
                        'label' => __( 'Products Per Page', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'columns'           => [
                        'label' => __( 'Number of Columns on Desktop (1 - 5)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'columns_mobile'    => [
                        'label' => __( 'Number of Columns on Mobile (1 - 5)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                ],
                'sapsfwc_section_screen'    => [
                    'z_index'                      => __( 'Screen Order', 'simple-ajax-product-search-for-woocommerce' ) . '<br><span class="sapsfwc-help">' . __( 'Increase or decrease this number if elements appear in front or behind the search screen', 'simple-ajax-product-search-for-woocommerce' ) . '</span>',
                    'height'                       => [
                        'label' => __( 'Screen Height (%)', 'simple-ajax-product-search-for-woocommerce' ),
                        'pro'   => true,
                    ],
                    'background_color'             => __( 'Background Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'body_before_background_color' => __( 'Overlay Background Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'body_before_blur'             => __( 'Overlay Blur (px)', 'simple-ajax-product-search-for-woocommerce' ),
                ],
                'sapsfwc_section_close'     => [
                    'close_button_width'                  => __( 'Button Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_height'                 => __( 'Button Height (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_border_radius'          => __( 'Border Radius (%)', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_font_size'              => __( 'Icon Size (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_color'                  => __( 'Icon Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_hover_color'            => __( 'Hover Icon Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_background_color'       => __( 'Background Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_hover_background_color' => __( 'Hover Background Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'close_button_transform'              => __( 'Disable Button Rotation on Hover', 'simple-ajax-product-search-for-woocommerce' ),
                ],
                'sapsfwc_section_toggle'    => [
                    'toggle_icon_width'         => __( 'Icon Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'toggle_icon_height'        => __( 'Icon Height (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'toggle_icon_color'         => __( 'Icon Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'toggle_hover_icon_color'   => __( 'Icon Hover Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'toggle_icon_width_mobile'  => __( 'Mobile Icon Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'toggle_icon_height_mobile' => __( 'Mobile Icon Height (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'toggle_icon_color_mobile'  => __( 'Mobile Icon Colour', 'simple-ajax-product-search-for-woocommerce' ),
                ],
                'sapsfwc_section_field'     => [
                    'search_field_font_size'    => __( 'Font Size (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'search_field_font_weight'  => __( 'Font Weight (100–800)', 'simple-ajax-product-search-for-woocommerce' ),
                    'search_field_color'        => __( 'Text Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'search_field_border_color' => __( 'Border Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'icon_color'                => __( 'Icon Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'icon_hover_color'          => __( 'Icon Hover Colour', 'simple-ajax-product-search-for-woocommerce' ),
                ],
                'sapsfwc_section_results'   => [
                    'view_results_font_size'   => __( 'Link Font Size (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'view_results_font_weight' => __( 'Link Font Weight (100–800)', 'simple-ajax-product-search-for-woocommerce' ),
                    'view_results_color'       => __( 'Link Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'view_results_hover_color' => __( 'Link Hover Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'no_results_background'    => __( 'No Results Background Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'no_results_color'         => __( 'No Results Text Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'loader_color'             => __( 'Animated Loader Colour', 'simple-ajax-product-search-for-woocommerce' ),
                ],
                'sapsfwc_section_shortcode' => [
                    'shortcode_search_icon_margin_right'  => __( 'Icon Right Margin (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'shortcode_search_icon_width'         => __( 'Icon Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'shortcode_search_icon_height'        => __( 'Icon Height (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'shortcode_search_icon_color'         => __( 'Icon Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'shortcode_search_hover_icon_color'   => __( 'Icon Hover Colour', 'simple-ajax-product-search-for-woocommerce' ),
                    'shortcode_search_icon_width_mobile'  => __( 'Mobile Icon Width (px)', 'simple-ajax-product-search-for-woocommerce' ),
                    'shortcode_search_icon_height_mobile' => __( 'Mobile Icon Height (px)', 'simple-ajax-product-search-for-woocommerce' ),
                ],
            ];
            foreach ( $sections as $section_id => $fields ) {
                foreach ( $fields as $field => $data ) {
                    $label = ( is_array( $data ) ? $data['label'] : $data );
                    $isPro = is_array( $data ) && !empty( $data['pro'] );
                    if ( $isPro && !sapsfwc_fs()->can_use_premium_code__premium_only() ) {
                        $label .= sprintf( ' <a href="%s" class="sapsfwc-pro-label">%s</a>', esc_url( sapsfwc_fs()->get_upgrade_url() ), esc_html__( 'Pro', 'simple-ajax-product-search-for-woocommerce' ) );
                    }
                    $label = wp_kses( $label, [
                        'a'    => [
                            'href'  => [],
                            'class' => [],
                        ],
                        'span' => [
                            'class' => [],
                        ],
                        'br'   => [],
                    ] );
                    add_settings_field(
                        'sapsfwc_field_' . $field,
                        $label,
                        [$this, 'renderSettingsField'],
                        SAPSFWC_MENU_SLUG,
                        $section_id,
                        [
                            'field' => $field,
                            'pro'   => $isPro,
                        ]
                    );
                }
            }
        }

        /**
         * @param $args
         * @return void
         */
        public function renderSettingsField( $args ) : void {
            $options = get_option( SAPSFWC_OPT_SETTINGS, [] );
            $field = $args['field'];
            $value = $options[$field] ?? '';
            $default = $this->defaults[$field] ?? '';
            $isPro = !empty( $args['pro'] );
            $isActive = sapsfwc_fs()->can_use_premium_code__premium_only();
            $disabled = ( $isPro && !$isActive ? 'disabled' : '' );
            $isCheckbox = in_array( $field, ['load_more_enabled', 'close_button_transform'], true );
            $showDefault = !$isCheckbox && $default !== '';
            // translators: %s is the default value for this setting
            $defaultLabel = ( $showDefault ? sprintf( '<small class="sapsfwc-default-note">%s %s</small>', esc_html__( 'Default:', 'simple-ajax-product-search-for-woocommerce' ), esc_html( $default ) ) : '' );
            if ( $field === 'logo_url' ) {
                $this->tpl( 'admin/fields/field-logo-url.php', compact(
                    'field',
                    'value',
                    'disabled',
                    'defaultLabel'
                ) );
                return;
            }
            $type = 'text';
            if ( $isCheckbox ) {
                $type = 'checkbox';
            } elseif ( false !== strpos( $field, 'color' ) || false !== strpos( $field, 'background' ) ) {
                $type = 'color';
            }
            if ( $type === 'color' ) {
                $this->tpl( 'admin/fields/field-color.php', [
                    'field'        => $field,
                    'value'        => ( $value !== '' ? $value : $default ),
                    'default'      => $default,
                    'disabled'     => $disabled,
                    'defaultLabel' => $defaultLabel,
                ] );
            } elseif ( $type === 'checkbox' ) {
                $this->tpl( 'admin/fields/field-checkbox.php', [
                    'field'     => $field,
                    'isChecked' => !empty( $value ),
                    'disabled'  => $disabled,
                ] );
            } else {
                $this->tpl( 'admin/fields/field-text.php', [
                    'field'        => $field,
                    'value'        => ( $value !== '' ? $value : $default ),
                    'disabled'     => $disabled,
                    'defaultLabel' => $defaultLabel,
                ] );
            }
        }

        /**
         * @return void
         */
        public function renderSettingsPage() : void {
            $this->tpl( 'admin/settings-page.php', [
                'settings_group' => SAPSFWC_SETTINGS_GROUP,
                'menu_slug'      => SAPSFWC_MENU_SLUG,
            ] );
        }

        /**
         * @param array $settings
         * @return string
         */
        private function buildDynamicCss( array $settings ) : string {
            $int = static fn( $v ) => intval( $v );
            $txt = static fn( $v ) => esc_attr( $v );
            $get = static fn( $k, $d = '' ) => $settings[$k] ?? $d;
            $css = ':root{';
            $css .= '--sapsfwc-background:' . $txt( $get( 'background_color' ) ) . ';';
            $css .= '--sapsfwc-z-index:' . $int( $get( 'z_index' ) ) . ';';
            $css .= '--sapsfwc-body-before-background:' . $txt( $get( 'body_before_background_color' ) ) . ';';
            $css .= '--sapsfwc-body-before-blur:' . $txt( $get( 'body_before_blur' ) ) . ';';
            $css .= '--sapsfwc-close-width:' . $int( $get( 'close_button_width' ) ) . 'px;';
            $css .= '--sapsfwc-close-height:' . $int( $get( 'close_button_height' ) ) . 'px;';
            $css .= '--sapsfwc-close-border-radius:' . $int( $get( 'close_button_border_radius' ) ) . '%;';
            $css .= '--sapsfwc-close-font-size:' . $int( $get( 'close_button_font_size' ) ) . 'px;';
            $css .= '--sapsfwc-close-color:' . $txt( $get( 'close_button_color' ) ) . ';';
            $css .= '--sapsfwc-close-hover-color:' . $txt( $get( 'close_button_hover_color' ) ) . ';';
            $css .= '--sapsfwc-close-background:' . $txt( $get( 'close_button_background_color' ) ) . ';';
            $css .= '--sapsfwc-close-background-hover:' . $txt( $get( 'close_button_hover_background_color' ) ) . ';';
            $css .= '--sapsfwc-field-color:' . $txt( $get( 'search_field_color' ) ) . ';';
            $css .= '--sapsfwc-field-font-size:' . $int( $get( 'search_field_font_size' ) ) . 'px;';
            $css .= '--sapsfwc-field-font-weight:' . $int( $get( 'search_field_font_weight' ) ) . ';';
            $css .= '--sapsfwc-field-border-color:' . $txt( $get( 'search_field_border_color' ) ) . ';';
            $css .= '--sapsfwc-toggle-icon-width:' . $int( $get( 'toggle_icon_width' ) ) . 'px;';
            $css .= '--sapsfwc-toggle-icon-height:' . $int( $get( 'toggle_icon_height' ) ) . 'px;';
            $css .= '--sapsfwc-toggle-icon-color:' . $txt( $get( 'toggle_icon_color' ) ) . ';';
            $css .= '--sapsfwc-toggle-hover-icon-color:' . $txt( $get( 'toggle_hover_icon_color' ) ) . ';';
            $css .= '--sapsfwc-toggle-icon-width-mobile:' . $int( $get( 'toggle_icon_width_mobile' ) ) . 'px;';
            $css .= '--sapsfwc-toggle-icon-height-mobile:' . $int( $get( 'toggle_icon_height_mobile' ) ) . 'px;';
            $css .= '--sapsfwc-toggle-icon-color-mobile:' . $txt( $get( 'toggle_icon_color_mobile' ) ) . ';';
            $css .= '--sapsfwc-shortcode-icon-margin-right:' . $int( $get( 'shortcode_search_icon_margin_right' ) ) . 'px;';
            $css .= '--sapsfwc-shortcode-icon-width:' . $int( $get( 'shortcode_search_icon_width' ) ) . 'px;';
            $css .= '--sapsfwc-shortcode-icon-height:' . $int( $get( 'shortcode_search_icon_height' ) ) . 'px;';
            $css .= '--sapsfwc-shortcode-icon-color:' . $txt( $get( 'shortcode_search_icon_color' ) ) . ';';
            $css .= '--sapsfwc-shortcode-hover-icon-color:' . $txt( $get( 'shortcode_search_hover_icon_color' ) ) . ';';
            $css .= '--sapsfwc-shortcode-icon-width-mobile:' . $int( $get( 'shortcode_search_icon_width_mobile' ) ) . 'px;';
            $css .= '--sapsfwc-shortcode-icon-height-mobile:' . $int( $get( 'shortcode_search_icon_height_mobile' ) ) . 'px;';
            $css .= '--sapsfwc-icon-color:' . $txt( $get( 'icon_color' ) ) . ';';
            $css .= '--sapsfwc-icon-hover-color:' . $txt( $get( 'icon_hover_color' ) ) . ';';
            $css .= '--sapsfwc-scrollbar-thumb: rgba(36,36,36,0.4);';
            $css .= '--sapsfwc-no-results-background:' . $txt( $get( 'no_results_background' ) ) . ';';
            $css .= '--sapsfwc-no-results-color:' . $txt( $get( 'no_results_color' ) ) . ';';
            $css .= '--sapsfwc-view-all-results-color:' . $txt( $get( 'view_results_color' ) ) . ';';
            $css .= '--sapsfwc-view-all-results-font-size:' . $int( $get( 'view_results_font_size' ) ) . 'px;';
            $css .= '--sapsfwc-view-all-results-font-weight:' . $int( $get( 'view_results_font_weight' ) ) . ';';
            $css .= '--sapsfwc-view-all-results-hover-color:' . $txt( $get( 'view_results_hover_color' ) ) . ';';
            $css .= '--sapsfwc-loader-color:' . $txt( $get( 'loader_color' ) ) . ';';
            if ( function_exists( 'sapsfwc_fs' ) && sapsfwc_fs()->can_use_premium_code__premium_only() ) {
                $css .= '--sapsfwc-logo-max-width:' . $int( $get( 'logo_width' ) ) . 'px;';
                $css .= '--sapsfwc-logo-max-height:' . (( !empty( $get( 'logo_height' ) ) ? $int( $get( 'logo_height' ) ) . 'px' : 'auto' )) . ';';
                $css .= '--sapsfwc-container-width:' . $int( $get( 'container_width' ) ) . 'px;';
                $css .= '--sapsfwc-grid-columns:' . $int( $get( 'columns' ) ) . ';';
                $css .= '--sapsfwc-grid-columns-mobile:' . $int( $get( 'columns_mobile' ) ) . ';';
                $css .= '--sapsfwc-height:' . $int( $get( 'height' ) ) . '%;';
            }
            $css .= '}';
            if ( !empty( $settings['close_button_transform'] ) ) {
                $css .= 'button.sapsfwc-close:hover{transform:none!important;}';
            }
            return $css;
        }

        /**
         * @param $oldValue
         * @param null $newValue
         * @param null $option
         * @return void
         */
        public function regenerateDynamicCss( $oldValue, $newValue = null, $option = null ) : void {
            $settings = ( is_array( $newValue ) ? $newValue : (array) get_option( SAPSFWC_OPT_SETTINGS, [] ) );
            $settings = wp_parse_args( $settings, $this->defaults );
            $css = $this->buildDynamicCss( $settings );
            $uploads = wp_upload_dir();
            if ( !empty( $uploads['error'] ) ) {
                return;
            }
            $dir = trailingslashit( $uploads['basedir'] ) . 'simple-ajax-product-search-for-woocommerce';
            if ( !wp_mkdir_p( $dir ) ) {
                return;
            }
            $hash = md5( $css );
            $filename = "vars-{$hash}.css";
            $path = trailingslashit( $dir ) . $filename;
            if ( file_exists( $path ) ) {
                update_option( $this->cssOptionKey, esc_url_raw( trailingslashit( $uploads['baseurl'] ) . "simple-ajax-product-search-for-woocommerce/{$filename}" ) );
                return;
            }
            if ( false === file_put_contents( $path, $css ) ) {
                return;
            }
            foreach ( glob( $dir . '/vars-*.css' ) as $file ) {
                if ( basename( $file ) !== $filename ) {
                    wp_delete_file( $file );
                }
            }
            update_option( $this->cssOptionKey, esc_url_raw( trailingslashit( $uploads['baseurl'] ) . "simple-ajax-product-search-for-woocommerce/{$filename}" ) );
        }

        /**
         * Display the upgrade notice box if not a paying user.
         *
         * @return void
         */
        private function renderUpgradeNoticeBox() : void {
            $this->tpl( 'admin/upgrade-notice.php' );
        }

        /**
         * @return void
         */
        public function maybeResetSettings() : void {
            if ( isset( $_POST['sapsfwc_reset'] ) && current_user_can( 'manage_options' ) ) {
                check_admin_referer( SAPSFWC_SETTINGS_GROUP . '-options' );
                update_option( SAPSFWC_OPT_SETTINGS, $this->defaults );
                wp_safe_redirect( add_query_arg( [
                    'page'     => SAPSFWC_MENU_SLUG,
                    'reset'    => 'true',
                    '_wpnonce' => wp_create_nonce( SAPSFWC_RESET_NONCE ),
                ], admin_url( 'admin.php' ) ) );
                exit;
            }
        }

        /**
         * @return void
         */
        public function enqueueScripts() : void {
            wp_register_style(
                'sapsfwc-css',
                plugin_dir_url( __FILE__ ) . 'assets/css/style.css',
                [],
                '1.0'
            );
            wp_enqueue_style( 'sapsfwc-css' );
            $varsURL = get_option( SAPSFWC_OPT_CSS_URL );
            $current_settings = wp_parse_args( get_option( SAPSFWC_OPT_SETTINGS, [] ), $this->defaults );
            $expected_css = $this->buildDynamicCss( $current_settings );
            $expected_hash = md5( $expected_css );
            if ( !$varsURL || !preg_match( '/vars\\-([a-f0-9]{32})\\.css$/', $varsURL, $m ) || $m[1] !== $expected_hash ) {
                $this->regenerateDynamicCss( null, $current_settings, null );
                $varsURL = get_option( SAPSFWC_OPT_CSS_URL );
            }
            if ( $varsURL ) {
                $ver = null;
                if ( preg_match( '/vars\\-([a-f0-9]{32})\\.css$/', $varsURL, $m ) ) {
                    $ver = $m[1];
                }
                wp_register_style(
                    'sapsfwc-vars',
                    esc_url( $varsURL ),
                    ['sapsfwc-css'],
                    $ver
                );
                wp_enqueue_style( 'sapsfwc-vars' );
            }
            wp_register_script(
                'sapsfwc-js',
                plugin_dir_url( __FILE__ ) . 'assets/js/ajax-search.js',
                ['jquery'],
                '1.0',
                true
            );
            if ( function_exists( 'wp_script_add_data' ) ) {
                wp_script_add_data( 'sapsfwc-js', 'strategy', 'defer' );
            }
            wp_localize_script( 'sapsfwc-js', 'SAPSFWC', [
                'ajaxUrl' => admin_url( 'admin-ajax.php' ),
                'nonce'   => wp_create_nonce( SAPSFWC_NONCE_ACTION ),
                'i18n'    => [
                    'viewAll'   => __( 'View all results', 'simple-ajax-product-search-for-woocommerce' ),
                    'noResults' => __( 'No products found.', 'simple-ajax-product-search-for-woocommerce' ),
                ],
            ] );
            wp_enqueue_script( 'sapsfwc-js' );
        }

        /**
         * @return void
         */
        public function renderSearchOverlay() : void {
            $settings = wp_parse_args( get_option( SAPSFWC_OPT_SETTINGS, [] ), $this->defaults );
            $this->tpl( 'frontend/ajax-search-form.php', [
                'settings' => $settings,
            ] );
        }

        /**
         * @return void
         */
        public function ajaxGetProducts() : void {
            check_ajax_referer( SAPSFWC_NONCE_ACTION, 'security' );
            $settings = wp_parse_args( get_option( SAPSFWC_OPT_SETTINGS, [] ), $this->defaults );
            $isPro = function_exists( 'sapsfwc_fs' ) && sapsfwc_fs()->can_use_premium_code__premium_only();
            $productsPerPage = ( $isPro ? ( isset( $settings['products_per_page'] ) ? intval( $settings['products_per_page'] ) : 6 ) : 6 );
            $search = ( isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '' );
            $paged = ( isset( $_POST['current_page'] ) ? max( 1, absint( $_POST['current_page'] ) ) : 1 );
            $productsPerPage = max( 1, min( 24, $productsPerPage ) );
            $args = [
                'post_type'      => 'product',
                'post_status'    => 'publish',
                'posts_per_page' => $productsPerPage,
                'paged'          => $paged,
                's'              => $search,
            ];
            $query = new WP_Query($args);
            ob_start();
            if ( $query->have_posts() ) {
                $this->tpl( 'frontend/product-grid.php', [
                    'query' => $query,
                ] );
            } else {
                $this->tpl( 'no-results.php', [
                    'search' => $search,
                ] );
            }
            wp_reset_postdata();
            $html = ob_get_clean();
            $totalPages = $query->max_num_pages;
            wp_send_json( [
                'html'        => $html,
                'total_pages' => $totalPages,
            ] );
        }

        /**
         * @return void
         */
        public function registerShortcode() : void {
            add_shortcode( 'sapsfwc_button', [$this, 'sapsfwcRenderButton'] );
        }

        /**
         * @param array $atts
         * @return string
         */
        public function sapsfwcRenderButton( array $atts = [] ) : string {
            $atts = shortcode_atts( [
                'label' => '',
            ], $atts, 'sapsfwc_button' );
            return $this->tpl( 'frontend/shortcode-button.php', [
                'label' => $atts['label'],
            ], true );
        }

        /**
         * @param string $label
         * @return void
         */
        public function sapsfwcButton( string $label = '' ) : void {
            echo do_shortcode( '[sapsfwc_button label="' . esc_attr( $label ) . '"]' );
        }

        /**
         * @return void
         */
        public function sapsfwcRegisterMenuToggleMetabox() : void {
            if ( !current_user_can( 'manage_options' ) ) {
                return;
            }
            add_meta_box(
                'sapsfwc_toggle',
                __( 'Simple AJAX Product Search Toggle', 'simple-ajax-product-search-for-woocommerce' ),
                [$this, 'sapsfwcRenderMenuToggleMetabox'],
                'nav-menus',
                'side',
                'default'
            );
        }

        /**
         * @return void
         */
        public function sapsfwcRenderMenuToggleMetabox() : void {
            $this->tpl( 'admin/menu-toggle-metabox.php' );
        }

        /**
         * @param $item_output
         * @param $item
         * @param $depth
         * @param $args
         * @return string
         */
        public function sapsfwcRenderMenuToggleLink(
            $item_output,
            $item,
            $depth,
            $args
        ) : string {
            if ( isset( $item->url ) && false !== strpos( $item->url, '#sapsfwc-toggle' ) ) {
                $label = ( !empty( $item->title ) ? esc_html( $item->title ) : esc_html__( 'Open product search', 'simple-ajax-product-search-for-woocommerce' ) );
                return $this->tpl( 'frontend/menu-toggle-link.php', [
                    'label' => $label,
                ], true );
            }
            return $item_output;
        }

        /**
         * @param $input
         * @return mixed
         */
        public function sanitizeSettings( $input ) : array {
            $input = ( is_array( $input ) ? $input : [] );
            $input['load_more_enabled'] = ( !empty( $input['load_more_enabled'] ) ? 1 : 0 );
            $input['close_button_transform'] = ( !empty( $input['close_button_transform'] ) ? 1 : 0 );
            if ( isset( $input['logo_url'] ) ) {
                $input['logo_url'] = esc_url_raw( $input['logo_url'] );
            }
            $ints = [
                'logo_width',
                'logo_height',
                'z_index',
                'height',
                'close_button_width',
                'close_button_height',
                'close_button_border_radius',
                'close_button_font_size',
                'toggle_icon_width',
                'toggle_icon_height',
                'toggle_icon_width_mobile',
                'toggle_icon_height_mobile',
                'shortcode_search_icon_margin_right',
                'shortcode_search_icon_width',
                'shortcode_search_icon_height',
                'shortcode_search_icon_width_mobile',
                'shortcode_search_icon_height_mobile',
                'container_width',
                'view_results_font_size',
                'view_results_font_weight',
                'products_per_page',
                'columns',
                'columns_mobile',
                'search_field_font_size',
                'search_field_font_weight'
            ];
            foreach ( $ints as $k ) {
                if ( isset( $input[$k] ) ) {
                    $input[$k] = max( 0, absint( $input[$k] ) );
                }
            }
            if ( isset( $input['columns'] ) ) {
                $input['columns'] = min( max( 1, $input['columns'] ), 5 );
            }
            if ( isset( $input['columns_mobile'] ) ) {
                $input['columns_mobile'] = min( max( 1, $input['columns_mobile'] ), 5 );
            }
            if ( isset( $input['view_results_font_weight'] ) ) {
                $input['view_results_font_weight'] = min( max( 100, $input['view_results_font_weight'] ), 800 );
            }
            if ( isset( $input['search_field_font_weight'] ) ) {
                $input['search_field_font_weight'] = min( max( 100, $input['search_field_font_weight'] ), 800 );
            }
            $colors = [
                'background_color',
                'body_before_background_color',
                'close_button_color',
                'close_button_hover_color',
                'close_button_background_color',
                'close_button_hover_background_color',
                'toggle_icon_color',
                'toggle_hover_icon_color',
                'toggle_icon_color_mobile',
                'shortcode_search_icon_color',
                'shortcode_search_hover_icon_color',
                'icon_color',
                'icon_hover_color',
                'no_results_background',
                'no_results_color',
                'loader_color',
                'view_results_color',
                'view_results_hover_color',
                'search_field_color',
                'search_field_border_color',
                'body_before_blur'
            ];
            foreach ( $colors as $k ) {
                if ( !isset( $input[$k] ) ) {
                    continue;
                }
                $v = trim( $input[$k] );
                if ( $k === 'body_before_blur' ) {
                    $input[$k] = ( preg_match( '/^\\d+(\\.\\d+)?(px)?$/', $v ) ? $v : '5px' );
                } elseif ( preg_match( '/^#([0-9a-fA-F]{3}){1,2}$/', $v ) || preg_match( '/^rgba?\\([\\d\\s.,%]+\\)$/', $v ) ) {
                    $input[$k] = $v;
                } else {
                    $input[$k] = $this->defaults[$k] ?? '';
                }
            }
            foreach ( [
                'load_more_enabled',
                'logo_url',
                'logo_width',
                'logo_height',
                'container_width',
                'products_per_page',
                'columns',
                'columns_mobile'
            ] as $k ) {
                unset($input[$k]);
            }
            return $input;
        }

        /**
         * @return void
         */
        public function adminSuccessNotice() : void {
            if ( !isset( $_GET['page'] ) || $_GET['page'] !== SAPSFWC_MENU_SLUG ) {
                return;
            }
            if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] === 'true' ) {
                $this->tpl( 'admin/notices/success-saved.php' );
            }
            if ( isset( $_GET['reset'], $_GET['_wpnonce'] ) && $_GET['reset'] === 'true' && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), SAPSFWC_RESET_NONCE ) ) {
                $this->tpl( 'admin/notices/success-reset.php' );
            }
        }

    }

    add_action( 'plugins_loaded', function () {
        if ( sapsfwcIsEnvCompatible() ) {
            new SAPSFWC_Plugin();
        }
    } );
}