<?php
namespace BookWellAB;

defined('ABSPATH') || exit;

if (!class_exists('BookWellAB_Settings')) {
    class BookWellAB_Settings
    {
        private static $instance = null;
        private $bookwell_page = 'settings';
        private $bwdb;
        private $bw_wp_nonce;

        /**
         * Label keys managed on the Form Fields admin page (excluded from Booking Form Labels).
         *
         * @return string[]
         */
        public static function get_form_field_managed_label_keys()
        {
            return [
                'first_name',
                'last_name',
                'email',
                'phone',
                'notes',
                'terms_agree_prefix',
                'terms_agree_link',
                'terms_conditions_url',
                'terms_agree_error',
            ];
        }

        /**
         * @param array<string, mixed> $settings Settings array.
         * @return array<string, mixed>
         */
        private function strip_form_field_managed_labels(array $settings)
        {
            if (!isset($settings['labels']) || !is_array($settings['labels'])) {
                return $settings;
            }

            foreach (self::get_form_field_managed_label_keys() as $label_key) {
                unset($settings['labels'][$label_key]);
            }

            return $settings;
        }

        public static function get_instance()
        {
            if (self::$instance === null) {
                self::$instance = new self();
            }
            return self::$instance;
        }

        public function __construct()
        {
            global $BOOKWELLAB;
            $this->bwdb = new BookWellAB_Database();
            $current_page = (isset($BOOKWELLAB) && $BOOKWELLAB instanceof BOOKWELL)
                ? $BOOKWELLAB->get_bookwell_admin_page()
                : '';

            if (is_admin() && $current_page == $this->bookwell_page) {
                add_filter('bookwellab_admin_script_vriable_data', [$this, 'bookwellab_admin_script_vriable_data'], 10, 2);
                add_action('bookwellab_settings_admin_html', [$this, 'bookwellab_settings_admin_html_func'], 10);
                add_filter('bookwellab_page_method_data', [$this, 'bookwellab_page_method_data_func'], 10, 2);
                add_filter('bookwellab_page_mounted_data', [$this, 'bookwellab_page_mounted_data_func'], 10, 2);
                add_action('bookwellab_add_extra_admin_assets', [$this, 'bookwellab_enqueue_settings_inline_styles']);
            }

            add_action('wp_ajax_bookwellab_get_settings', [$this, 'bookwellab_get_settings_func']);
            add_action('wp_ajax_bookwellab_save_settings', [$this, 'bookwellab_save_settings_func']);
            add_action('wp_ajax_bookwellab_reset_appearance_defaults', [$this, 'bookwellab_reset_appearance_defaults_func']);
            add_action('wp_ajax_bookwellab_apply_appearance_theme', [$this, 'bookwellab_apply_appearance_theme_func']);
            add_action('wp_ajax_bookwellab_save_appearance_form_type', [$this, 'bookwellab_save_appearance_form_type_func']);
            add_action('wp_ajax_bookwellab_send_test_email', [$this, 'bookwellab_send_test_email_func']);

            // SMTP Configuration Hook
            add_action('phpmailer_init', [$this, 'bookwellab_configure_smtp']);

            // WordPress Mail From Filters
            add_filter('wp_mail_from', [$this, 'bookwellab_wp_mail_from']);
            add_filter('wp_mail_from_name', [$this, 'bookwellab_wp_mail_from_name']);
        }

        public function bookwellab_wp_mail_from($original_email_address)
        {
            $settings = self::get_settings();
            $from_email = isset($settings['notifications']['from_email']) ? $settings['notifications']['from_email'] : '';
            if (!empty($from_email) && filter_var($from_email, FILTER_VALIDATE_EMAIL)) {
                return $from_email;
            }
            return $original_email_address;
        }

        public function bookwellab_wp_mail_from_name($original_email_from_name)
        {
            $settings = self::get_settings();
            $from_name = isset($settings['notifications']['from_name']) ? $settings['notifications']['from_name'] : '';
            if (!empty($from_name)) {
                return $from_name;
            }
            return $original_email_from_name;
        }

        public function bookwellab_configure_smtp($phpmailer)
        {
            $settings = self::get_settings();
            $notifications = isset($settings['notifications']) ? $settings['notifications'] : [];

            if (isset($notifications['method']) && $notifications['method'] === 'smtp') {
                self::apply_smtp_config_to_phpmailer($phpmailer, $notifications);
            }
        }

        /**
         * Apply SMTP settings to PHPMailer.
         *
         * @param object $phpmailer  PHPMailer instance.
         * @param array  $notifications Notification settings.
         * @param string $from_email Optional override From email.
         * @param string $from_name  Optional override From name.
         * @return void
         */
        private static function apply_smtp_config_to_phpmailer($phpmailer, $notifications, $from_email = '', $from_name = '')
        {
            $smtp_secure = isset($notifications['smtp_secure']) ? (string) $notifications['smtp_secure'] : 'tls';
            $from_email = $from_email !== '' ? $from_email : (isset($notifications['from_email']) ? (string) $notifications['from_email'] : '');
            $from_name = $from_name !== '' ? $from_name : (isset($notifications['from_name']) ? (string) $notifications['from_name'] : '');

            if ($from_email === '' && !empty($notifications['smtp_username'])) {
                $from_email = (string) $notifications['smtp_username'];
            }

            $phpmailer->isSMTP();
            $phpmailer->Host = isset($notifications['smtp_host']) ? (string) $notifications['smtp_host'] : '';
            $phpmailer->SMTPAuth = true;
            $phpmailer->Port = isset($notifications['smtp_port']) ? absint($notifications['smtp_port']) : 587;
            $phpmailer->Username = isset($notifications['smtp_username']) ? (string) $notifications['smtp_username'] : '';
            $phpmailer->Password = isset($notifications['smtp_password']) ? (string) $notifications['smtp_password'] : '';
            $phpmailer->SMTPSecure = ($smtp_secure === 'none') ? '' : $smtp_secure;
            $phpmailer->Timeout = 20;
            $phpmailer->SMTPKeepAlive = false;

            if ($from_email !== '') {
                $phpmailer->From = $from_email;
                $phpmailer->FromName = $from_name;
            }
        }

        /**
         * Sanitize notification settings used for SMTP test sends.
         *
         * @param array $notifications Raw notification settings.
         * @return array
         */
        private static function sanitize_notifications_for_mail_test($notifications)
        {
            if (!is_array($notifications)) {
                return array();
            }

            $sanitized = self::get_instance()->sanitize_settings_for_save(
                array(
                    'notifications' => $notifications,
                )
            );

            return isset($sanitized['notifications']) && is_array($sanitized['notifications'])
                ? $sanitized['notifications']
                : array();
        }

        public function bookwellab_settings_admin_html_func()
        {
            require_once BOOKWELLAB_HTML_PATH . 'settings_view.php';
        }

        public function bookwellab_enqueue_settings_inline_styles()
        {
            $inline_css = '
                .bw-pdf-html-template-textarea .el-textarea__inner:focus,
                .bw-pdf-html-template-textarea .el-textarea__inner:hover,
                .bw-pdf-html-template-textarea.is-focus .el-textarea__inner {
                    border-color: #5700b4 !important;
                    box-shadow: 0 0 0 1px rgba(87, 0, 180, 0.2) !important;
                    outline: none !important;
                }
            ';

            wp_add_inline_style('bookwellab-admin-style', $inline_css);
        }

        /**
         * Default label strings for the frontend customer panel.
         *
         * Stored inside the "customer_panel" settings group so site owners can
         * translate/relabel every string shown in the [bookwellnow_customer_panel] view.
         *
         * @return array<string, string>
         */
        public static function get_customer_panel_label_defaults()
        {
            bookwellab_load_textdomain();

            return [
                'my_bookings' => __('My Bookings', 'bookwellnow-appointment-booking'),
                'my_appointments' => __('My Appointments', 'bookwellnow-appointment-booking'),
                'edit_account' => __('Edit Account', 'bookwellnow-appointment-booking'),
                'change_password' => __('Change Password', 'bookwellnow-appointment-booking'),
                'logout' => __('Logout', 'bookwellnow-appointment-booking'),
                'login_required' => __('Please log in to your account to view your bookings.', 'bookwellnow-appointment-booking'),
                'login_button' => __('Log In', 'bookwellnow-appointment-booking'),
                'login_title' => __('Login', 'bookwellnow-appointment-booking'),
                'login_username' => __('Username', 'bookwellnow-appointment-booking'),
                'login_username_placeholder' => __('Enter your email address', 'bookwellnow-appointment-booking'),
                'login_password' => __('Password', 'bookwellnow-appointment-booking'),
                'login_password_placeholder' => __('Enter your password', 'bookwellnow-appointment-booking'),
                'login_remember' => __('Remember Me', 'bookwellnow-appointment-booking'),
                'login_submit' => __('Login', 'bookwellnow-appointment-booking'),
                'login_lost_password' => __('Lost Your Password', 'bookwellnow-appointment-booking'),
                'login_required_fields' => __('Please enter your username and password.', 'bookwellnow-appointment-booking'),
                'login_failed' => __('Invalid username or password.', 'bookwellnow-appointment-booking'),
                'login_success' => __('Logged in successfully.', 'bookwellnow-appointment-booking'),
                'forgot_title' => __('Forgot Password', 'bookwellnow-appointment-booking'),
                'forgot_username' => __('Username OR Email Address', 'bookwellnow-appointment-booking'),
                'forgot_placeholder' => __('Enter email address', 'bookwellnow-appointment-booking'),
                'forgot_submit' => __('Submit', 'bookwellnow-appointment-booking'),
                'forgot_back' => __('Sign In', 'bookwellnow-appointment-booking'),
                'forgot_required' => __('Please enter your username or email address.', 'bookwellnow-appointment-booking'),
                'forgot_success' => __('A password reset link has been emailed to you.', 'bookwellnow-appointment-booking'),
                'forgot_failed' => __('Unable to send the password reset email. Please check the details and try again.', 'bookwellnow-appointment-booking'),
                'forgot_not_found' => __('No account found with that username or email address.', 'bookwellnow-appointment-booking'),
                'no_customer_record' => __('No customer account is linked to your user. Book an appointment first or contact the site administrator.', 'bookwellnow-appointment-booking'),
                'search_appointments' => __('Search appointments', 'bookwellnow-appointment-booking'),
                'select_date' => __('Please select date', 'bookwellnow-appointment-booking'),
                'apply' => __('Apply', 'bookwellnow-appointment-booking'),
                'id' => __('ID', 'bookwellnow-appointment-booking'),
                'service' => __('Service', 'bookwellnow-appointment-booking'),
                'date' => __('Date', 'bookwellnow-appointment-booking'),
                'status' => __('Status', 'bookwellnow-appointment-booking'),
                'payment' => __('Payment', 'bookwellnow-appointment-booking'),
                'payment_method' => __('Payment Method', 'bookwellnow-appointment-booking'),
                'payment_details' => __('Payment Details', 'bookwellnow-appointment-booking'),
                'total_amount' => __('Total Amount', 'bookwellnow-appointment-booking'),
                'booking_id' => __('Booking ID', 'bookwellnow-appointment-booking'),
                'time' => __('Time', 'bookwellnow-appointment-booking'),
                'book_again' => __('Book Again', 'bookwellnow-appointment-booking'),
                'cancel_appointment' => __('Cancel Appointment', 'bookwellnow-appointment-booking'),
                'cancel_confirm' => __('Are you sure you want to cancel this appointment?', 'bookwellnow-appointment-booking'),
                'yes' => __('Yes', 'bookwellnow-appointment-booking'),
                'no' => __('No', 'bookwellnow-appointment-booking'),
                'no_appointments' => __('No appointments found.', 'bookwellnow-appointment-booking'),
                'first_name' => __('First Name', 'bookwellnow-appointment-booking'),
                'last_name' => __('Last Name', 'bookwellnow-appointment-booking'),
                'email' => __('Email', 'bookwellnow-appointment-booking'),
                'phone' => __('Phone', 'bookwellnow-appointment-booking'),
                'save' => __('Save', 'bookwellnow-appointment-booking'),
                'current_password' => __('Current Password', 'bookwellnow-appointment-booking'),
                'new_password' => __('New Password', 'bookwellnow-appointment-booking'),
                'confirm_password' => __('Confirm Password', 'bookwellnow-appointment-booking'),
                'profile_updated' => __('Profile updated successfully.', 'bookwellnow-appointment-booking'),
                'password_updated' => __('Password updated successfully.', 'bookwellnow-appointment-booking'),
                'cancelled_success' => __('Appointment cancelled successfully.', 'bookwellnow-appointment-booking'),
                'loading' => __('Loading...', 'bookwellnow-appointment-booking'),
                'join_zoom_meeting' => __('Join Zoom Meeting', 'bookwellnow-appointment-booking'),
            ];
        }

        public function get_defaults()
        {
            $defaults = [
                'general' => [
                    'company_name' => get_bloginfo('name'),
                    'company_phone' => '',
                    'company_address' => '',
                    'date_format' => 'Y-m-d',
                    'time_format' => 'h:i a',
                    'week_starts_on' => '1',
                    'default_status' => 'pending',
                    'default_payment_status' => 'pending',
                    'slot_step' => 'service_duration',
                    'booking_status' => 'pending',
                    'default_payment_gateway' => 'offline',
                    'currency_code' => 'USD',
                    'currency_position' => 'before',
                    'default_country' => 'us',
                    'default_phone_code' => '+1',
                    'hide_categories' => false,
                    'hide_staff_step' => false,
                    'show_terms_conditions' => true,
                    'setup_completed' => false,
                    'booking_form_page_id' => 0,
                    'customer_panel_page_id' => 0,
                ],
                'notifications' => [
                    'admin_email' => get_option('admin_email'),
                    'from_name' => get_bloginfo('name'),
                    'from_email' => get_option('admin_email'),
                    'method' => 'wp_mail',
                    'smtp_host' => '',
                    'smtp_port' => '587',
                    'smtp_username' => '',
                    'smtp_password' => '',
                    'smtp_secure' => 'tls'
                ],
                'labels' => [
                    'sidebar_service' => __('Service', 'bookwellnow-appointment-booking'),
                    'sidebar_staff' => __('Staff', 'bookwellnow-appointment-booking'),
                    'sidebar_date_time' => __('Date & Time', 'bookwellnow-appointment-booking'),
                    'sidebar_details' => __('Your Details', 'bookwellnow-appointment-booking'),
                    'sidebar_summary' => __('Summary', 'bookwellnow-appointment-booking'),
                    'service_content_title' => __('Service', 'bookwellnow-appointment-booking'),
                    'staff_content_title' => __('Staff Member', 'bookwellnow-appointment-booking'),
                    'date_content_title' => __('Select Date & Time', 'bookwellnow-appointment-booking'),
                    'details_content_title' => __('Your Details', 'bookwellnow-appointment-booking'),
                    'summary_content_title' => __('Summary & Payment', 'bookwellnow-appointment-booking'),
                    'all_categories' => __('All', 'bookwellnow-appointment-booking'),
                    'no_services' => __('No services found.', 'bookwellnow-appointment-booking'),
                    'select_service' => __('Select Service', 'bookwellnow-appointment-booking'),
                    'time_slot' => __('Time Slot', 'bookwellnow-appointment-booking'),
                    'morning' => __('Morning', 'bookwellnow-appointment-booking'),
                    'afternoon' => __('Afternoon', 'bookwellnow-appointment-booking'),
                    'pick_a_day' => __('Pick a day', 'bookwellnow-appointment-booking'),
                    'loading_slots' => __('Loading slots...', 'bookwellnow-appointment-booking'),
                    'no_slots' => __('No slots available', 'bookwellnow-appointment-booking'),
                    'please_select_date_first' => __('Please select a date first.', 'bookwellnow-appointment-booking'),
                    'payment_method' => __('Payment Method', 'bookwellnow-appointment-booking'),
                    'service_label' => __('Service', 'bookwellnow-appointment-booking'),
                    'staff_label' => __('Staff', 'bookwellnow-appointment-booking'),
                    'date_label' => __('Date', 'bookwellnow-appointment-booking'),
                    'time_label' => __('Time', 'bookwellnow-appointment-booking'),
                    'customer_label' => __('Customer', 'bookwellnow-appointment-booking'),
                    'total_label' => __('Total', 'bookwellnow-appointment-booking'),
                    'confirm_booking' => __('Confirm Booking', 'bookwellnow-appointment-booking'),
                    'appointment_id_label' => __('Appointment ID', 'bookwellnow-appointment-booking'),
                    'booking_confirmed_title' => __('Booking Confirmed', 'bookwellnow-appointment-booking'),
                    'booking_confirmed_msg' => __('Please check your email for details', 'bookwellnow-appointment-booking'),
                    'book_another' => __('Book Another', 'bookwellnow-appointment-booking'),
                    'add_to_calendar' => __('Add to Calendar', 'bookwellnow-appointment-booking'),
                    'google_calendar' => 'Google',
                    'outlook_calendar' => 'Outlook',
                    'ical_calendar' => 'iCal',
                    'next' => __('Continue', 'bookwellnow-appointment-booking'),
                    'back' => __('Back', 'bookwellnow-appointment-booking'),
                    'required_fields_error' => __('Please fill in all required fields marked in red.', 'bookwellnow-appointment-booking'),
                    'select_date_time_error' => __('Please select date and time.', 'bookwellnow-appointment-booking'),
                    'select_service_error' => __('Please select a service to continue.', 'bookwellnow-appointment-booking'),
                    'select_staff_error' => __('Please select a staff member to continue.', 'bookwellnow-appointment-booking'),
                    'invalid_email_error' => __('Please enter a valid email address.', 'bookwellnow-appointment-booking'),
                    'no_staff_available' => __('No staff available for the selected service.', 'bookwellnow-appointment-booking'),
                    'offline_payment' => __('Offline Payment', 'bookwellnow-appointment-booking'),
                    'unexpected_error' => __('An unexpected error occurred. Please try again.', 'bookwellnow-appointment-booking'),
                    'missing_appointment_id' => __('Appointment ID missing.', 'bookwellnow-appointment-booking'),
                    'minute_label' => __('Min', 'bookwellnow-appointment-booking'),
                    'minutes_label' => __('Mins', 'bookwellnow-appointment-booking'),
                    'hour_label' => __('Hour', 'bookwellnow-appointment-booking'),
                    'hours_label' => __('Hours', 'bookwellnow-appointment-booking'),
                    'book_appointment' => __('Book Appointment', 'bookwellnow-appointment-booking'),
                ],
                'payment' => [
                    'enable_offline' => 'yes',
                    'offline_label' => __('Pay on Arrival', 'bookwellnow-appointment-booking'),
                    'enable_manually' => 'yes',
                    'manually_label' => __('Manually', 'bookwellnow-appointment-booking'),
                    'enable_paypal' => 'no',
                    'paypal_active_mode' => 'sandbox',
                    'paypal_sandbox_client_id' => '',
                    'paypal_sandbox_client_secret' => '',
                    'paypal_live_client_id' => '',
                    'paypal_live_client_secret' => '',
                    'paypal_label' => __('PayPal', 'bookwellnow-appointment-booking'),
                ],
                'debug_log' => [
                    'enable_offline_log' => 'no',
                    'enable_paypal_log' => 'no',
                    'enable_email_log' => 'no',
                ],
                'customer_panel' => array_merge(
                    [
                        'create_wp_user_on_booking' => false,
                    ],
                    self::get_customer_panel_label_defaults()
                ),
                'appearance' => [
                    'appearance_theme' => 'default',
                    'form_type' => 'wizard',
                    'hide_description' => false,
                    'show_staff_designation' => false,
                    'primary_color' => '#044343',
                    'font_family' => 'Poppins',
                    'title_color' => '#044343',
                    'detail_text_color' => '#64748b',
                    'title_font_size' => '14',
                    'detail_text_size' => '13',
                    'sidebar_title_color' => '#ffffff',
                    'sidebar_text_color' => '#ffffff',
                    'sidebar_title_size' => '12',
                    'sidebar_text_size' => '10',
                    'section_title_size' => '18',
                    'category_title_color' => '#4C4D55',
                    'category_title_size' => '12',
                    'price_badge_color' => '#FFFFFF',
                    'price_badge_size' => '12',
                    'button_text_color' => '#FFFFFF',
                    'button_font_size' => '14',
                    'subtitle_color' => '#044343',
                    'subtitle_size' => '13',
                    'content_text_color' => '#64748B',
                    'content_text_size' => '12',
                    'panel_bg_color' => '#F8F4F8',
                    'border_color' => '#CACACA',
                    'calendar_title_color' => '#E23535',
                    'calendar_title_size' => '12',
                ],
            ];

            return apply_filters('bookwellab_settings_defaults', $defaults);
        }

        /**
         * Booking form appearance theme presets (colors + sizes; font stays Poppins when applied).
         *
         * @return array<int, array{id: string, label: string, preview: array<string, string>, appearance: array<string, string>}>
         */
        public static function get_appearance_themes()
        {
            $instance = self::get_instance();
            $defaults = $instance->get_defaults();
            $base = isset($defaults['appearance']) && is_array($defaults['appearance']) ? $defaults['appearance'] : [];
            unset(
                $base['font_family'],
                $base['appearance_theme'],
                $base['form_type'],
                $base['hide_description'],
                $base['show_staff_designation']
            );

            $build = static function ($theme_id, $label, $preview, $overrides, $section = 'primary') use ($base) {
                return [
                    'id' => $theme_id,
                    'label' => $label,
                    'section' => $section,
                    'preview' => $preview,
                    'appearance' => array_merge($base, $overrides, ['appearance_theme' => $theme_id]),
                ];
            };

            $themes = [
                $build(
                    'default',
                    __('Default Theme', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#044343',
                        'panel' => '#F8F4F8',
                        'sidebar' => '#044343',
                        'accent' => '#64748b',
                    ],
                    [
                        'primary_color' => '#044343',
                        'title_color' => '#044343',
                        'detail_text_color' => '#64748b',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#ffffff',
                        'category_title_color' => '#4C4D55',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#044343',
                        'content_text_color' => '#64748B',
                        'panel_bg_color' => '#F8F4F8',
                        'border_color' => '#CACACA',
                        'calendar_title_color' => '#E23535',
                    ]
                ),
                $build(
                    'ocean_blue',
                    __('Ocean Blue', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#1565C0',
                        'panel' => '#F8F4F8',
                        'sidebar' => '#0D47A1',
                        'accent' => '#546E7A',
                    ],
                    [
                        'primary_color' => '#1565C0',
                        'title_color' => '#0D47A1',
                        'detail_text_color' => '#546E7A',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#E3F2FD',
                        'category_title_color' => '#37474F',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#1565C0',
                        'content_text_color' => '#607D8B',
                        'panel_bg_color' => '#F8F4F8',
                        'border_color' => '#90CAF9',
                        'calendar_title_color' => '#1976D2',
                    ]
                ),
                $build(
                    'royal_purple',
                    __('Royal Purple', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#7B1FA2',
                        'panel' => '#F8F4F8',
                        'sidebar' => '#6A1B9A',
                        'accent' => '#6B7280',
                    ],
                    [
                        'primary_color' => '#7B1FA2',
                        'title_color' => '#6A1B9A',
                        'detail_text_color' => '#6B7280',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#F3E5F5',
                        'category_title_color' => '#4A148C',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#7B1FA2',
                        'content_text_color' => '#757575',
                        'panel_bg_color' => '#F8F4F8',
                        'border_color' => '#CE93D8',
                        'calendar_title_color' => '#9C27B0',
                    ]
                ),
                $build(
                    'midnight_navy',
                    __('Midnight Navy', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#17295A',
                        'panel' => '#F8F4F8',
                        'sidebar' => '#0F1D42',
                        'accent' => '#5A6B8A',
                    ],
                    [
                        'primary_color' => '#17295A',
                        'title_color' => '#0F1D42',
                        'detail_text_color' => '#5A6B8A',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#E8EDF7',
                        'category_title_color' => '#0A1530',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#17295A',
                        'content_text_color' => '#64748B',
                        'panel_bg_color' => '#F8F4F8',
                        'border_color' => '#A8B8D4',
                        'calendar_title_color' => '#1E4A8C',
                    ]
                ),
                $build(
                    'classic_crimson',
                    __('Classic Crimson', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#840a09',
                        'panel' => '#F8F4F8',
                        'sidebar' => '#5C0707',
                        'accent' => '#7D6B6B',
                    ],
                    [
                        'primary_color' => '#840a09',
                        'title_color' => '#5C0707',
                        'detail_text_color' => '#7D6B6B',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#FAE8E8',
                        'category_title_color' => '#420505',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#840a09',
                        'content_text_color' => '#8B6B6B',
                        'panel_bg_color' => '#F8F4F8',
                        'border_color' => '#D09090',
                        'calendar_title_color' => '#A50D0C',
                    ]
                ),
                $build(
                    'corporate_steel',
                    __('Corporate Steel', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#2B4C7E',
                        'panel' => '#FFFFFF',
                        'sidebar' => '#1E3454',
                        'accent' => '#6B7C93',
                    ],
                    [
                        'primary_color' => '#2B4C7E',
                        'title_color' => '#1E3454',
                        'detail_text_color' => '#6B7C93',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#E8EEF5',
                        'category_title_color' => '#152640',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#2B4C7E',
                        'content_text_color' => '#6B7C93',
                        'panel_bg_color' => '#FFFFFF',
                        'border_color' => '#B8C9DC',
                        'calendar_title_color' => '#3B6BA8',
                    ],
                    'extra'
                ),
                $build(
                    'executive_graphite',
                    __('Executive Graphite', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#3D4F5F',
                        'panel' => '#FFFFFF',
                        'sidebar' => '#2C3A47',
                        'accent' => '#8A96A3',
                    ],
                    [
                        'primary_color' => '#3D4F5F',
                        'title_color' => '#2C3A47',
                        'detail_text_color' => '#8A96A3',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#EEF1F4',
                        'category_title_color' => '#1F2933',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#3D4F5F',
                        'content_text_color' => '#8A96A3',
                        'panel_bg_color' => '#FFFFFF',
                        'border_color' => '#C5CDD5',
                        'calendar_title_color' => '#5A6D7E',
                    ],
                    'extra'
                ),
                $build(
                    'professional_teal',
                    __('Professional Teal', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#0D7C66',
                        'panel' => '#FFFFFF',
                        'sidebar' => '#0A5C4D',
                        'accent' => '#6B8F87',
                    ],
                    [
                        'primary_color' => '#0D7C66',
                        'title_color' => '#0A5C4D',
                        'detail_text_color' => '#6B8F87',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#E6F5F1',
                        'category_title_color' => '#064A3F',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#0D7C66',
                        'content_text_color' => '#6B8F87',
                        'panel_bg_color' => '#FFFFFF',
                        'border_color' => '#A8D4C8',
                        'calendar_title_color' => '#10967D',
                    ],
                    'extra'
                ),
                $build(
                    'burgundy_elite',
                    __('Burgundy Elite', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#6D2E46',
                        'panel' => '#FFFFFF',
                        'sidebar' => '#4F2233',
                        'accent' => '#8C7A82',
                    ],
                    [
                        'primary_color' => '#6D2E46',
                        'title_color' => '#4F2233',
                        'detail_text_color' => '#8C7A82',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#F5ECEF',
                        'category_title_color' => '#3A1826',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#6D2E46',
                        'content_text_color' => '#8C7A82',
                        'panel_bg_color' => '#FFFFFF',
                        'border_color' => '#D4B8C4',
                        'calendar_title_color' => '#8B3A56',
                    ],
                    'extra'
                ),
                $build(
                    'sage_executive',
                    __('Sage Executive', 'bookwellnow-appointment-booking'),
                    [
                        'primary' => '#4A6741',
                        'panel' => '#FFFFFF',
                        'sidebar' => '#354A2E',
                        'accent' => '#7A8F74',
                    ],
                    [
                        'primary_color' => '#4A6741',
                        'title_color' => '#354A2E',
                        'detail_text_color' => '#7A8F74',
                        'sidebar_title_color' => '#ffffff',
                        'sidebar_text_color' => '#EEF3EC',
                        'category_title_color' => '#253520',
                        'price_badge_color' => '#FFFFFF',
                        'button_text_color' => '#FFFFFF',
                        'subtitle_color' => '#4A6741',
                        'content_text_color' => '#7A8F74',
                        'panel_bg_color' => '#FFFFFF',
                        'border_color' => '#B8C9B2',
                        'calendar_title_color' => '#5C7D52',
                    ],
                    'extra'
                ),
            ];

            /**
             * Filter booking form appearance theme presets.
             *
             * @param array<int, array{id: string, label: string, preview: array<string, string>, appearance: array<string, string>}> $themes Theme definitions.
             */
            return apply_filters('bookwellab_appearance_themes', $themes);
        }

        public function bookwellab_admin_script_vriable_data($bookwellab_admin_script_vriable_data, $bookwellpage)
        {
            if ($this->bookwell_page != $bookwellpage) {
                return $bookwellab_admin_script_vriable_data;
            }

            // Fetch settings merged with defaults
            $settings = self::get_settings();

            $bookwellab_admin_script_vriable_data['settings_form'] = $settings;
            if (!isset($bookwellab_admin_script_vriable_data['settings_form']['debug_log']) || !is_array($bookwellab_admin_script_vriable_data['settings_form']['debug_log'])) {
                $bookwellab_admin_script_vriable_data['settings_form']['debug_log'] = [];
            }
            foreach (BookWellAB_Payment_Debug_Log::get_all_log_channels() as $channel) {
                $setting_key = isset($channel['setting_key']) ? (string) $channel['setting_key'] : '';
                if ($setting_key !== '' && !isset($bookwellab_admin_script_vriable_data['settings_form']['debug_log'][$setting_key])) {
                    $bookwellab_admin_script_vriable_data['settings_form']['debug_log'][$setting_key] = 'no';
                }
            }
            $active_tab = 'general';
            $requested_tab = filter_input(INPUT_GET, 'bw_tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
            if (is_string($requested_tab) && $requested_tab !== '') {
                $requested_tab = sanitize_key($requested_tab);
                $allowed_tabs = apply_filters(
                    'bookwellab_settings_allowed_tabs',
                    array('general', 'notifications', 'payment', 'appearance', 'labels', 'customer_panel', 'debug_log')
                );
                if (in_array($requested_tab, $allowed_tabs, true)) {
                    $active_tab = $requested_tab;
                }
            }
            $bookwellab_admin_script_vriable_data['active_tab'] = $active_tab;
            $bookwellab_admin_script_vriable_data['save_loader'] = false;
            $bookwellab_admin_script_vriable_data['test_email_address'] = '';
            $bookwellab_admin_script_vriable_data['test_email_loader'] = false;
            $bookwellab_admin_script_vriable_data['reset_appearance_loader'] = false;
            $bookwellab_admin_script_vriable_data['apply_appearance_theme_loader'] = false;
            $bookwellab_admin_script_vriable_data['applying_appearance_theme_id'] = '';
            $appearance_themes_all = self::get_appearance_themes();
            $bookwellab_admin_script_vriable_data['appearance_themes'] = array_values(array_filter(
                $appearance_themes_all,
                static function ($theme) {
                    return !isset($theme['section']) || $theme['section'] !== 'extra';
                }
            ));
            $bookwellab_admin_script_vriable_data['appearance_extra_themes'] = array_values(array_filter(
                $appearance_themes_all,
                static function ($theme) {
                    return isset($theme['section']) && $theme['section'] === 'extra';
                }
            ));
            $bookwellab_admin_script_vriable_data['appearance_settings_expanded'] = ['customize'];
            $bookwellab_admin_script_vriable_data['currency_list'] = $this->get_currencies();
            $bookwellab_admin_script_vriable_data['paypal_supported_currencies'] = BookWellAB_Paypal::get_supported_currencies();
            $bookwellab_admin_script_vriable_data['country_list'] = $this->get_countries_list();
            $bookwellab_admin_script_vriable_data['phone_code_list'] = $this->get_phone_codes();
            $bookwellab_admin_script_vriable_data['google_fonts'] = self::get_google_fonts();
            $bookwellab_admin_script_vriable_data['wp_timezone'] = wp_timezone_string();
            $bookwellab_admin_script_vriable_data['wp_timezone_url'] = admin_url('options-general.php');
            $bookwellab_admin_script_vriable_data['wp_pages_list'] = $this->get_wp_pages_for_select();

            $bookwellab_label_field_labels = [];
            foreach ($this->get_translatable_setting_sources()['labels'] as $bookwellab_key => $bookwellab_msgid) {
                // English source names for admin captions (values come from settings_form.labels).
                $bookwellab_label_field_labels[$bookwellab_key] = (string) $bookwellab_msgid;
            }
            $bookwellab_admin_script_vriable_data['label_field_labels'] = $bookwellab_label_field_labels;

            $bookwellab_admin_script_vriable_data['debug_log_sections'] = [
                [
                    'id' => 'payment',
                    'title' => __('Payment Debug Logs', 'bookwellnow-appointment-booking'),
                    'channels' => BookWellAB_Payment_Debug_Log::get_gateways(),
                ],
                [
                    'id' => 'email',
                    'title' => __('Email Notification Debug Logs', 'bookwellnow-appointment-booking'),
                    'channels' => [BookWellAB_Payment_Debug_Log::get_email_log_channel()],
                ],
            ];
            $bookwellab_admin_script_vriable_data['debug_log_gateways'] = BookWellAB_Payment_Debug_Log::get_gateways();
            $bookwellab_admin_script_vriable_data['log_download_options'] = BookWellAB_Payment_Debug_Log::get_download_range_options();
            $bookwellab_admin_script_vriable_data['debug_log_modal_visible'] = false;
            $bookwellab_admin_script_vriable_data['debug_log_items'] = [];
            $bookwellab_admin_script_vriable_data['debug_log_gateway'] = '';
            $bookwellab_admin_script_vriable_data['debug_log_gateway_label'] = '';
            $bookwellab_admin_script_vriable_data['debug_log_current_page'] = 1;
            $bookwellab_admin_script_vriable_data['debug_log_per_page'] = BookWellAB_Payment_Debug_Log::LOGS_VIEW_PER_PAGE;
            $bookwellab_admin_script_vriable_data['debug_log_total'] = 0;
            $bookwellab_admin_script_vriable_data['debug_log_view_loading'] = false;
            $bookwellab_admin_script_vriable_data['debug_log_download_loading'] = false;
            $bookwellab_admin_script_vriable_data['debug_log_download_range'] = '1_week';
            $bookwellab_admin_script_vriable_data['debug_log_download_daterange'] = [];
            $bookwellab_admin_script_vriable_data['debug_log_download_gateway'] = '';
            $bookwellab_admin_script_vriable_data['debug_log_download_popover_gateway'] = '';

            return $bookwellab_admin_script_vriable_data;
        }

        /**
         * Google Font for frontend booking form only (Booking Form Appearance).
         *
         * @return string
         */
        public static function get_appearance_font_family()
        {
            $settings = self::get_settings();
            $appearance = isset($settings['appearance']) && is_array($settings['appearance']) ? $settings['appearance'] : [];
            $font_family = isset($appearance['font_family']) ? trim((string) $appearance['font_family']) : '';

            if ($font_family === '') {
                $font_family = 'Poppins';
            }

            if (!in_array($font_family, self::get_google_fonts(), true)) {
                $font_family = 'Poppins';
            }

            return $font_family;
        }

        /**
         * Backend admin font is fixed to locally bundled Poppins.
         *
         * @return string
         */
        public static function get_admin_font_family()
        {
            return 'Poppins';
        }

        /**
         * Alias for drawer/dialog/popup font (same as admin font).
         *
         * @return string
         */
        public static function get_admin_popup_font_family()
        {
            return self::get_admin_font_family();
        }

        public static function get_google_fonts()
        {
            return [
                'Inter',
                'Roboto',
                'Open Sans',
                'Lato',
                'Montserrat',
                'Poppins',
                'Oswald',
                'Raleway',
                'Ubuntu',
                'Nunito',
                'Playfair Display',
                'Merriweather',
                'Lora',
                'PT Sans',
                'PT Serif',
                'Noto Sans',
                'Noto Serif',
                'Kanit',
                'Quicksand',
                'Libre Franklin',
                'Karla',
                'Rubik',
                'Arvo',
                'Josefin Sans',
                'Muli',
                'Work Sans',
                'Fira Sans',
                'Nanum Gothic',
                'Titillium Web',
                'Oxygen',
                'Source Sans Pro',
                'Source Serif Pro',
                'Bebas Neue',
                'Caveat',
                'Dancing Script',
                'Pacifico',
                'Indie Flower',
                'Shadows Into Light',
                'Righteous',
                'Fredoka One',
                'Lobster',
                'Comfortaa',
                'Abril Fatface',
                'Patua One',
                'Cinzel',
                'Exo 2',
                'Archivo Black',
                'Signika',
                'Asap',
                'Prompt',
                'Outfit',
                'Questrial',
                'Antic Slab',
                'Adamina',
                'Alice',
                'Amatic SC',
                'Anton',
                'Assistant',
                'Bangers',
                'Bitter',
                'Cabin',
                'Cairo',
                'Catamaran',
                'Chakra Petch',
                'Cookie',
                'Crimson Text',
                'DM Sans',
                'Domine',
                'Dosis',
                'EB Garamond',
                'Fjalla One',
                'Grechen Fuemen',
                'Heebo',
                'Hind',
                'Inconsolata',
                'Josefin Slab',
                'Jost',
                'Kalam',
                'Kumbh Sans',
                'Lexend',
                'Manrope',
                'Mukta',
                'Nexus',
                'Old Standard TT',
                'Orbitron',
                'Overpass',
                'Oxygen',
                'Pattaya',
                'Permanent Marker',
                'Philosopher',
                'Prata',
                'Press Start 2P',
                'Rajdhani',
                'Rokkitt',
                'Sacramento',
                'Saira',
                'Sarabun',
                'Satisfy',
                'Sniglet',
                'Space Grotesk',
                'Spectral',
                'Teko',
                'Varela Round',
                'Vollkorn',
                'Yanone Kaffeesatz',
                'Zilla Slab'
            ];
        }

        public function bookwellab_page_mounted_data_func($bookwellab_page_mounted_data, $bookwellpage)
        {
            if ($this->bookwell_page != $bookwellpage) {
                return $bookwellab_page_mounted_data;
            }

            // Data is already loaded via hook, but we can verify or re-fetch if needed.
            // For now, simple init.
            return $bookwellab_page_mounted_data;
        }

        public function bookwellab_page_method_data_func($bookwellab_page_method_data, $bookwellpage)
        {
            if ($this->bookwell_page != $bookwellpage) {
                return $bookwellab_page_method_data;
            }

            $this->bw_wp_nonce = esc_html(wp_create_nonce('bw_wp_nonce'));

            $bookwellab_page_method_data .= '
                bwab_onDefaultCountryChange(iso) {
                    const isoLower = String(iso || "").toLowerCase();
                    const match = (this.phone_code_list || []).find(function(item) {
                        return String(item.iso || "").toLowerCase() === isoLower;
                    });
                    if (match) {
                        this.settings_form.general.default_country = isoLower;
                        this.settings_form.general.default_phone_code = match.code;
                    }
                },
                bwab_isPayPalCurrencySupported() {
                    const currency = String((this.settings_form.general && this.settings_form.general.currency_code) || "").toUpperCase();
                    const supported = this.paypal_supported_currencies || [];
                    return supported.indexOf(currency) !== -1;
                },
                bwab_goToWPTimezone() {
                    window.location.href = this.wp_timezone_url;
                },
                bwab_saveSettings() {
                    const vuedata = this;
                    vuedata.save_loader = true;
                    var ajax_url = bookwellab_ajax_obj.ajax_url;
                    
                    var postData = {
                        action: "bookwellab_save_settings",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                        settings: JSON.stringify(vuedata.settings_form)
                    };
                    
                    axios.post(ajax_url, Qs.stringify(postData))
                    .then(function(response) {
                        vuedata.save_loader = false;
                        if(response.data.success) {
                            vuedata.$notify({
                                title: "Success",
                                message: response.data.data.msg || "Settings saved successfully",
                                type: "success",
                                duration: 3000
                            });
                        } else {
                            vuedata.$notify({
                                title: "Error",
                                message: response.data.data.msg || "Failed to save settings",
                                type: "error",
                                duration: 3000
                            });
                        }
                    }).catch(function(error) {
                        console.log(error);
                        vuedata.save_loader = false;
                        vuedata.$notify({
                            title: "Error",
                            message: "An error occurred",
                            type: "error",
                            duration: 3000
                        });
                    });
                },
                bwab_resetAppearanceDefaults() {
                    const vuedata = this;
                    vuedata.reset_appearance_loader = true;
                    var ajax_url = bookwellab_ajax_obj.ajax_url;
                    var postData = {
                        action: "bookwellab_reset_appearance_defaults",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce
                    };
                    axios.post(ajax_url, Qs.stringify(postData))
                    .then(function(response) {
                        vuedata.reset_appearance_loader = false;
                        if (response.data.success) {
                            if (response.data.data && response.data.data.appearance) {
                                vuedata.settings_form.appearance = response.data.data.appearance;
                            }
                            vuedata.$notify({
                                title: "Success",
                                message: response.data.data.msg || "Appearance reset to defaults",
                                type: "success",
                                duration: 3000
                            });
                        } else {
                            vuedata.$notify({
                                title: "Error",
                                message: response.data.data.msg || "Could not reset appearance",
                                type: "error",
                                duration: 3000
                            });
                        }
                    }).catch(function(error) {
                        console.log(error);
                        vuedata.reset_appearance_loader = false;
                        vuedata.$notify({
                            title: "Error",
                            message: "An error occurred",
                            type: "error",
                            duration: 3000
                        });
                    });
                },
                bwab_applyAppearanceTheme(themeId) {
                    const vuedata = this;
                    const themes = (vuedata.appearance_themes || []).concat(vuedata.appearance_extra_themes || []);
                    const theme = themes.find(function(item) {
                        return item.id === themeId;
                    });
                    if (!theme || !theme.appearance) {
                        return;
                    }
                    vuedata.apply_appearance_theme_loader = true;
                    vuedata.applying_appearance_theme_id = themeId;
                    var ajax_url = bookwellab_ajax_obj.ajax_url;
                    var postData = {
                        action: "bookwellab_apply_appearance_theme",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                        theme_id: themeId
                    };
                    axios.post(ajax_url, Qs.stringify(postData))
                    .then(function(response) {
                        vuedata.apply_appearance_theme_loader = false;
                        vuedata.applying_appearance_theme_id = "";
                        if (response.data.success) {
                            if (response.data.data && response.data.data.appearance) {
                                vuedata.settings_form.appearance = response.data.data.appearance;
                            }
                            vuedata.$notify({
                                title: "Success",
                                message: response.data.data.msg || ((theme.label || themeId) + " applied."),
                                type: "success",
                                duration: 3500
                            });
                        } else {
                            vuedata.$notify({
                                title: "Error",
                                message: response.data.data.msg || "Could not apply theme",
                                type: "error",
                                duration: 3000
                            });
                        }
                    }).catch(function(error) {
                        console.log(error);
                        vuedata.apply_appearance_theme_loader = false;
                        vuedata.applying_appearance_theme_id = "";
                        vuedata.$notify({
                            title: "Error",
                            message: "An error occurred",
                            type: "error",
                            duration: 3000
                        });
                    });
                },
                bwab_sendTestEmail() {
                    const vuedata = this;
                    if (!vuedata.test_email_address) {
                        vuedata.$notify({
                            title: "Error",
                            message: "Please enter a test email address",
                            type: "error"
                        });
                        return;
                    }
                    vuedata.test_email_loader = true;
                    var ajax_url = bookwellab_ajax_obj.ajax_url;
                    
                    var postData = {
                        action: "bookwellab_send_test_email",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                        email: vuedata.test_email_address,
                        settings: JSON.stringify(vuedata.settings_form.notifications)
                    };
                    
                    axios.post(ajax_url, Qs.stringify(postData), { timeout: 30000 })
                    .then(function(response) {
                        vuedata.test_email_loader = false;
                        if(response.data.success) {
                            vuedata.$notify({
                                title: "Success",
                                message: response.data.data.msg,
                                type: "success"
                            });
                        } else {
                            vuedata.$notify({
                                title: "Error",
                                message: response.data.data.msg,
                                type: "error"
                            });
                        }
                    }).catch(function(error) {
                        console.log(error);
                        vuedata.test_email_loader = false;
                        var errMsg = "An error occurred while sending test email";
                        if (error.code === "ECONNABORTED") {
                            errMsg = "SMTP connection timed out. Check host, port (465=SSL, 587=TLS), and that your server allows outbound SMTP.";
                        } else if (error.response && error.response.data && error.response.data.data && error.response.data.data.msg) {
                            errMsg = error.response.data.data.msg;
                        }
                        vuedata.$notify({
                            title: "Error",
                            message: errMsg,
                            type: "error"
                        });
                    });
                },
                bwab_viewPaymentDebugLog(gateway, gatewayLabel, page) {
                    const vuedata = this;
                    const targetPage = page || 1;
                    vuedata.debug_log_gateway = gateway;
                    vuedata.debug_log_gateway_label = gatewayLabel || gateway;
                    vuedata.debug_log_current_page = targetPage;
                    vuedata.debug_log_modal_visible = true;
                    vuedata.debug_log_view_loading = true;

                    axios.post(bookwellab_ajax_obj.ajax_url, Qs.stringify({
                        action: "bookwellab_get_payment_debug_logs",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                        gateway: gateway,
                        page: targetPage,
                        per_page: vuedata.debug_log_per_page || 10
                    })).then(function(response) {
                        vuedata.debug_log_view_loading = false;
                        if (response.data.success) {
                            vuedata.debug_log_items = response.data.data.items || [];
                            vuedata.debug_log_total = response.data.data.total || 0;
                        } else {
                            vuedata.debug_log_items = [];
                            vuedata.debug_log_total = 0;
                            vuedata.$notify({
                                title: "Error",
                                message: (response.data.data && response.data.data.msg) ? response.data.data.msg : "Unable to load debug logs",
                                type: "error"
                            });
                        }
                    }).catch(function(error) {
                        console.log(error);
                        vuedata.debug_log_view_loading = false;
                        vuedata.$notify({
                            title: "Error",
                            message: "Unable to load debug logs",
                            type: "error"
                        });
                    });
                },
                bwab_debugLogPageChange(page) {
                    if (!this.debug_log_gateway) {
                        return;
                    }
                    this.bwab_viewPaymentDebugLog(this.debug_log_gateway, this.debug_log_gateway_label, page);
                },
                bwab_clearPaymentDebugLog(gateway) {
                    const vuedata = this;
                    axios.post(bookwellab_ajax_obj.ajax_url, Qs.stringify({
                        action: "bookwellab_clear_payment_debug_logs",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                        gateway: gateway
                    })).then(function(response) {
                        if (response.data.success) {
                            vuedata.$notify({
                                title: "Success",
                                message: response.data.data.msg || "Debug logs cleared successfully.",
                                type: "success"
                            });
                            if (vuedata.debug_log_gateway === gateway && vuedata.debug_log_modal_visible) {
                                vuedata.bwab_viewPaymentDebugLog(gateway, vuedata.debug_log_gateway_label, 1);
                            }
                        } else {
                            vuedata.$notify({
                                title: "Error",
                                message: (response.data.data && response.data.data.msg) ? response.data.data.msg : "Unable to clear debug logs",
                                type: "error"
                            });
                        }
                    }).catch(function(error) {
                        console.log(error);
                        vuedata.$notify({
                            title: "Error",
                            message: "Unable to clear debug logs",
                            type: "error"
                        });
                    });
                },
                bwab_openPaymentDebugLogDownloadPopover(gateway) {
                    const vuedata = this;
                    vuedata.debug_log_download_popover_gateway = gateway || "";
                    vuedata.debug_log_download_gateway = gateway || "";
                    vuedata.debug_log_download_range = "1_week";
                    vuedata.debug_log_download_daterange = [];
                },
                bwab_closePaymentDebugLogDownloadPopover() {
                    this.debug_log_download_popover_gateway = "";
                },
                bwab_downloadPaymentDebugLog(gateway) {
                    const vuedata = this;
                    vuedata.debug_log_download_gateway = gateway || "";
                    vuedata.debug_log_download_loading = true;

                    const form = document.createElement("form");
                    form.method = "POST";
                    form.action = bookwellab_ajax_obj.ajax_url;
                    form.style.display = "none";

                    const fields = {
                        action: "bookwellab_download_payment_debug_logs",
                        _wpnonce: bookwellab_ajax_obj.bookwellab_nonce,
                        gateway: gateway,
                        range: vuedata.debug_log_download_range || "1_week"
                    };

                    if (vuedata.debug_log_download_range === "custom" && Array.isArray(vuedata.debug_log_download_daterange)) {
                        fields.custom_from = vuedata.debug_log_download_daterange[0] || "";
                        fields.custom_to = vuedata.debug_log_download_daterange[1] || "";
                    }

                    Object.keys(fields).forEach(function(key) {
                        const input = document.createElement("input");
                        input.type = "hidden";
                        input.name = key;
                        input.value = fields[key];
                        form.appendChild(input);
                    });

                    document.body.appendChild(form);
                    form.submit();
                    document.body.removeChild(form);

                    setTimeout(function() {
                        vuedata.debug_log_download_loading = false;
                    }, 1200);
                },
            ';

            return $bookwellab_page_method_data;
        }

        public function bookwellab_get_settings_func()
        {
            if (!\BookWellAB\BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }

            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            // Fetch settings merged with defaults
            $settings = self::get_settings();

            wp_send_json_success(['settings' => $settings]);
        }

        public function bookwellab_reset_appearance_defaults_func()
        {
            if (!\BookWellAB\BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }

            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            $defaults = $this->get_defaults();
            $appearance = isset($defaults['appearance']) && is_array($defaults['appearance']) ? $defaults['appearance'] : [];
            if (empty($appearance)) {
                wp_send_json_error(['msg' => esc_html__('Appearance defaults not found.', 'bookwellnow-appointment-booking')]);
            }

            $appearance['appearance_theme'] = 'default';
            $appearance['font_family'] = 'Poppins';

            $sanitized = $this->sanitize_settings_for_save(array('appearance' => $appearance));
            $appearance_sanitized = isset($sanitized['appearance']) && is_array($sanitized['appearance'])
                ? $sanitized['appearance']
                : $appearance;

            $this->bwdb->update_settings_by_type('appearance', $appearance_sanitized);

            self::clear_frontend_cache();

            $merged = self::get_settings();

            wp_send_json_success([
                'msg' => esc_html__('Booking form appearance was reset to defaults.', 'bookwellnow-appointment-booking'),
                'appearance' => isset($merged['appearance']) ? $merged['appearance'] : $appearance_sanitized,
            ]);
        }

        public function bookwellab_apply_appearance_theme_func()
        {
            if (!\BookWellAB\BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }

            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            $theme_id = sanitize_key(BookWellAB_Input::get_post_string('theme_id'));
            if ($theme_id === '') {
                wp_send_json_error(['msg' => esc_html__('Invalid theme.', 'bookwellnow-appointment-booking')]);
            }

            $theme = null;
            foreach (self::get_appearance_themes() as $item) {
                if (isset($item['id']) && $item['id'] === $theme_id) {
                    $theme = $item;
                    break;
                }
            }

            if (!$theme || empty($theme['appearance']) || !is_array($theme['appearance'])) {
                wp_send_json_error(['msg' => esc_html__('Theme not found.', 'bookwellnow-appointment-booking')]);
            }

            $appearance = $theme['appearance'];
            $appearance['font_family'] = 'Poppins';
            $appearance['appearance_theme'] = $theme_id;

            // Preserve Form Type and customized form options when applying a color theme.
            $current_settings = self::get_settings();
            $current_form_type = isset($current_settings['appearance']['form_type'])
                ? sanitize_key((string) $current_settings['appearance']['form_type'])
                : 'wizard';
            if (!in_array($current_form_type, ['wizard', 'full_page_list'], true)) {
                $current_form_type = 'wizard';
            }
            $appearance['form_type'] = $current_form_type;
            $appearance['hide_description'] = $this->normalize_bool_setting(
                $current_settings['appearance']['hide_description'] ?? false
            );
            $appearance['show_staff_designation'] = $this->normalize_bool_setting(
                $current_settings['appearance']['show_staff_designation'] ?? false
            );

            $sanitized = $this->sanitize_settings_for_save(['appearance' => $appearance]);
            $appearance_sanitized = isset($sanitized['appearance']) && is_array($sanitized['appearance'])
                ? $sanitized['appearance']
                : $appearance;

            $this->bwdb->update_settings_by_type('appearance', $appearance_sanitized);

            self::clear_frontend_cache();

            $merged = self::get_settings();
            $theme_label = isset($theme['label']) ? $theme['label'] : $theme_id;

            wp_send_json_success([
                'msg' => sprintf(
                    /* translators: %s: appearance theme name */
                    esc_html__('%s applied. Frontend booking form cache cleared.', 'bookwellnow-appointment-booking'),
                    $theme_label
                ),
                'appearance' => isset($merged['appearance']) ? $merged['appearance'] : $appearance_sanitized,
            ]);
        }

        /**
         * Save only appearance.form_type (used by Settings and Shortcode Generator).
         *
         * @return void
         */
        public function bookwellab_save_appearance_form_type_func()
        {
            if (!\BookWellAB\BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }

            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            $form_type = sanitize_key(BookWellAB_Input::get_post_string('form_type'));
            if (!in_array($form_type, ['wizard', 'full_page_list'], true)) {
                wp_send_json_error(['msg' => esc_html__('Invalid form type.', 'bookwellnow-appointment-booking')]);
            }

            $this->bwdb->update_setting_value('appearance', 'form_type', $form_type);
            self::clear_frontend_cache();

            wp_send_json_success([
                'msg' => esc_html__('Form type saved.', 'bookwellnow-appointment-booking'),
                'form_type' => $form_type,
            ]);
        }

        /**
         * Clear cached frontend booking payloads after settings are saved.
         *
         * @return void
         */
        public static function clear_frontend_cache()
        {
            \BookWellAB\BookWellAB_Frontend::clear_front_booking_cache();
        }

        public static function get_settings()
        {
            $instance = self::get_instance();
            static $bookwellab_settings_migrated = false;
            if (!$bookwellab_settings_migrated && method_exists($instance->bwdb, 'migrate_legacy_settings_to_typed_rows')) {
                $instance->bwdb->migrate_legacy_settings_to_typed_rows();
                $bookwellab_settings_migrated = true;
            }
            $defaults = $instance->get_defaults();
            $saved_settings = [];

            foreach ($defaults as $setting_type => $type_defaults) {
                if (!is_array($type_defaults)) {
                    continue;
                }
                $saved_settings[$setting_type] = $instance->bwdb->get_settings_by_type($setting_type, []);
            }
            $settings = array_replace_recursive($defaults, $saved_settings);

            // Re-apply translations when DB still holds untranslated English defaults.
            $settings = $instance->apply_locale_to_translatable_settings($settings, $defaults);

            if (isset($settings['labels']) && is_array($settings['labels'])) {
                $settings['labels'] = bookwellab_ensure_utf8($settings['labels']);
                $legacy_calendar_labels = [
                    'google_calendar' => ['Google Calendar'],
                    'outlook_calendar' => ['Outlook Calendar'],
                    'ical_calendar' => ['iCal Calendar'],
                ];
                foreach ($legacy_calendar_labels as $label_key => $legacy_values) {
                    if (!isset($settings['labels'][$label_key])) {
                        continue;
                    }
                    $current = (string) $settings['labels'][$label_key];
                    if (in_array($current, $legacy_values, true) && isset($defaults['labels'][$label_key])) {
                        $settings['labels'][$label_key] = $defaults['labels'][$label_key];
                    }
                }
            }

            // Normalize known boolean settings from mixed legacy DB values.
            $settings = $instance->normalize_boolean_settings_for_output($settings);

            if (isset($settings['general']) && is_array($settings['general'])) {
                $settings['general'] = $instance->sync_general_country_and_phone_code($settings['general']);
                $settings['general'] = $instance->hydrate_general_page_ids($settings['general']);
                $settings['general']['week_starts_on'] = (string) self::get_week_starts_on($settings);
            }

            if (isset($settings['payment']) && is_array($settings['payment'])) {
                $settings['payment'] = bookwellab_ensure_utf8($settings['payment']);
            }

            return $instance->strip_form_field_managed_labels($settings);
        }

        /**
         * Frontend booking labels (saved customizations with locale fallback for defaults).
         *
         * @return array<string, string>
         */
        public static function get_frontend_labels()
        {
            bookwellab_load_textdomain();
            $settings = self::get_settings();

            return isset($settings['labels']) && is_array($settings['labels'])
                ? apply_filters('bookwellab_frontend_labels', bookwellab_ensure_utf8($settings['labels']))
                : apply_filters('bookwellab_frontend_labels', []);
        }

        /**
         * English source strings for settings that are stored in the database.
         * Used to detect untouched defaults and re-translate them for the active locale.
         *
         * @return array<string, array<string, string>>
         */
        private function get_translatable_setting_sources()
        {
            $sources = [
                'labels' => [
                    'sidebar_service' => 'Service',
                    'sidebar_staff' => 'Staff',
                    'sidebar_date_time' => 'Date & Time',
                    'sidebar_details' => 'Your Details',
                    'sidebar_summary' => 'Summary',
                    'service_content_title' => 'Service',
                    'staff_content_title' => 'Staff Member',
                    'date_content_title' => 'Select Date & Time',
                    'details_content_title' => 'Your Details',
                    'summary_content_title' => 'Summary & Payment',
                    'all_categories' => 'All',
                    'no_services' => 'No services found.',
                    'select_service' => 'Select Service',
                    'time_slot' => 'Time Slot',
                    'morning' => 'Morning',
                    'afternoon' => 'Afternoon',
                    'pick_a_day' => 'Pick a day',
                    'loading_slots' => 'Loading slots...',
                    'no_slots' => 'No slots available',
                    'please_select_date_first' => 'Please select a date first.',
                    'payment_method' => 'Payment Method',
                    'service_label' => 'Service',
                    'staff_label' => 'Staff',
                    'date_label' => 'Date',
                    'time_label' => 'Time',
                    'customer_label' => 'Customer',
                    'total_label' => 'Total',
                    'confirm_booking' => 'Confirm Booking',
                    'appointment_id_label' => 'Appointment ID',
                    'booking_confirmed_title' => 'Booking Confirmed',
                    'booking_confirmed_msg' => 'Please check your email for details',
                    'book_another' => 'Book Another',
                    'add_to_calendar' => 'Add to Calendar',
                    'google_calendar' => 'Google',
                    'outlook_calendar' => 'Outlook',
                    'ical_calendar' => 'iCal',
                    'next' => 'Continue',
                    'back' => 'Back',
                    'required_fields_error' => 'Please fill in all required fields marked in red.',
                    'select_date_time_error' => 'Please select date and time.',
                    'select_service_error' => 'Please select a service to continue.',
                    'select_staff_error' => 'Please select a staff member to continue.',
                    'invalid_email_error' => 'Please enter a valid email address.',
                    'no_staff_available' => 'No staff available for the selected service.',
                    'offline_payment' => 'Offline Payment',
                    'unexpected_error' => 'An unexpected error occurred. Please try again.',
                    'missing_appointment_id' => 'Appointment ID missing.',
                    'minute_label' => 'Min',
                    'minutes_label' => 'Mins',
                    'hour_label' => 'Hour',
                    'hours_label' => 'Hours',
                    'book_appointment' => 'Book Appointment',
                ],
                'payment' => [
                    'offline_label' => 'Pay on Arrival',
                    'paypal_label' => 'PayPal',
                ],
            ];

            return apply_filters('bookwellab_translatable_setting_sources', $sources);
        }

        /**
         * @param array $settings Merged settings.
         * @param array $defaults Localized defaults from get_defaults().
         * @return array
         */
        private function apply_locale_to_translatable_settings($settings, $defaults)
        {
            foreach ($this->get_translatable_setting_sources() as $section => $sources) {
                if (!isset($settings[$section]) || !is_array($settings[$section])) {
                    continue;
                }
                $section_defaults = isset($defaults[$section]) && is_array($defaults[$section])
                    ? $defaults[$section]
                    : [];

                foreach ($sources as $key => $english_msgid) {
                    if (!array_key_exists($key, $settings[$section])) {
                        continue;
                    }
                    $stored = $settings[$section][$key];
                    $expected = isset($section_defaults[$key]) ? (string) $section_defaults[$key] : '';
                    $is_default_value = ($stored === $english_msgid)
                        || in_array($stored, bookwellab_get_known_translations_for_msgid($english_msgid), true);
                    $needs_refresh = bookwellab_string_is_invalid_utf8($stored)
                        || bookwellab_looks_like_broken_accents($stored, $expected);
                    if (!$is_default_value && !$needs_refresh) {
                        continue;
                    }
                    if (isset($section_defaults[$key])) {
                        $settings[$section][$key] = bookwellab_ensure_utf8($section_defaults[$key]);
                    }
                }
            }

            return $settings;
        }

        /**
         * Sanitize settings payload (all sections/keys) before database write.
         *
         * @param array $settings Raw decoded settings (may include one or more sections).
         * @return array
         */
        public function sanitize_settings_for_save(array $settings)
        {
            return $this->sanitize_settings_payload($settings);
        }

        /**
         * Sanitize settings payload while allowing safe HTML in PDF template.
         *
         * @param array $settings Raw decoded settings.
         * @return array
         */
        private function sanitize_settings_payload($settings)
        {
            $defaults = $this->get_defaults();
            $sanitized_settings = [];

            foreach ($defaults as $setting_type => $type_defaults) {
                if (!isset($settings[$setting_type]) || !is_array($settings[$setting_type])) {
                    continue;
                }
                $sanitized_settings[$setting_type] = [];
                foreach ($settings[$setting_type] as $setting_name => $setting_value) {
                    $setting_name = sanitize_key((string) $setting_name);
                    if ($setting_name === '' || !array_key_exists($setting_name, $type_defaults)) {
                        continue;
                    }
                    $sanitized_settings[$setting_type][$setting_name] = $this->sanitize_setting_value_by_key(
                        $setting_type,
                        $setting_name,
                        $setting_value,
                        $type_defaults[$setting_name]
                    );
                }
            }

            if (isset($sanitized_settings['general']) && is_array($sanitized_settings['general'])) {
                $sanitized_settings['general'] = $this->sync_general_country_and_phone_code($sanitized_settings['general']);
            }

            return $sanitized_settings;
        }

        /**
         * Keep default country ISO and dial code aligned (e.g. US vs CA both use +1).
         *
         * @param array<string, mixed> $general General settings section.
         * @return array<string, mixed>
         */
        private function sync_general_country_and_phone_code(array $general)
        {
            $country = isset($general['default_country']) ? BookWellAB_Input::sanitize_country_slug($general['default_country']) : '';
            if ($country === '') {
                return $general;
            }

            $entry = self::get_phone_code_entry_by_iso($country);
            if (!$entry) {
                return $general;
            }

            $general['default_country'] = strtolower($entry['iso']);
            $general['default_phone_code'] = $entry['code'];

            return $general;
        }

        /**
         * Show effective page selections in admin when legacy store/slug values exist.
         *
         * @param array<string, mixed> $general General settings section.
         * @return array<string, mixed>
         */
        private function hydrate_general_page_ids(array $general)
        {
            if (empty($general['booking_form_page_id'])) {
                $stored = BookWellAB_Default_Pages::get_stored_page_id('booking');
                if ($stored > 0) {
                    $general['booking_form_page_id'] = $stored;
                } else {
                    $definitions = BookWellAB_Default_Pages::get_page_definitions();
                    $slug = sanitize_title((string) ($definitions['booking']['slug'] ?? ''));
                    if ($slug !== '') {
                        $page = get_page_by_path($slug);
                        if ($page instanceof \WP_Post) {
                            $general['booking_form_page_id'] = (int) $page->ID;
                        }
                    }
                }
            }

            if (empty($general['customer_panel_page_id'])) {
                $stored = BookWellAB_Default_Pages::get_stored_page_id('customer_panel');
                if ($stored > 0) {
                    $general['customer_panel_page_id'] = $stored;
                } else {
                    $definitions = BookWellAB_Default_Pages::get_page_definitions();
                    $slug = sanitize_title((string) ($definitions['customer_panel']['slug'] ?? ''));
                    if ($slug !== '') {
                        $page = get_page_by_path($slug);
                        if ($page instanceof \WP_Post) {
                            $general['customer_panel_page_id'] = (int) $page->ID;
                        }
                    }
                }
            }

            $general['booking_form_page_id'] = isset($general['booking_form_page_id'])
                ? absint($general['booking_form_page_id'])
                : 0;
            $general['customer_panel_page_id'] = isset($general['customer_panel_page_id'])
                ? absint($general['customer_panel_page_id'])
                : 0;

            return $general;
        }

        /**
         * @return array<int, array{id: int, title: string}>
         */
        private function get_wp_pages_for_select()
        {
            if (!function_exists('get_pages')) {
                return [];
            }

            $pages = get_pages(
                [
                    'sort_column' => 'post_title',
                    'sort_order' => 'ASC',
                    'post_status' => ['publish', 'draft', 'private', 'pending'],
                ]
            );

            if (!is_array($pages)) {
                return [];
            }

            $list = [];
            foreach ($pages as $page) {
                if (!$page instanceof \WP_Post) {
                    continue;
                }

                $list[] = [
                    'id' => (int) $page->ID,
                    'title' => (string) $page->post_title,
                ];
            }

            return $list;
        }

        /**
         * @param mixed $value
         * @return int
         */
        private function sanitize_page_id_value($value)
        {
            $page_id = absint($value);
            if ($page_id <= 0) {
                return 0;
            }

            if (get_post_type($page_id) !== 'page') {
                return 0;
            }

            $status = get_post_status($page_id);
            if (!$status || $status === 'trash') {
                return 0;
            }

            return $page_id;
        }

        /**
         * Lookup a phone-code list entry by ISO country code.
         *
         * @param string $iso ISO 3166-1 alpha-2 country code.
         * @return array{name: string, code: string, iso: string}|null
         */
        public static function get_phone_code_entry_by_iso($iso)
        {
            $iso = strtoupper(sanitize_text_field((string) $iso));
            if ($iso === '') {
                return null;
            }

            foreach (self::get_phone_codes() as $entry) {
                if (strtoupper((string) $entry['iso']) === $iso) {
                    return $entry;
                }
            }

            return null;
        }

        /**
         * Key-wise sanitizer strategy map (section.key => type).
         *
         * Built from get_defaults() so every label/appearance key has an explicit strategy.
         *
         * @return array<string, string>
         */
        private function get_settings_sanitizer_map()
        {
            static $cached_map = null;

            if (is_array($cached_map)) {
                return $cached_map;
            }

            $cached_map = [
                // General
                'general.company_name' => 'text',
                'general.company_phone' => 'text',
                'general.company_address' => 'textarea',
                'general.date_format' => 'text',
                'general.time_format' => 'text',
                'general.week_starts_on' => 'week_starts_on',
                'general.default_status' => 'text',
                'general.default_payment_status' => 'text',
                'general.slot_step' => 'slot_step',
                'general.booking_status' => 'text',
                'general.default_payment_gateway' => 'key',
                'general.currency_code' => 'currency_code',
                'general.currency_position' => 'currency_position',
                'general.default_country' => 'country_slug',
                'general.default_phone_code' => 'phone_code',
                'general.hide_categories' => 'bool',
                'general.hide_staff_step' => 'bool',
                'general.show_terms_conditions' => 'bool',
                'general.setup_completed' => 'bool',
                'general.booking_form_page_id' => 'page_id',
                'general.customer_panel_page_id' => 'page_id',

                'customer_panel.create_wp_user_on_booking' => 'bool',

                // Notifications
                'notifications.admin_email' => 'email',
                'notifications.from_name' => 'text',
                'notifications.from_email' => 'email',
                'notifications.method' => 'mail_method',
                'notifications.smtp_host' => 'text',
                'notifications.smtp_port' => 'port',
                'notifications.smtp_username' => 'text',
                'notifications.smtp_password' => 'smtp_password',
                'notifications.smtp_secure' => 'smtp_secure',

                // Payment
                'payment.enable_offline' => 'yes_no',
                'payment.offline_label' => 'text',
                'payment.enable_manually' => 'yes_no',
                'payment.manually_label' => 'text',
                'payment.enable_paypal' => 'yes_no',
                'payment.paypal_active_mode' => 'paypal_mode',
                'payment.paypal_sandbox_client_id' => 'text',
                'payment.paypal_sandbox_client_secret' => 'smtp_password',
                'payment.paypal_live_client_id' => 'text',
                'payment.paypal_live_client_secret' => 'smtp_password',
                'payment.paypal_label' => 'text',

                // Debug log
                'debug_log.enable_offline_log' => 'yes_no',
                'debug_log.enable_paypal_log' => 'yes_no',
                'debug_log.enable_email_log' => 'yes_no',
            ];

            $defaults = $this->get_defaults();

            if (isset($defaults['labels']) && is_array($defaults['labels'])) {
                foreach (array_keys($defaults['labels']) as $label_key) {
                    $cached_map['labels.' . $label_key] = 'text';
                }
            }

            if (isset($defaults['appearance']) && is_array($defaults['appearance'])) {
                foreach (array_keys($defaults['appearance']) as $appearance_key) {
                    $full_key = 'appearance.' . $appearance_key;
                    if ($appearance_key === 'font_family') {
                        $cached_map[$full_key] = 'google_font';
                    } elseif ($appearance_key === 'appearance_theme' || $appearance_key === 'form_type') {
                        $cached_map[$full_key] = 'key';
                    } elseif (in_array($appearance_key, ['hide_description', 'show_staff_designation'], true)) {
                        $cached_map[$full_key] = 'bool';
                    } elseif ($this->string_ends_with($appearance_key, '_color')) {
                        $cached_map[$full_key] = 'color';
                    } elseif ($this->string_ends_with($appearance_key, '_size')) {
                        $cached_map[$full_key] = 'font_size';
                    } else {
                        $cached_map[$full_key] = 'text';
                    }
                }
            }

            $cached_map = apply_filters('bookwellab_settings_sanitizer_map', $cached_map);
            return $cached_map;
        }

        /**
         * Sanitize one setting by its full key.
         *
         * @param string $setting_type Section name.
         * @param string $setting_name Setting key.
         * @param mixed  $setting_value Raw value.
         * @param mixed  $default_value Default value for fallback.
         * @return mixed
         */
        private function sanitize_setting_value_by_key($setting_type, $setting_name, $setting_value, $default_value)
        {
            $full_key = $setting_type . '.' . $setting_name;
            $map = $this->get_settings_sanitizer_map();
            $strategy = isset($map[$full_key]) ? $map[$full_key] : 'text';

            switch ($strategy) {
                case 'bool':
                    return $this->normalize_bool_setting($setting_value);

                case 'email':
                    return sanitize_email((string) $setting_value);

                case 'key':
                    $key_value = sanitize_key((string) $setting_value);
                    if ($full_key === 'appearance.form_type') {
                        return in_array($key_value, ['wizard', 'full_page_list'], true)
                            ? $key_value
                            : (string) $default_value;
                    }
                    return $key_value;

                case 'country_slug':
                    $country = BookWellAB_Input::sanitize_country_slug($setting_value);
                    return $country !== '' ? $country : (string) $default_value;

                case 'phone_code':
                    return $this->sanitize_phone_code_value($setting_value, $default_value);

                case 'currency_code':
                    return $this->sanitize_currency_code_value($setting_value, $default_value);

                case 'currency_position':
                    return in_array((string) $setting_value, ['before', 'after'], true)
                        ? (string) $setting_value
                        : (string) $default_value;

                case 'mail_method':
                    return in_array((string) $setting_value, ['wp_mail', 'smtp'], true)
                        ? (string) $setting_value
                        : (string) $default_value;

                case 'smtp_secure':
                    return in_array((string) $setting_value, ['tls', 'ssl', 'none'], true)
                        ? (string) $setting_value
                        : (string) $default_value;

                case 'port':
                    $port = absint($setting_value);
                    return $port > 0 ? (string) $port : (string) $default_value;

                case 'page_id':
                    return $this->sanitize_page_id_value($setting_value);

                case 'google_font':
                    return $this->sanitize_google_font_value($setting_value, $default_value);

                case 'yes_no':
                    return $this->normalize_bool_setting($setting_value) ? 'yes' : 'no';

                case 'paypal_mode':
                    return in_array((string) $setting_value, ['sandbox', 'live'], true)
                        ? (string) $setting_value
                        : (string) $default_value;

                case 'smtp_password':
                    return str_replace("\0", '', (string) $setting_value);

                case 'slot_step':
                    return $this->sanitize_slot_step_value($setting_value, $default_value);

                case 'week_starts_on':
                    return $this->sanitize_week_starts_on_value($setting_value, $default_value);

                case 'color':
                    return $this->sanitize_color_value($setting_value, $default_value);

                case 'font_size':
                    return $this->sanitize_positive_number_string($setting_value, $default_value);

                case 'textarea':
                    return is_string($setting_value)
                        ? sanitize_textarea_field($setting_value)
                        : sanitize_textarea_field((string) $setting_value);

                case 'esc_url':
                    return esc_url_raw((string) $setting_value);

                case 'text':
                        default:
                    return $this->sanitize_string_value($setting_value);
            }
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_week_starts_on_value($value, $default_value)
        {
            $day = absint($value);
            if ($day >= 0 && $day <= 6) {
                return (string) $day;
            }

            $fallback = absint($default_value);
            if ($fallback >= 0 && $fallback <= 6) {
                return (string) $fallback;
            }

            return (string) absint(get_option('start_of_week', 1));
        }

        /**
         * Week start day for calendars (0 = Sunday … 6 = Saturday), WordPress-style.
         *
         * @param array<string, mixed>|null $settings Optional settings payload.
         * @return int
         */
        public static function get_week_starts_on($settings = null)
        {
            if (!is_array($settings)) {
                $settings = self::get_settings();
            }

            $value = isset($settings['general']['week_starts_on'])
                ? absint($settings['general']['week_starts_on'])
                : absint(get_option('start_of_week', 1));

            return ($value >= 0 && $value <= 6) ? $value : 1;
        }

        /**
         * Rotated weekday labels starting from the configured week start.
         *
         * @param bool $short Use short day names.
         * @param array<string, mixed>|null $settings Optional settings payload.
         * @return array<int, string>
         */
        public static function get_week_day_labels($short = true, $settings = null)
        {
            $labels = $short
                ? array(
                    0 => __('Sun', 'bookwellnow-appointment-booking'),
                    1 => __('Mon', 'bookwellnow-appointment-booking'),
                    2 => __('Tue', 'bookwellnow-appointment-booking'),
                    3 => __('Wed', 'bookwellnow-appointment-booking'),
                    4 => __('Thu', 'bookwellnow-appointment-booking'),
                    5 => __('Fri', 'bookwellnow-appointment-booking'),
                    6 => __('Sat', 'bookwellnow-appointment-booking'),
                )
                : array(
                    0 => __('Sunday', 'bookwellnow-appointment-booking'),
                    1 => __('Monday', 'bookwellnow-appointment-booking'),
                    2 => __('Tuesday', 'bookwellnow-appointment-booking'),
                    3 => __('Wednesday', 'bookwellnow-appointment-booking'),
                    4 => __('Thursday', 'bookwellnow-appointment-booking'),
                    5 => __('Friday', 'bookwellnow-appointment-booking'),
                    6 => __('Saturday', 'bookwellnow-appointment-booking'),
                );

            $start = self::get_week_starts_on($settings);
            $ordered = array();
            for ($i = 0; $i < 7; $i++) {
                $ordered[] = $labels[($start + $i) % 7];
            }

            return $ordered;
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_slot_step_value($value, $default_value)
        {
            $raw = (string) $value;
            if ($raw === 'service_duration') {
                return 'service_duration';
            }

            $minutes = absint($value);
            if ($minutes > 0) {
                return (string) $minutes;
            }

            $fallback = (string) $default_value;
            if ($fallback === 'service_duration') {
                return 'service_duration';
            }

            $fallback_minutes = absint($default_value);
            return $fallback_minutes > 0 ? (string) $fallback_minutes : '15';
        }

        /**
         * @param mixed $value
         * @return string
         */
        private function sanitize_string_value($value)
        {
            return is_string($value)
                ? sanitize_text_field($value)
                : sanitize_text_field((string) $value);
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_color_value($value, $default_value)
        {
            $sanitized = sanitize_hex_color((string) $value);
            if ($sanitized !== null && $sanitized !== false && $sanitized !== '') {
                return $sanitized;
            }

            $fallback = sanitize_hex_color((string) $default_value);
            return ($fallback !== null && $fallback !== false && $fallback !== '') ? $fallback : '#000000';
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_positive_number_string($value, $default_value)
        {
            $number = absint($value);
            if ($number > 0) {
                return (string) $number;
            }

            $fallback = absint($default_value);
            if ($fallback > 0) {
                return (string) $fallback;
            }

            return '1';
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_google_font_value($value, $default_value)
        {
            $font = trim((string) $value);
            if (in_array($font, self::get_google_fonts(), true)) {
                return $font;
            }

            $fallback = trim((string) $default_value);
            if (in_array($fallback, self::get_google_fonts(), true)) {
                return $fallback;
            }

            return 'Poppins';
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_phone_code_value($value, $default_value)
        {
            $phone_code = preg_replace('/[^0-9+]/', '', (string) $value);
            if (is_string($phone_code) && preg_match('/^\+\d{1,4}$/', $phone_code)) {
                return $phone_code;
            }

            $fallback = preg_replace('/[^0-9+]/', '', (string) $default_value);
            if (is_string($fallback) && preg_match('/^\+\d{1,4}$/', $fallback)) {
                return $fallback;
            }

            return '+1';
        }

        /**
         * @param mixed $value
         * @param mixed $default_value
         * @return string
         */
        private function sanitize_currency_code_value($value, $default_value)
        {
            $code = strtoupper(sanitize_key((string) $value));
            if ($code !== '' && isset(self::get_currencies()[$code])) {
                return $code;
            }

            $fallback = strtoupper(sanitize_key((string) $default_value));
            if ($fallback !== '' && isset(self::get_currencies()[$fallback])) {
                return $fallback;
            }

            return 'USD';
        }

        /**
         * PHP 7 compatible ends-with helper.
         *
         * @param string $haystack
         * @param string $needle
         * @return bool
         */
        private function string_ends_with($haystack, $needle)
        {
            $haystack = (string) $haystack;
            $needle = (string) $needle;

            if ($needle === '') {
                return true;
            }

            $needle_len = strlen($needle);
            if ($needle_len > strlen($haystack)) {
                return false;
            }

            return substr($haystack, -$needle_len) === $needle;
        }

        /**
         * Normalize mixed boolean-like payload values into strict bool.
         *
         * Accepts common true-like values: true, 1, "1", "true", "on", "yes".
         * Everything else is treated as false (including "false", "0", "off", "").
         *
         * @param mixed $value
         * @return bool
         */
        private function normalize_bool_setting($value)
        {
            if (is_bool($value)) {
                return $value;
            }
            if (is_int($value) || is_float($value)) {
                return ((int) $value) === 1;
            }
            if (is_string($value)) {
                $normalized = strtolower(trim($value));
                return in_array($normalized, ['1', 'true', 'on', 'yes'], true);
            }
            return !empty($value);
        }

        /**
         * Ensure boolean settings are strict booleans before sending to JS/UI.
         *
         * @param array $settings
         * @return array
         */
        private function normalize_boolean_settings_for_output($settings)
        {
            if (!is_array($settings)) {
                return [];
            }

            if (!isset($settings['general']) || !is_array($settings['general'])) {
                $settings['general'] = [];
            }

            $bool_keys = ['hide_categories', 'hide_staff_step', 'show_terms_conditions', 'setup_completed'];
            foreach ($bool_keys as $key) {
                if (array_key_exists($key, $settings['general'])) {
                    $settings['general'][$key] = $this->normalize_bool_setting($settings['general'][$key]);
                }
            }

            if (!isset($settings['appearance']) || !is_array($settings['appearance'])) {
                $settings['appearance'] = [];
            }
            $appearance_bool_keys = ['hide_description', 'show_staff_designation'];
            foreach ($appearance_bool_keys as $key) {
                if (array_key_exists($key, $settings['appearance'])) {
                    $settings['appearance'][$key] = $this->normalize_bool_setting($settings['appearance'][$key]);
                }
            }

            if (!isset($settings['customer_panel']) || !is_array($settings['customer_panel'])) {
                $settings['customer_panel'] = [];
            }
            if (array_key_exists('create_wp_user_on_booking', $settings['customer_panel'])) {
                $settings['customer_panel']['create_wp_user_on_booking'] = $this->normalize_bool_setting(
                    $settings['customer_panel']['create_wp_user_on_booking']
                );
            }

            return $settings;
        }

        public function bookwellab_save_settings_func()
        {
            if (!\BookWellAB\BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }

            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            // BookWellAB_Input: decoded JSON only; all keys sanitized in sanitize_settings_payload() before DB write.
            $settings = BookWellAB_Input::get_post_json('settings');
            if (empty($settings)) {
                wp_send_json_error(['msg' => 'No settings data received']);
            }
            $settings = $this->sanitize_settings_for_save($settings);
            foreach ($settings as $setting_type => $type_settings) {
                if (!is_array($type_settings)) {
                    continue;
                }
                $this->bwdb->update_settings_by_type($setting_type, $type_settings);
            }

            if (isset($settings['general']) && is_array($settings['general'])) {
                if (isset($settings['general']['booking_form_page_id'])) {
                    BookWellAB_Default_Pages::sync_stored_page_id(
                        'booking',
                        absint($settings['general']['booking_form_page_id'])
                    );
                }
                if (isset($settings['general']['customer_panel_page_id'])) {
                    BookWellAB_Default_Pages::sync_stored_page_id(
                        'customer_panel',
                        absint($settings['general']['customer_panel_page_id'])
                    );
                }
            }

            self::clear_frontend_cache();

            wp_send_json_success(['msg' => 'Settings saved successfully']);
        }

        public function bookwellab_send_test_email_func()
        {
            if (!\BookWellAB\BookWellAB_Permissions::has_permission('bookwellab_manage_settings')) {
                wp_send_json_error(['msg' => esc_html__('Unauthorized', 'bookwellnow-appointment-booking')]);
            }

            if (!check_ajax_referer('bw_wp_nonce', '_wpnonce', false)) {
                wp_send_json_error(['msg' => esc_html__('Security token mismatch.', 'bookwellnow-appointment-booking')]);
            }

            // BookWellAB_Input: unslashed string; sanitized on next line before use.
            $test_email_raw = BookWellAB_Input::get_post_string('email');
            $test_email = $test_email_raw !== '' ? sanitize_email($test_email_raw) : '';
            // BookWellAB_Input: decoded JSON only; sanitized in sanitize_notifications_for_mail_test() below.
            $notifications = BookWellAB_Input::get_post_json('settings');

            if (empty($test_email)) {
                wp_send_json_error(['msg' => esc_html__('Invalid email address.', 'bookwellnow-appointment-booking')]);
            }

            // Temporarily override SMTP and From settings if provided (unsaved testing)
            $final_from_email = '';
            $final_from_name = '';

            if (!empty($notifications)) {
                $notifications = self::sanitize_notifications_for_mail_test($notifications);
                $final_from_email = !empty($notifications['from_email']) ? $notifications['from_email'] : '';
                $final_from_name = !empty($notifications['from_name']) ? $notifications['from_name'] : '';

                // Fallback to SMTP username if from_email is empty and method is SMTP
                if (empty($final_from_email) && isset($notifications['method']) && $notifications['method'] === 'smtp') {
                    $final_from_email = !empty($notifications['smtp_username']) ? $notifications['smtp_username'] : '';
                }

                if (isset($notifications['method']) && $notifications['method'] === 'smtp') {
                    if (empty($notifications['smtp_host']) || empty($notifications['smtp_port'])) {
                        wp_send_json_error(['msg' => esc_html__('SMTP host and port are required.', 'bookwellnow-appointment-booking')]);
                    }

                    remove_action('phpmailer_init', [$this, 'bookwellab_configure_smtp']);
                    add_action(
                        'phpmailer_init',
                        function ($phpmailer) use ($notifications, $final_from_email, $final_from_name) {
                            self::apply_smtp_config_to_phpmailer($phpmailer, $notifications, $final_from_email, $final_from_name);
                        },
                        999
                    );
                }
            }

            // Always ensure we have a valid from email for the test
            if (empty($final_from_email)) {
                $settings = self::get_settings();
                $final_from_email = !empty($settings['notifications']['from_email']) ? $settings['notifications']['from_email'] : get_option('admin_email');
                $final_from_name = !empty($settings['notifications']['from_name']) ? $settings['notifications']['from_name'] : get_bloginfo('name');
            }

            // Apply filters to override WordPress defaults
            add_filter('wp_mail_from', function () use ($final_from_email) {
                return $final_from_email;
            }, 999);

            add_filter('wp_mail_from_name', function () use ($final_from_name) {
                return $final_from_name;
            }, 999);

            $subject = esc_html__('Test Email from BookWell Appointment Booking', 'bookwellnow-appointment-booking');
            $message = esc_html__('This is a test email to verify your email settings. If you received this, your configuration is working correctly.', 'bookwellnow-appointment-booking');
            $headers = ['Content-Type: text/html; charset=UTF-8'];

            // Capture WP Mail errors if any
            add_action('wp_mail_failed', function ($error) {
                global $bookwellab_mail_error;
                $bookwellab_mail_error = $error->get_error_message();
            });

            global $bookwellab_mail_error;
            $bookwellab_mail_error = '';

            BookWellAB_Payment_Debug_Log::log(
                'email',
                'Send Test Email',
                'bookwellab_settings_test_email',
                [
                    'to' => $test_email,
                    'subject' => $subject,
                    'method' => isset($notifications['method']) ? (string) $notifications['method'] : 'wp_mail',
                ],
                0
            );

            $sent = wp_mail($test_email, $subject, $message, $headers);

            if ($sent) {
                BookWellAB_Payment_Debug_Log::log(
                    'email',
                    'Send Test Email Success',
                    'bookwellab_settings_test_email',
                    [
                        'to' => $test_email,
                        'status' => 1,
                    ],
                    0
                );
                wp_send_json_success(['msg' => esc_html__('Test email sent successfully!', 'bookwellnow-appointment-booking')]);
            }

            global $phpmailer;
            $phpmailer_error = '';
            if (isset($phpmailer) && is_object($phpmailer) && !empty($phpmailer->ErrorInfo)) {
                $phpmailer_error = (string) $phpmailer->ErrorInfo;
            }

            if (!empty($bookwellab_mail_error)) {
                $error_msg = $bookwellab_mail_error;
            } elseif ($phpmailer_error !== '') {
                $error_msg = $phpmailer_error;
            } else {
                $error_msg = esc_html__('Failed to send test email. Please check your SMTP host, port, encryption, username, and password.', 'bookwellnow-appointment-booking');
            }

            BookWellAB_Payment_Debug_Log::log(
                'email',
                'Send Test Email Error',
                'bookwellab_settings_test_email',
                [
                    'to' => $test_email,
                    'status' => 0,
                    'error' => $error_msg,
                ],
                0
            );

            wp_send_json_error(['msg' => $error_msg]);
        }
        public static function get_formatted_price($price)
        {
            $settings = self::get_settings();
            $currency_code = isset($settings['general']['currency_code']) ? $settings['general']['currency_code'] : 'USD';
            $currency_position = isset($settings['general']['currency_position']) ? $settings['general']['currency_position'] : 'before';

            $currencies = self::get_currencies();
            $currency_symbol = isset($currencies[$currency_code]) ? $currencies[$currency_code]['symbol'] : '$';

            if ($currency_position == 'after') {
                return $price . $currency_symbol;
            } else {
                return $currency_symbol . $price;
            }
        }

        public static function get_currencies()
        {
            return [
                'USD' => ['name' => __('US Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'EUR' => ['name' => __('Euro', 'bookwellnow-appointment-booking'), 'symbol' => '€'],
                'GBP' => ['name' => __('Pound Sterling', 'bookwellnow-appointment-booking'), 'symbol' => '£'],
                'AUD' => ['name' => __('Australian Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'CAD' => ['name' => __('Canadian Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'JPY' => ['name' => __('Japanese Yen', 'bookwellnow-appointment-booking'), 'symbol' => '¥'],
                'INR' => ['name' => __('Indian Rupee', 'bookwellnow-appointment-booking'), 'symbol' => '₹'],
                'BRL' => ['name' => __('Brazilian Real', 'bookwellnow-appointment-booking'), 'symbol' => 'R$'],
                'CNY' => ['name' => __('Chinese Yuan', 'bookwellnow-appointment-booking'), 'symbol' => '¥'],
                'CZK' => ['name' => __('Czech Koruna', 'bookwellnow-appointment-booking'), 'symbol' => 'Kč'],
                'DKK' => ['name' => __('Danish Krone', 'bookwellnow-appointment-booking'), 'symbol' => 'kr'],
                'HKD' => ['name' => __('Hong Kong Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'HUF' => ['name' => __('Hungarian Forint', 'bookwellnow-appointment-booking'), 'symbol' => 'Ft'],
                'ILS' => ['name' => __('Israeli New Sheqel', 'bookwellnow-appointment-booking'), 'symbol' => '₪'],
                'MYR' => ['name' => __('Malaysian Ringgit', 'bookwellnow-appointment-booking'), 'symbol' => 'RM'],
                'MXN' => ['name' => __('Mexican Peso', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'NOK' => ['name' => __('Norwegian Krone', 'bookwellnow-appointment-booking'), 'symbol' => 'kr'],
                'NZD' => ['name' => __('New Zealand Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'PHP' => ['name' => __('Philippine Peso', 'bookwellnow-appointment-booking'), 'symbol' => '₱'],
                'PLN' => ['name' => __('Polish Zloty', 'bookwellnow-appointment-booking'), 'symbol' => 'zł'],
                'SGD' => ['name' => __('Singapore Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'SEK' => ['name' => __('Swedish Krona', 'bookwellnow-appointment-booking'), 'symbol' => 'kr'],
                'CHF' => ['name' => __('Swiss Franc', 'bookwellnow-appointment-booking'), 'symbol' => 'CHF'],
                'TWD' => ['name' => __('New Taiwan Dollar', 'bookwellnow-appointment-booking'), 'symbol' => '$'],
                'THB' => ['name' => __('Thai Baht', 'bookwellnow-appointment-booking'), 'symbol' => '฿'],
                'TRY' => ['name' => __('Turkish Lira', 'bookwellnow-appointment-booking'), 'symbol' => '₺'],
                'RUB' => ['name' => __('Russian Ruble', 'bookwellnow-appointment-booking'), 'symbol' => '₽'],
                'ZAR' => ['name' => __('South African Rand', 'bookwellnow-appointment-booking'), 'symbol' => 'R'],
            ];
        }

        public static function get_countries_list()
        {
            return [
                'af' => 'Afghanistan',
                'ax' => 'Åland Islands',
                'al' => 'Albania',
                'dz' => 'Algeria',
                'as' => 'American Samoa',
                'ad' => 'Andorra',
                'ao' => 'Angola',
                'ai' => 'Anguilla',
                'aq' => 'Antarctica',
                'ag' => 'Antigua and Barbuda',
                'ar' => 'Argentina',
                'am' => 'Armenia',
                'aw' => 'Aruba',
                'au' => 'Australia',
                'at' => 'Austria',
                'az' => 'Azerbaijan',
                'bs' => 'Bahamas',
                'bh' => 'Bahrain',
                'bd' => 'Bangladesh',
                'bb' => 'Barbados',
                'by' => 'Belarus',
                'be' => 'Belgium',
                'bz' => 'Belize',
                'bj' => 'Benin',
                'bm' => 'Bermuda',
                'bt' => 'Bhutan',
                'bo' => 'Bolivia',
                'ba' => 'Bosnia and Herzegovina',
                'bw' => 'Botswana',
                'bv' => 'Bouvet Island',
                'br' => 'Brazil',
                'io' => 'British Indian Ocean Territory',
                'bn' => 'Brunei Darussalam',
                'bg' => 'Bulgaria',
                'bf' => 'Burkina Faso',
                'bi' => 'Burundi',
                'kh' => 'Cambodia',
                'cm' => 'Cameroon',
                'ca' => 'Canada',
                'cv' => 'Cape Verde',
                'ky' => 'Cayman Islands',
                'cf' => 'Central African Republic',
                'td' => 'Chad',
                'cl' => 'Chile',
                'cn' => 'China',
                'cx' => 'Christmas Island',
                'cc' => 'Cocos (Keeling) Islands',
                'co' => 'Colombia',
                'km' => 'Comoros',
                'cg' => 'Congo',
                'cd' => 'Congo, The Democratic Republic of the',
                'ck' => 'Cook Islands',
                'cr' => 'Costa Rica',
                'ci' => 'Cote D\'Ivoire',
                'hr' => 'Croatia',
                'cu' => 'Cuba',
                'cy' => 'Cyprus',
                'cz' => 'Czech Republic',
                'dk' => 'Denmark',
                'dj' => 'Djibouti',
                'dm' => 'Dominica',
                'do' => 'Dominican Republic',
                'ec' => 'Ecuador',
                'eg' => 'Egypt',
                'sv' => 'El Salvador',
                'gq' => 'Equatorial Guinea',
                'er' => 'Eritrea',
                'ee' => 'Estonia',
                'et' => 'Ethiopia',
                'fk' => 'Falkland Islands (Malvinas)',
                'fo' => 'Faroe Islands',
                'fj' => 'Fiji',
                'fi' => 'Finland',
                'fr' => 'France',
                'gf' => 'French Guiana',
                'pf' => 'French Polynesia',
                'tf' => 'French Southern Territories',
                'ga' => 'Gabon',
                'gm' => 'Gambia',
                'ge' => 'Georgia',
                'de' => 'Germany',
                'gh' => 'Ghana',
                'gi' => 'Gibraltar',
                'gr' => 'Greece',
                'gl' => 'Greenland',
                'gd' => 'Grenada',
                'gp' => 'Guadeloupe',
                'gu' => 'Guam',
                'gt' => 'Guatemala',
                'gg' => 'Guernsey',
                'gn' => 'Guinea',
                'gw' => 'Guinea-Bissau',
                'gy' => 'Guyana',
                'ht' => 'Haiti',
                'hm' => 'Heard Island and Mcdonald Islands',
                'va' => 'Holy See (Vatican City State)',
                'hn' => 'Honduras',
                'hk' => 'Hong Kong',
                'hu' => 'Hungary',
                'is' => 'Iceland',
                'in' => 'India',
                'id' => 'Indonesia',
                'ir' => 'Iran, Islamic Republic Of',
                'iq' => 'Iraq',
                'ie' => 'Ireland',
                'im' => 'Isle of Man',
                'il' => 'Israel',
                'it' => 'Italy',
                'jm' => 'Jamaica',
                'jp' => 'Japan',
                'je' => 'Jersey',
                'jo' => 'Jordan',
                'kz' => 'Kazakhstan',
                'ke' => 'Kenya',
                'ki' => 'Kiribati',
                'kp' => 'Korea, Democratic People\'S Republic of',
                'kr' => 'Korea, Republic of',
                'kw' => 'Kuwait',
                'kg' => 'Kyrgyzstan',
                'la' => 'Lao People\'S Democratic Republic',
                'lv' => 'Latvia',
                'lb' => 'Lebanon',
                'ls' => 'Lesotho',
                'lr' => 'Liberia',
                'ly' => 'Libyan Arab Jamahiriya',
                'li' => 'Liechtenstein',
                'lt' => 'Lithuania',
                'lu' => 'Luxembourg',
                'mo' => 'Macao',
                'mk' => 'Macedonia, The Former Yugoslav Republic of',
                'mg' => 'Madagascar',
                'mw' => 'Malawi',
                'my' => 'Malaysia',
                'mv' => 'Maldives',
                'ml' => 'Mali',
                'mt' => 'Malta',
                'mh' => 'Marshall Islands',
                'mq' => 'Martinique',
                'mr' => 'Mauritania',
                'mu' => 'Mauritius',
                'yt' => 'Mayotte',
                'mx' => 'Mexico',
                'fm' => 'Micronesia, Federated States of',
                'md' => 'Moldova, Republic of',
                'mc' => 'Monaco',
                'mn' => 'Mongolia',
                'me' => 'Montenegro',
                'ms' => 'Montserrat',
                'ma' => 'Morocco',
                'mz' => 'Mozambique',
                'mm' => 'Myanmar',
                'na' => 'Namibia',
                'nr' => 'Nauru',
                'np' => 'Nepal',
                'nl' => 'Netherlands',
                'an' => 'Netherlands Antilles',
                'nc' => 'New Caledonia',
                'nz' => 'New Zealand',
                'ni' => 'Nicaragua',
                'ne' => 'Niger',
                'ng' => 'Nigeria',
                'nu' => 'Niue',
                'nf' => 'Norfolk Island',
                'mp' => 'Northern Mariana Islands',
                'no' => 'Norway',
                'om' => 'Oman',
                'pk' => 'Pakistan',
                'pw' => 'Palau',
                'ps' => 'Palestinian Territory, Occupied',
                'pa' => 'Panama',
                'pg' => 'Papua New Guinea',
                'py' => 'Paraguay',
                'pe' => 'Peru',
                'ph' => 'Philippines',
                'pn' => 'Pitcairn',
                'pl' => 'Poland',
                'pt' => 'Portugal',
                'pr' => 'Puerto Rico',
                'qa' => 'Qatar',
                're' => 'Reunion',
                'ro' => 'Romania',
                'ru' => 'Russian Federation',
                'rw' => 'Rwanda',
                'sh' => 'Saint Helena',
                'kn' => 'Saint Kitts and Nevis',
                'lc' => 'Saint Lucia',
                'pm' => 'Saint Pierre and Miquelon',
                'vc' => 'Saint Vincent and the Grenadines',
                'ws' => 'Samoa',
                'sm' => 'San Marino',
                'st' => 'Sao Tome and Principe',
                'sa' => 'Saudi Arabia',
                'sn' => 'Senegal',
                'rs' => 'Serbia',
                'sc' => 'Seychelles',
                'sl' => 'Sierra Leone',
                'sg' => 'Singapore',
                'sk' => 'Slovakia',
                'si' => 'Slovenia',
                'sb' => 'Solomon Islands',
                'so' => 'Somalia',
                'za' => 'South Africa',
                'gs' => 'South Georgia and the South Sandwich Islands',
                'es' => 'Spain',
                'lk' => 'Sri Lanka',
                'sd' => 'Sudan',
                'sr' => 'Suriname',
                'sj' => 'Svalbard and Jan Mayen',
                'sz' => 'Swaziland',
                'se' => 'Sweden',
                'ch' => 'Switzerland',
                'sy' => 'Syrian Arab Republic',
                'tw' => 'Taiwan, Province of China',
                'tj' => 'Tajikistan',
                'tz' => 'Tanzania, United Republic of',
                'th' => 'Thailand',
                'tl' => 'Timor-Leste',
                'tg' => 'Togo',
                'tk' => 'Tokelau',
                'to' => 'Tonga',
                'tt' => 'Trinidad and Tobago',
                'tn' => 'Tunisia',
                'tr' => 'Turkey',
                'tm' => 'Turkmenistan',
                'tc' => 'Turks and Caicos Islands',
                'tv' => 'Tuvalu',
                'ug' => 'Uganda',
                'ua' => 'Ukraine',
                'ae' => 'United Arab Emirates',
                'gb' => 'United Kingdom',
                'us' => 'United States',
                'um' => 'United States Minor Outlying Islands',
                'uy' => 'Uruguay',
                'uz' => 'Uzbekistan',
                'vu' => 'Vanuatu',
                've' => 'Venezuela',
                'vn' => 'Viet Nam',
                'vg' => 'Virgin Islands, British',
                'vi' => 'Virgin Islands, U.S.',
                'wf' => 'Wallis and Futuna',
                'eh' => 'Western Sahara',
                'ye' => 'Yemen',
                'zm' => 'Zambia',
                'zw' => 'Zimbabwe',
            ];
        }

        public static function get_phone_codes()
        {
            return [
                ['name' => 'United States', 'code' => '+1', 'iso' => 'US'],
                ['name' => 'United Kingdom', 'code' => '+44', 'iso' => 'GB'],
                ['name' => 'India', 'code' => '+91', 'iso' => 'IN'],
                ['name' => 'Australia', 'code' => '+61', 'iso' => 'AU'],
                ['name' => 'Canada', 'code' => '+1', 'iso' => 'CA'],
                ['name' => 'Germany', 'code' => '+49', 'iso' => 'DE'],
                ['name' => 'France', 'code' => '+33', 'iso' => 'FR'],
                ['name' => 'Italy', 'code' => '+39', 'iso' => 'IT'],
                ['name' => 'Spain', 'code' => '+34', 'iso' => 'ES'],
                ['name' => 'Brazil', 'code' => '+55', 'iso' => 'BR'],
                ['name' => 'Japan', 'code' => '+81', 'iso' => 'JP'],
                ['name' => 'China', 'code' => '+86', 'iso' => 'CN'],
                ['name' => 'Singapore', 'code' => '+65', 'iso' => 'SG'],
                ['name' => 'United Arab Emirates', 'code' => '+971', 'iso' => 'AE'],
                ['name' => 'South Africa', 'code' => '+27', 'iso' => 'ZA'],
                ['name' => 'Netherlands', 'code' => '+31', 'iso' => 'NL'],
                ['name' => 'Switzerland', 'code' => '+41', 'iso' => 'CH'],
                ['name' => 'Sweden', 'code' => '+46', 'iso' => 'SE'],
                ['name' => 'Norway', 'code' => '+47', 'iso' => 'NO'],
                ['name' => 'Denmark', 'code' => '+45', 'iso' => 'DK'],
                ['name' => 'Finland', 'code' => '+358', 'iso' => 'FI'],
                ['name' => 'Ireland', 'code' => '+353', 'iso' => 'IE'],
                ['name' => 'Portugal', 'code' => '+351', 'iso' => 'PT'],
                ['name' => 'Poland', 'code' => '+48', 'iso' => 'PL'],
                ['name' => 'Russia', 'code' => '+7', 'iso' => 'RU'],
                ['name' => 'Turkey', 'code' => '+90', 'iso' => 'TR'],
                ['name' => 'Saudi Arabia', 'code' => '+966', 'iso' => 'SA'],
                ['name' => 'Israel', 'code' => '+972', 'iso' => 'IL'],
                ['name' => 'Mexico', 'code' => '+52', 'iso' => 'MX'],
                ['name' => 'Argentina', 'code' => '+54', 'iso' => 'AR'],
                ['name' => 'Chile', 'code' => '+56', 'iso' => 'CL'],
                ['name' => 'Colombia', 'code' => '+57', 'iso' => 'CO'],
                ['name' => 'Peru', 'code' => '+51', 'iso' => 'PE'],
                ['name' => 'New Zealand', 'code' => '+64', 'iso' => 'NZ'],
                ['name' => 'Malaysia', 'code' => '+60', 'iso' => 'MY'],
                ['name' => 'Indonesia', 'code' => '+62', 'iso' => 'ID'],
                ['name' => 'Thailand', 'code' => '+66', 'iso' => 'TH'],
                ['name' => 'Vietnam', 'code' => '+84', 'iso' => 'VN'],
                ['name' => 'Philippines', 'code' => '+63', 'iso' => 'PH'],
                ['name' => 'Pakistan', 'code' => '+92', 'iso' => 'PK'],
                ['name' => 'Bangladesh', 'code' => '+880', 'iso' => 'BD'],
                ['name' => 'Sri Lanka', 'code' => '+94', 'iso' => 'LK'],
                ['name' => 'Nigeria', 'code' => '+234', 'iso' => 'NG'],
                ['name' => 'Egypt', 'code' => '+20', 'iso' => 'EG'],
                ['name' => 'Kenya', 'code' => '+254', 'iso' => 'KE'],
                ['name' => 'Ghana', 'code' => '+233', 'iso' => 'GH'],
                ['name' => 'Ethiopia', 'code' => '+251', 'iso' => 'ET']
            ];
        }
    }
}
