PNG %k25u25%fgd5n!
/home/mkuwqnjx/palaknaturals.com/wp-content/plugins/echo-rewards/includes/Ecre_Ajax.php
<?php
/**
 * File: Ecre_Ajax.php
 *
 * The Ecre_Ajax class handles AJAX requests and provides functionalities for generating referral coupons.
 *
 * @package ECRE
 * @since   1.0.0
 */

namespace ECRE;

if ( ! class_exists( 'Ecre_Ajax' ) ) {
	/**
	 * The Ecre_Ajax class handles AJAX requests and provides functionalities for generating referral coupons.
	 *
	 * @since 1.0.0
	 */
	class Ecre_Ajax {
		/**
		 * Indicates whether the user has a professional (pro) account.
		 *
		 * @var bool
		 */
		public $is_pro = false;

		/**
		 * Holds the settings configuration for the ECRE order tracking system.
		 *
		 * This property stores various settings retrieved from the database,
		 * such as email templates, discount configurations, and tracking options.
		 *
		 * @var array
		 */
		public $settings = array();

		/**
		 * Initializes the Ecre_Ajax class.
		 *
		 * Sets up the class properties and registers AJAX request handlers based on the user's
		 * professional (pro) status and the provided configuration settings.
		 *
		 * @param bool  $is_pro        Indicates whether the user has a professional (pro) account.
		 * @param array $erce_settings An array of settings used to configure AJAX handling.
		 *
		 * @since 1.0.0
		 */
		public function __construct( $is_pro, $erce_settings ) {
			$this->is_pro   = $is_pro;
			$this->settings = $erce_settings;
			add_action( 'wp_ajax_ecre_notice_action', array( $this, 'manage_notices' ) );
			add_action( 'wp_ajax_nopriv_ecre_notice_action', array( $this, 'manage_notices' ) );
			add_action( 'wp_ajax_ecre_save_settings', array( $this, 'ecre_save_settings_callback' ) );
			add_action( 'wp_ajax_ecre_fetch_settings', array( $this, 'ecre_fetch_settings_callback' ) );
			add_action( 'wp_ajax_nopriv_ecre_fetch_settings', array( $this, 'ecre_fetch_settings_callback' ) );
			add_action( 'wp_ajax_ecre_fetch_referral_coupon', array( $this, 'ecre_fetch_referral_coupon_callback' ) );
			add_action( 'wp_ajax_nopriv_ecre_fetch_referral_coupon', array( $this, 'ecre_fetch_referral_coupon_callback' ) );
			add_action( 'wp_ajax_ecre_fetch_invite_coupons', array( $this, 'ecre_fetch_invite_coupons_callback' ) );
			add_action( 'wp_ajax_nopriv_ecre_fetch_invite_coupons', array( $this, 'ecre_fetch_invite_coupons_callback' ) );
			add_action( 'wp_ajax_ecre_send_invite_email', array( $this, 'ecre_send_email_handler' ) );
			add_action( 'wp_ajax_nopriv_ecre_send_invite_email', array( $this, 'ecre_send_email_handler' ) );
			add_action( 'wp_ajax_fetch_products_and_categories', array( $this, 'fetch_products_and_categories' ) );
			add_action( 'wp_ajax_nopriv_fetch_products_and_categories', array( $this, 'fetch_products_and_categories' ) );
			add_action( 'wp_ajax_ecre_fetch_reward_coupons', array( $this, 'ecre_fetch_reward_coupons' ) );
			add_action( 'wp_ajax_nopriv_ecre_fetch_reward_coupons', array( $this, 'ecre_fetch_reward_coupons' ) );
			add_action( 'wp_ajax_ecre_fetch_reward_points', array( $this, 'ecre_fetch_reward_points' ) );
			add_action( 'wp_ajax_nopriv_ecre_fetch_reward_points', array( $this, 'ecre_fetch_reward_points' ) );
			add_action( 'wp_ajax_fetch_wp_pages', array( $this, 'fetch_wp_pages' ) );
			add_action( 'wp_ajax_fetch_wp_pages', array( $this, 'fetch_wp_pages' ) );
			add_action( 'wp_ajax_get_chart_data', array( $this, 'ecre_chart_data_handle' ) );
			add_action( 'wp_ajax_nopriv_get_chart_data', array( $this, 'ecre_chart_data_handle' ) );
			add_action( 'wp_ajax_install_activate_woocommerce', array( $this, 'ecre_install_activate_woocommerce' ) );
			add_action( 'wp_ajax_activate_woocommerce', array( $this, 'ecre_activate_woocommerce' ) );
			// Add these lines to the constructor after the existing actions.
			add_action( 'wp_ajax_ecre_fetch_referrers', array( $this, 'ecre_fetch_referrers_handle' ) );
			add_action( 'wp_ajax_ecre_fetch_dashboard_summary', array( $this, 'ecre_fetch_dashboard_summary_handle' ) );
			add_action( 'wp_ajax_ecre_fetch_referrer_dashboard', array( $this, 'ecre_fetch_referrer_dashboard_handle' ) );
			add_action( 'wp_ajax_ecre_fetch_referrer_history', array( $this, 'ecre_fetch_referrer_history_handle' ) );
			// Add this line in the Ecre_Ajax constructor after the existing add_action calls:.
			add_action( 'wp_ajax_ecre_fetch_referrer_reward_coupons', array( $this, 'ecre_fetch_referrer_reward_coupons_handle' ) );
			add_action( 'wp_ajax_ecre_fetch_referrer_reward_points', array( $this, 'ecre_fetch_referrer_reward_points_handle' ) );

			add_action( 'wp_ajax_ecre_fetch_user_points_summary', array( $this, 'ecre_fetch_user_points_summary_handle' ) );

			// ADD these lines to the constructor after existing actions.
			add_action( 'wp_ajax_ecre_save_user_reward_settings', array( $this, 'ecre_save_user_reward_settings_handle' ) );
			add_action( 'wp_ajax_ecre_fetch_user_reward_settings', array( $this, 'ecre_fetch_user_reward_settings_handle' ) );
			add_action( 'wp_ajax_ecre_reset_user_reward_settings', array( $this, 'ecre_reset_user_reward_settings_handle' ) );
			add_action( 'wp_ajax_ecre_issue_reward_points', array( $this, 'ecre_issue_reward_points_handle' ) );
			// ADD this line to the constructor after existing actions.
			add_action( 'wp_ajax_ecre_issue_reward_coupon', array( $this, 'ecre_issue_reward_coupon_handle' ) );
			add_action( 'wp_ajax_ecre_check_update_progress', array( $this, 'ecre_check_update_progress_callback' ) );
		}

		/**
		 * Fetches the current reward points for the user.
		 *
		 * This method verifies the security nonce to ensure the request is valid,
		 * retrieves the user's reward points, and sends the points back as a JSON response.
		 * It is intended to be used with AJAX calls for updating the frontend without a page refresh.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function ecre_fetch_reward_points() {
			// Verify nonce for security.
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );
			$reward_points = ecre_get_points();

			// Return the settings as JSON.
			wp_send_json_success( $reward_points );
		}

		/**
		 * Retrieves the available reward coupons for the user.
		 *
		 * This method fetches the user's reward coupons and returns them
		 * as a JSON response. It is intended for use with AJAX calls to
		 * dynamically update the frontend with the user's available coupons.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function ecre_fetch_reward_coupons() {
			// Verify nonce for security.
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );
			$reward_coupons = ecre_reward_coupons();

			// Return the settings as JSON.
			wp_send_json_success( $reward_coupons );
		}

		/**
		 * Fetches all published products and their associated categories.
		 *
		 * This method verifies the security nonce to ensure the request is valid,
		 * retrieves all products and categories from the WordPress database,
		 * and sends the data back as a JSON response. It is intended for use
		 * with AJAX calls to dynamically update the frontend with the list of
		 * products and categories.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function fetch_products_and_categories() {
			// Verify nonce for security.
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			global $wpdb;

			// Fetch all products.
			//phpcs:ignore
			$products = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT p.ID as id, p.post_title as text
				FROM {$wpdb->posts} p
				WHERE p.post_type = %s
				  AND p.post_status = %s",
					'product',
					'publish'
				)
			);

			// Fetch all categories.
			//phpcs:ignore
			$categories = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT t.term_id as id, t.name as text
					FROM {$wpdb->terms} t
					INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
					WHERE tt.taxonomy = %s",
					'product_cat'
				)
			);

			// Send the data back to the client.
			wp_send_json_success(
				array(
					'products'   => $products,
					'categories' => $categories,
				)
			);
		}

		/**
		 * Retrieves the invite coupons for the user.
		 *
		 * This method verifies the security nonce to ensure the request is valid,
		 * fetches the invite coupons using the `ecre_referral_coupons_with_usage`
		 * function, and sends the data back as a JSON response. It is intended
		 * for use with AJAX calls to dynamically provide invite coupon information
		 * to the client.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function ecre_fetch_invite_coupons_callback() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Retrieve settings from the database.
			$invite_coupons = ecre_referral_coupons_with_usage();

			// Return the settings as JSON.
			wp_send_json_success( $invite_coupons );
		}

		/**
		 * Saves the plugin settings provided via AJAX with cancellation support.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function ecre_save_settings_callback() {
			// Ensure the existence of $_POST and unslash it.
			$settings_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();

			// Verify nonce.
			if ( ! isset( $settings_data['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $settings_data['nonce'] ), 'ecre_admin_nonce' ) ) {
				wp_send_json_error( __( 'Invalid nonce', 'echo-rewards' ) );
			}

			$settings = isset( $settings_data['settings'] ) ? json_decode( $settings_data['settings'], true ) : array();

			if ( $settings ) {
				// Generate unique process ID for cancellation.
				$process_id = 'coupon_update_' . wp_generate_uuid4();

				// Cancel any existing scheduled actions.
				if ( function_exists( 'as_unschedule_all_actions' ) ) {
					as_unschedule_all_actions( 'ecre_background_update_coupons' );
				}

				// Store current process ID.
				update_option( 'ecre_current_coupon_process', $process_id );

				// Save settings immediately.
				update_option( 'ecre_settings', $settings );

				// Schedule background coupon update.
				if ( function_exists( 'as_enqueue_async_action' ) ) {
					as_enqueue_async_action(
						'ecre_background_update_coupons',
						array(
							'settings'   => $settings,
							'process_id' => $process_id,
						),
						'ecre_coupon_updates'
					);

					wp_send_json_success(
						array(
							'message'    => 'Settings saved successfully. Coupon updates are processing in the background.',
							'process_id' => $process_id,
						)
					);
				} else {
					// Fallback to synchronous update if Action Scheduler not available.
					ecre_update_referral_coupons( $settings, $process_id );
					wp_send_json_success( 'Settings saved successfully' );
				}
			} else {
				wp_send_json_error( 'Invalid settings data' );
			}
		}

		/**
		 * Check coupon update progress
		 */
		public function ecre_check_update_progress_callback() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			$progress        = get_option( 'ecre_coupon_update_in_progress', array() );
			$current_process = get_option( 'ecre_current_coupon_process', '' );

			$response = array(
				'has_active_process' => ! empty( $current_process ),
				'process_id'         => $current_process,
				'status'             => isset( $progress['status'] ) ? $progress['status'] : 'idle',
				'started_at'         => isset( $progress['started_at'] ) ? $progress['started_at'] : null,
				'completed_at'       => isset( $progress['completed_at'] ) ? $progress['completed_at'] : null,
				'cancelled_at'       => isset( $progress['cancelled_at'] ) ? $progress['cancelled_at'] : null,
			);

			wp_send_json_success( $response );
		}

		/**
		 * Fetches the current plugin settings.
		 *
		 * This method verifies the security nonce to ensure the request is valid
		 * and sends the current settings as a JSON response. It is intended for
		 * use with AJAX calls to allow the client to retrieve the latest settings
		 * configuration.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function ecre_fetch_settings_callback() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );
			// Return the settings as JSON.
			wp_send_json_success( $this->settings );
		}

		/**
		 * Fetches the referral coupon details and current usage limits.
		 *
		 * Performs a database-first lookup against the wp_ecre_referrers custom table
		 * for fast, real-time retrieval. Falls back to the legacy ecre_referral_coupons()
		 * helper when the custom table does not exist or contains no record for the user.
		 *
		 * @since 1.0.0
		 * @since 2.6.0 Refactored to use wp_ecre_referrers custom table lookup.
		 * @return void
		 */
		public function ecre_fetch_referral_coupon_callback() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			global $wpdb;

			$user_id = get_current_user_id();

			// --- Database-first lookup via wp_ecre_referrers custom table ---
			$referrers_table = $wpdb->prefix . 'ecre_referrers';
			$coupon_code     = '';

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$table_exists = $wpdb->get_var(
				$wpdb->prepare( 'SHOW TABLES LIKE %s', $referrers_table )
			) === $referrers_table;

			if ( $table_exists ) {
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$coupon_code = $wpdb->get_var(
					$wpdb->prepare(
						// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
						"SELECT referral_coupon_code FROM {$referrers_table} WHERE user_id = %d LIMIT 1",
						$user_id
					)
				);
			}

			// Fallback to legacy lookup if custom table is missing or user has no record.
			if ( empty( $coupon_code ) ) {
				$referral_coupon = ecre_referral_coupons();
				if ( ! empty( $referral_coupon ) ) {
					$coupon_code = $referral_coupon[0]['coupon_code'];
				}
			}

			$coupon_code = strtoupper( (string) $coupon_code );
			// Discount info comes from the plugin settings (supports custom per-user overrides).
			$referral_discount_type = $this->settings['referralCouponType']['value'];
			$referral_discount      = $this->settings['referralDiscount'];
			$monthly_referral_limit = $this->settings['referralMonthlyLimit'] ? $this->settings['referralMonthlyLimit'] : 0;

			$monthly_limit_reached = 0;

			if ( $this->is_pro ) {
				// Cache monthly limit check.
				$limit_cache_key       = 'ecre_monthly_limit_' . $user_id;
				$monthly_limit_reached = get_transient( $limit_cache_key );

				if ( false === $monthly_limit_reached ) {
					$monthly_limit_reached = ecre_monthly_referral_coupons_usage();
					set_transient( $limit_cache_key, $monthly_limit_reached, 300 );
				}
			}

			$is_monthly_limit_reached = false;
			$current_referral_limit   = 0;

			$reward_discount      = $this->settings['rewardDiscount'];
			$reward_discount_type = $this->settings['rewardType']['value'];

			if ( 'percent' === $referral_discount_type ) {
				$referral_discount = $referral_discount . '%';
			} else {
				$referral_discount = ecre_format_price( $referral_discount );
			}

			if ( 'percent' === $reward_discount_type || 'sign_up_fee_percent' === $reward_discount_type || 'recurring_percent' === $reward_discount_type ) {
				$reward_discount = $reward_discount . '%';
			} elseif ( 'reward_point' !== $reward_discount_type ) {
				$reward_discount = ecre_format_price( $reward_discount );
			}

			if ( $this->is_pro && ! empty( $monthly_referral_limit ) && $monthly_referral_limit > 0 ) {
				if ( $monthly_limit_reached >= $monthly_referral_limit ) {
					$is_monthly_limit_reached = true;
					$current_referral_limit   = 0;
				} else {
					$current_referral_limit = $monthly_referral_limit - $monthly_limit_reached;
				}
			}

			$response = array(
				'coupon_code'                    => $coupon_code,
				'referral_discount'              => $referral_discount,
				'reward_discount'                => $reward_discount,
				'is_monthly_limit_reached'       => $is_monthly_limit_reached,
				'referrals_remaining_this_month' => $current_referral_limit,
				'discount_type'                  => $referral_discount_type,
			);

			wp_send_json_success( $response );
		}

		/**
		 * Handles sending email via AJAX.
		 *
		 * @since 1.0.0
		 */
		public function ecre_send_email_handler() {
			// Ensure the existence of $_POST and unslash it.
			$email_data = isset( $_POST ) ? wp_unslash( $_POST ) : array();

			// Verify nonce.
			if ( ! isset( $email_data['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $email_data['nonce'] ), 'ecre_admin_nonce' ) ) {
				wp_send_json_error( __( 'Invalid nonce', 'echo-rewards' ) );
			}

			// Retrieve settings from the database.
			$ecre_currency_sign = ecre_custom_currency_symbol();

			$recipient_name         = $email_data['name'];
			$recipient_email        = $email_data['email'];
			$coupon_code            = '';
			$referral_discount_type = '';
			$referral_discount      = '';
			$referral_user_id       = get_current_user_id();
			$email_type             = 'referral_email';
			$response               = '';
			$referral_coupon        = ecre_referral_coupons();

			if ( ! empty( $referral_coupon ) ) {
				$coupon_code            = strtoupper( $referral_coupon[0]['coupon_code'] );
				$referral_discount_type = $referral_coupon[0]['discount_type'];
				$referral_discount      = $referral_coupon[0]['discount'];
			}

			if ( 'percent' === $referral_discount_type ) {
				$referral_discount = $referral_discount . '%';
			} else {
				$referral_discount = $referral_discount . $ecre_currency_sign;
			}

			// If enable mail settings then only run.
			$wc_emails       = WC()->mailer();
			$emails_array    = $wc_emails->get_emails();
			$new_order_email = $emails_array['Ecre_Email'];
			$send_status     = $new_order_email->trigger( $referral_user_id, esc_html( $coupon_code ), $recipient_name, $recipient_email, $email_type, $referral_discount );

			if ( true === $send_status ) {
				$response = 'success';
			} else {
				$response = 'fail';
			}

			// Return the data as JSON.
			wp_send_json( $response );

			// Make sure to exit to avoid extra output.
			exit();
		}

		/**
		 * Manage notices ajax endpoint response.
		 *
		 * @since 2.12.15
		 */
		public function manage_notices() {
			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'ecre_notices_nonce' ) ) {
				wp_send_json_error(
					array(
						'message' => __( 'Invalid action', 'echo-rewards' ),
					)
				);
			}

			$action_type = isset( $_POST['actionType'] ) ? sanitize_text_field( wp_unslash( $_POST['actionType'] ) ) : '';
			$info_type   = isset( $_POST['info']['type'] ) ? sanitize_text_field( wp_unslash( $_POST['info']['type'] ) ) : '';
			$info_value  = isset( $_POST['info']['value'] ) ? sanitize_text_field( wp_unslash( $_POST['info']['value'] ) ) : '';

			if ( 'hide_notice' === $info_type ) {
				$this->hide_notice( $action_type );
			}

			if ( 'reminder' === $info_type ) {
				$this->set_reminder( $action_type, $info_value );
			}
		}

		/**
		 * Hide notices.
		 *
		 * @param string $action_type The action type.
		 * @since 2.12.15
		 */
		public function hide_notice( $action_type ) {
			if ( 'review_notice' === $action_type ) {
				update_option( 'ecre_review_notice', true );
			}

			if ( 'affiliate_notice' === $action_type ) {
				update_option( 'ecre_affiliate_notice', true );
			}

			if ( 'upgrade_notice' === $action_type ) {
				update_option( 'ecre_upgrade_notice', true );
			}

			wp_send_json_success(
				array(
					'response_type' => 'success',
				)
			);
		}

		/**
		 * Set reminder to display notice.
		 *
		 * @param string $action_type The action type.
		 * @param string $info_value  The reminder value.
		 * @since 2.12.15
		 */
		public function set_reminder( $action_type, $info_value = '' ) {
			if ( 'hide_notice' === $info_value ) {
				$this->hide_notice( $action_type );
				wp_send_json_success(
					array(
						'response_type' => 'success',
					)
				);
			} else {

				if ( 'review_notice' === $action_type ) {
					update_option( 'ecre_deafult_review_notice_interval', ( time() + intval( $info_value ) * 24 * 60 * 60 ) );
				}

				if ( 'affiliate_notice' === $action_type ) {
					update_option( 'ecre_deafult_affiliate_notice_interval', ( time() + intval( $info_value ) * 24 * 60 * 60 ) );
				}

				if ( 'upgrade_notice' === $action_type ) {
					update_option( 'ecre_deafult_upgrade_notice_interval', ( time() + intval( $info_value ) * 24 * 60 * 60 ) );
				}

				wp_send_json_success(
					array(
						'response_type' => 'success',
					)
				);
			}
		}

		/**
		 * Fetches all WordPress pages.
		 *
		 * This method verifies the security nonce to ensure the request is valid
		 * and retrieves a list of all published WordPress pages. The fetched
		 * pages are then returned as a JSON response.
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function fetch_wp_pages() {
			// Verify nonce for security.
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );
			$pages = ecre_get_all_wp_pages();

			// Return the settings as JSON.
			wp_send_json_success( $pages );
		}

		/**
		 * Handles AJAX requests to fetch and return chart data based on specified parameters.
		 *
		 * This function is responsible for processing AJAX requests to fetch chart data based on the
		 * specified time range and report tab. It retrieves relevant data using various helper functions
		 * and returns the result as JSON. The function covers different report tabs, including new users
		 * gained through referral and total referral coupons, with specific time range options.
		 *
		 * @return void
		 */
		public function ecre_chart_data_handle() {

			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Ensure the existence of $_POST['report_fetch_data'] and unslash and sanitize it.
			$fetch_data = isset( $_POST['report_fetch_data'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['report_fetch_data'] ) ) : array();

			$time_range = $this->is_pro ? $fetch_data['time_range'] : 'echo_range_last_week';
			$report_tab = $fetch_data['report_tab'];

			if ( 'total_referral_coupons' === $report_tab ) {
				switch ( $time_range ) {
					case 'echo_range_year':
						$chart_data  = ecre_get_referral_order_data( 'yearly' );
						$top_coupons = ecre_get_top_10_coupons_with_referral( 'yearly' );
						$data        = array(
							'chart_data'  => $chart_data,
							'top_coupons' => $top_coupons,
						);
						break;
					case 'echo_range_last_month':
						$chart_data  = ecre_get_referral_order_data( 'last_month' );
						$top_coupons = ecre_get_top_10_coupons_with_referral( 'last_month' );
						$data        = array(
							'chart_data'  => $chart_data,
							'top_coupons' => $top_coupons,
						);
						break;
					case 'echo_range_this_month':
						$chart_data  = ecre_get_referral_order_data( 'current_month' );
						$top_coupons = ecre_get_top_10_coupons_with_referral( 'current_month' );
						$data        = array(
							'chart_data'  => $chart_data,
							'top_coupons' => $top_coupons,
						);
						break;
					case 'echo_range_last_week':
						$chart_data  = ecre_get_referral_order_data( '7_days' );
						$top_coupons = ecre_get_top_10_coupons_with_referral( '7_days' );
						$data        = array(
							'chart_data'  => $chart_data,
							'top_coupons' => $top_coupons,
						);
						break;
					default:
						$data = array();
				}
			} elseif ( 'total_sales_coupons' === $report_tab ) {
				switch ( $time_range ) {
					case 'echo_range_year':
						$data = array(
							'chart_data' => ecre_get_sales_data( 'yearly' ),
						);
						break;
					case 'echo_range_last_month':
						$data = array(
							'chart_data' => ecre_get_sales_data( 'last_month' ),
						);
						break;
					case 'echo_range_this_month':
						$data = array(
							'chart_data' => ecre_get_sales_data( 'current_month' ),
						);
						break;
					case 'echo_range_last_week':
						$data = array(
							'chart_data' => ecre_get_sales_data( '7_days' ),
						);
						break;
					default:
						$data = array();
				}
			} elseif ( 'total_discount_coupons' === $report_tab ) {
				switch ( $time_range ) {
					case 'echo_range_year':
						$data = array(
							'chart_data' => ecre_get_discount_data( 'yearly' ),
						);
						break;
					case 'echo_range_last_month':
						$data = array(
							'chart_data' => ecre_get_discount_data( 'last_month' ),
						);
						break;
					case 'echo_range_this_month':
						$data = array(
							'chart_data' => ecre_get_discount_data( 'current_month' ),
						);
						break;
					case 'echo_range_last_week':
						$data = array(
							'chart_data' => ecre_get_discount_data( '7_days' ),
						);
						break;
					default:
						$data = array();
				}
			}

			// Return the data as JSON.
			wp_send_json( $data );

			// Make sure to exit to avoid extra output.
			exit();
		}

		/**
		 * Install and activate WooCommerce plugin.
		 *
		 * This method should be added to your Ecre_Ajax class.
		 */
		public function ecre_install_activate_woocommerce() {
			// Check nonce for security.
			if ( ! check_ajax_referer( 'ecre_admin_nonce', 'security', false ) ) {
				wp_send_json_error( 'Invalid security token' );
				return;
			}

			// Check user capabilities.
			if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) {
				wp_send_json_error( 'You do not have permission to install or activate plugins' );
				return;
			}

			// Include required files for plugin installation.
			if ( ! function_exists( 'plugins_api' ) ) {
				require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
			}

			if ( ! class_exists( 'WP_Upgrader' ) ) {
				require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
			}

			if ( ! class_exists( 'Plugin_Upgrader' ) ) {
				require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
			}

			if ( ! class_exists( 'WP_Upgrader_Skin' ) ) {
				require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skin.php';
			}

			// We need to define the Skin outside the class
			// Use a basic upgrader skin.
			$skin = new \WP_Ajax_Upgrader_Skin();

			// Get WooCommerce plugin info.
			// Get WooCommerce plugin info.
			$api = plugins_api(
				'plugin_information',
				array(
					'slug'   => 'woocommerce',
					'fields' => array(
						'short_description' => false,
						'sections'          => false,
						'requires'          => false,
						'rating'            => false,
						'ratings'           => false,
						'downloaded'        => false,
						'last_updated'      => false,
						'added'             => false,
						'tags'              => false,
						'compatibility'     => false,
						'homepage'          => false,
						'donate_link'       => false,
					),
				)
			);

			if ( is_wp_error( $api ) ) {
				wp_send_json_error( $api->get_error_message() );
				return;
			}

			// Install WooCommerce.
			$upgrader       = new \Plugin_Upgrader( $skin );
			$install_result = $upgrader->install( $api->download_link );

			if ( is_wp_error( $install_result ) ) {
				wp_send_json_error( $install_result->get_error_message() );
				return;
			}

			if ( false === $install_result ) {
				// Check if there were any errors in the skin.
				if ( $skin->get_errors()->has_errors() ) {
					wp_send_json_error( $skin->get_errors()->get_error_message() );
					return;
				}
				wp_send_json_error( 'There was an error installing WooCommerce' );
				return;
			}

			// Activate WooCommerce.
			$activate_result = activate_plugin( 'woocommerce/woocommerce.php' );

			if ( is_wp_error( $activate_result ) ) {
				wp_send_json_error( $activate_result->get_error_message() );
				return;
			}

			wp_send_json_success( 'WooCommerce installed and activated successfully' );
		}

		/**
		 * Activate WooCommerce plugin.
		 *
		 * This method should be added to your Ecre_Ajax class.
		 */
		public function ecre_activate_woocommerce() {
			// Check nonce for security.
			if ( ! check_ajax_referer( 'ecre_admin_nonce', 'security', false ) ) {
				wp_send_json_error( 'Invalid security token' );
				return;
			}

			// Check user capabilities.
			if ( ! current_user_can( 'activate_plugins' ) ) {
				wp_send_json_error( 'You do not have permission to activate plugins' );
				return;
			}

			// Check if WooCommerce is already activated.
			if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
				wp_send_json_success( 'WooCommerce is already activated' );
				return;
			}

			// Activate WooCommerce.
			$activate_result = activate_plugin( 'woocommerce/woocommerce.php' );

			if ( is_wp_error( $activate_result ) ) {
				wp_send_json_error( $activate_result->get_error_message() );
				return;
			}

			wp_send_json_success( 'WooCommerce activated successfully' );
		}

		/**
		 * Handle AJAX request to fetch referrers with server-side pagination, filtering, and search
		 */
		public function ecre_fetch_referrers_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Get parameters.
			$page        = intval( $_POST['page'] ?? 1 );
			$per_page    = intval( $_POST['per_page'] ?? 10 );
			$search      = sanitize_text_field( wp_unslash( $_POST['search'] ?? '' ) );  // Unsashed before sanitization.
			$time_filter = sanitize_text_field( wp_unslash( $_POST['time_filter'] ?? 'All Time' ) );

			// Check if custom rewards and referrals filters are set with Yoda condition.
			$custom_rewards_filter   = '1' === sanitize_text_field( wp_unslash( $_POST['custom_rewards_filter'] ?? '' ) );
			$custom_referrals_filter = '1' === sanitize_text_field( wp_unslash( $_POST['custom_referrals_filter'] ?? '' ) );

			// Ensure valid pagination parameters.
			$page = max( 1, $page );
			$per_page = max( 1, min( 100, $per_page ) ); // Limit max per page to 100.

			// Get referrers data using database class.
			$database = new \ECRE\Ecre_Database();

			$result = $database->get_referrers_with_pagination(
				$page,
				$per_page,
				$search,
				$time_filter,
				$custom_rewards_filter,
				$custom_referrals_filter
			);

			wp_send_json_success( $result );
		}

		/**
		 * Handle AJAX request to fetch dashboard summary
		 */
		public function ecre_fetch_dashboard_summary_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );
			$database = new \ECRE\Ecre_Database();
			$summary  = $database->get_dashboard_summary();
			wp_send_json_success( $summary );
		}

		/**
		 * Handle AJAX request to fetch single referrer dashboard summary by user_id
		 */
		public function ecre_fetch_referrer_dashboard_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			$user_id = intval( $_POST['user_id'] ?? 0 );

			if ( ! $user_id ) {
				wp_send_json_error( 'Invalid user ID' );
				return;
			}

			$database = new \ECRE\Ecre_Database();
			$referrer = $database->get_referrer_dashboard_summary( $user_id );

			if ( ! $referrer ) {
				wp_send_json_error( 'Referrer not found' );
				return;
			}

			wp_send_json_success( $referrer );
		}

		/**
		 * Handle AJAX request to fetch referral history for a specific referrer
		 */
		public function ecre_fetch_referrer_history_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Get parameters.
			$referrer_user_id = intval( $_POST['referrer_user_id'] ?? 0 );
			$page             = intval( $_POST['page'] ?? 1 );
			$per_page         = intval( $_POST['per_page'] ?? 10 );
			$time_filter      = sanitize_text_field( wp_unslash( $_POST['time_filter'] ?? 'All Time' ) );

			// Validate referrer user ID.
			if ( ! $referrer_user_id ) {
				wp_send_json_error( 'Invalid referrer user ID' );
				return;
			}

			// Ensure valid pagination parameters.
			$page     = max( 1, $page );
			$per_page = max( 1, min( 100, $per_page ) );

			// Get referral history data using database class.
			$database = new \ECRE\Ecre_Database();
			$result   = $database->get_referrer_history_with_pagination(
				$referrer_user_id,
				$page,
				$per_page,
				$time_filter
			);

			wp_send_json_success( $result );
		}

		/**
		 * Handle AJAX request to fetch reward coupons for a specific referrer
		 * Add this method to the Ecre_Ajax class
		 */
		public function ecre_fetch_referrer_reward_coupons_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Get parameters.
			$referrer_user_id = intval( $_POST['referrer_user_id'] ?? 0 );
			$page             = intval( $_POST['page'] ?? 1 );
			$per_page         = intval( $_POST['per_page'] ?? 10 );
			$time_filter      = sanitize_text_field( wp_unslash( $_POST['time_filter'] ?? 'All Time' ) );

			// Validate referrer user ID.
			if ( ! $referrer_user_id ) {
				wp_send_json_error( 'Invalid referrer user ID' );
				return;
			}

			// Ensure valid pagination parameters.
			$page     = max( 1, $page );
			$per_page = max( 1, min( 100, $per_page ) );

			// Get reward coupons data using database class.
			$database = new \ECRE\Ecre_Database();

			$result = $database->get_referrer_reward_coupons_with_pagination(
				$referrer_user_id,
				$page,
				$per_page,
				$time_filter
			);

			wp_send_json_success( $result );
		}

		/**
		 * Handle AJAX request to fetch reward points for a specific referrer
		 */
		public function ecre_fetch_referrer_reward_points_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Get parameters.
			$referrer_user_id = intval( $_POST['referrer_user_id'] ?? 0 );
			$page             = intval( $_POST['page'] ?? 1 );
			$per_page         = intval( $_POST['per_page'] ?? 10 );
			$time_filter      = sanitize_text_field( wp_unslash( $_POST['time_filter'] ?? 'All Time' ) );

			// Validate referrer user ID.
			if ( ! $referrer_user_id ) {
				wp_send_json_error( 'Invalid referrer user ID' );
				return;
			}

			// Ensure valid pagination parameters.
			$page     = max( 1, $page );
			$per_page = max( 1, min( 100, $per_page ) );

			// Get reward points data using database class.
			$database = new \ECRE\Ecre_Database();
			$result   = $database->get_referrer_reward_points_with_pagination(
				$referrer_user_id,
				$page,
				$per_page,
				$time_filter
			);

			wp_send_json_success( $result );
		}

		/**
		 * Handles the AJAX request to fetch a user's reward points summary.
		 *
		 * This function retrieves the summary of a user's reward points, including the total points, available points,
		 * applied points, and points redemption status. It also checks for an expiry date of the reward points, formats
		 * the expiry date, and determines the expiry status. The summary data is returned in JSON format, with success or
		 * error responses depending on the input and retrieved data.
		 *
		 * @since 1.0.0
		 *
		 * @return void Outputs a JSON response containing the user's reward points summary, or an error message if the user ID is invalid.
		 */
		public function ecre_fetch_user_points_summary_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			$user_id = intval( $_POST['user_id'] ?? 0 );

			if ( ! $user_id ) {
				wp_send_json_error( 'Invalid user ID' );
				return;
			}

			$total_points         = intval( get_user_meta( $user_id, 'ecre_reward_points', true ) );
			$total_applied_points = intval( get_user_meta( $user_id, 'ecre_applied_reward_points', true ) );
			$available_points     = intval( get_user_meta( $user_id, 'ecre_available_points', true ) );

			// Get expiry date and status.
			$reward_point_expiry_date = get_user_meta( $user_id, 'ecre_reward_point_expiry_date', true );
			$formatted_expiry_date    = '';
			$expiry_status            = '';

			if ( $reward_point_expiry_date ) {
				$formatted_expiry_date = gmdate( 'jS F, Y', strtotime( $reward_point_expiry_date ) );
				$expiry_status         = ecre_get_expiry_status( $formatted_expiry_date );
			}

			$summary = array(
				'total_points'     => $total_points,
				'available_points' => $available_points,
				'applied_points'   => $total_applied_points,
				'redeemed_points'  => $total_applied_points,
				'expiry_date'      => $formatted_expiry_date,
				'expiry_status'    => $expiry_status,
			);

			wp_send_json_success( $summary );
		}

		/**
		 * Handle AJAX request to save user-specific reward settings
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function ecre_save_user_reward_settings_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Sanitize and validate input data.
			$user_id       = intval( $_POST['user_id'] ?? 0 );
			$settings_json = isset( $_POST['settings'] ) ? sanitize_textarea_field( wp_unslash( $_POST['settings'] ) ) : '{}';
			$settings      = json_decode( $settings_json, true );

			if ( ! $user_id ) {
				wp_send_json_error( 'Invalid user ID' );
				return;
			}

			if ( JSON_ERROR_NONE !== json_last_error() ) {
				wp_send_json_error( 'Invalid JSON settings data' );
				return;
			}

			// Check if this is a referral coupon update.
			$is_referral_coupon_update = isset( $settings['referral_coupon_update'] ) && $settings['referral_coupon_update'];

			// Handle referral coupon update with excerpt.
			if ( $is_referral_coupon_update ) {
				$coupon_code          = sanitize_text_field( $settings['coupon_code'] ?? '' );
				$coupon_id            = intval( $settings['coupon_id'] ?? 0 );
				$referral_discount    = floatval( $settings['referralDiscount'] ?? 0 );
				$global_discount_type = $this->settings['referralCouponType']['value'];

				if ( $coupon_id && $coupon_code && $referral_discount > 0 ) {
					// Get currency symbol for excerpt.
					$currency_symbol = function_exists( 'ecre_pro_custom_currency_symbol' ) ?
						ecre_pro_custom_currency_symbol() : '$';

					// Create discount display text.
					$discount_text = ( 'percent' === $global_discount_type ) ?
						$referral_discount . '%' :
						$referral_discount . $currency_symbol;

					// Update the existing referral coupon.
					update_post_meta( $coupon_id, 'coupon_amount', $referral_discount );
					update_post_meta( $coupon_id, 'ecre_custom_referral', '1' );

					// Update post excerpt with new discount amount.
					wp_update_post(
						array(
							'ID'           => $coupon_id,
							'post_excerpt' => $discount_text . ' off coupon',
							'post_content' => $discount_text . ' off coupon',
						)
					);
				}
			}

			// Define allowed settings with their data types.
			$allowed_settings = array(
				// Reward Points settings.
				'rewardPoint'                   => 'number',
				'redeemPoint'                   => 'number',
				'redeemLimit'                   => 'number',
				'enableRedeemLimit'             => 'boolean',
				'redeemDiscount'                => 'number',

				// Reward Coupons settings.
				'rewardType'                    => 'array',
				'rewardDiscount'                => 'number',
				'rewardDiscountCapping'         => 'number',
				'enableRewardExpiry'            => 'boolean',
				'rewardCouponValidity'          => 'number',
				'enableRewardCouponUsageLimit'  => 'boolean',
				'rewardCouponUsageLimit'        => 'number',

				// Referral settings.
				'referralDiscount'              => 'number',
				'referralDiscountCapping'       => 'number',
				'enableReferralLimit'           => 'boolean',
				'referralMonthlyLimit'          => 'number',
				'referralMinimumPurchaseAmount' => 'number',

				// Common settings.
				'rewardMinimumPurchaseAmount'   => 'number',
			);

			if ( ! class_exists( '\ECRE\Ecre_Database' ) ) {
				wp_send_json_error( 'Database class not found' );
				return;
			}

			$database       = new \ECRE\Ecre_Database();
			$saved_settings = array();

			// Process and save allowed settings.
			foreach ( $settings as $setting_key => $setting_value ) {
				if ( array_key_exists( $setting_key, $allowed_settings ) ) {
					$data_type = $allowed_settings[ $setting_key ];

					// Handle different data types.
					if ( 'number' === $data_type ) {
						$setting_value = floatval( $setting_value );
					} elseif ( 'boolean' === $data_type ) {
						$setting_value = (bool) $setting_value;
					} elseif ( 'array' === $data_type ) {
						// For array types, ensure it's a valid array structure.
						if ( ! is_array( $setting_value ) ) {
							continue;
						}
					}

					if ( $database->save_user_reward_setting( $user_id, $setting_key, $setting_value, $data_type ) ) {
						$saved_settings[ $setting_key ] = $setting_value;
					}
				}
			}

			// Update flags in referrers table.
			global $wpdb;

			// Check if referral settings were saved.
			$referral_settings_keys = array(
				'referralDiscount',
				'referralDiscountCapping',
				'enableReferralLimit',
				'referralMonthlyLimit',
				'referralMinimumPurchaseAmount',
			);

			$has_referral_settings = array_intersect( $referral_settings_keys, array_keys( $saved_settings ) );

			// Determine which flags to set.
			$set_custom_rewards = ! empty( $saved_settings ); // Any saved settings means custom rewards.
			$set_custom_referrals = ! empty( $has_referral_settings ) || $is_referral_coupon_update;

			// Update the appropriate flags.
			if ( $set_custom_rewards ) {
				$this->update_custom_rewards_flag( $user_id );
			}

			if ( $set_custom_referrals ) {
				$this->update_custom_referrals_flag( $user_id );
			}

			wp_send_json_success(
				array(
					'message'        => 'User reward settings saved successfully',
					'saved_settings' => $saved_settings,
					'coupon_updated' => $is_referral_coupon_update,
				)
			);
		}

		/**
		 * Handle AJAX request to fetch user-specific reward settings
		 */
		public function ecre_fetch_user_reward_settings_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			$user_id = intval( $_POST['user_id'] ?? 0 );

			if ( ! $user_id ) {
				wp_send_json_error( 'Invalid user ID' );
				return;
			}

			$database             = new \ECRE\Ecre_Database();
			$global_settings      = get_option( 'ecre_settings', array() );
			$merged_settings      = $database->get_merged_user_settings( $user_id, $global_settings );
			$user_custom_settings = $database->get_user_custom_settings( $user_id );

			wp_send_json_success(
				array(
					'merged_settings'     => $merged_settings,
					'custom_settings'     => $user_custom_settings,
					'has_custom_settings' => ! empty( $user_custom_settings ),
				)
			);
		}

		/**
		 * Handle AJAX request to reset a user's reward settings.
		 *
		 * This function handles the AJAX request to reset a user's specific reward setting (or all settings) to the global defaults.
		 * It checks the nonce for security, validates the user ID, and performs the necessary updates in the database.
		 * If a referral coupon is associated with the settings, it will also reset the coupon's discount amount and other details.
		 *
		 * @since 1.0.0
		 *
		 * @return void Sends a JSON response with the success or failure message.
		 */
		public function ecre_reset_user_reward_settings_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			// Sanitize and validate input data.
			$user_id     = intval( $_POST['user_id'] ?? 0 );
			$setting_key = sanitize_text_field( wp_unslash( $_POST['setting_key'] ?? '' ) );

			if ( ! $user_id ) {
				wp_send_json_error( 'Invalid user ID' );
				return;
			}

			$database = new \ECRE\Ecre_Database();

			// Define referral settings keys for checking.
			$referral_settings_keys = array(
				'referralDiscount',
				'referralDiscountCapping',
				'enableReferralLimit',
				'referralMonthlyLimit',
				'referralMinimumPurchaseAmount',
			);

			// Check if we're resetting referral settings before deleting.
			$is_referral_reset = empty( $setting_key ) || in_array( $setting_key, $referral_settings_keys, true );

			// Get referrer info before deleting settings (if needed for coupon update).
			$referrer_info = null;
			if ( $is_referral_reset ) {
				global $wpdb;

				$referrer_info = $wpdb->get_row(
					$wpdb->prepare(
						"SELECT referral_coupon_id, referral_coupon_code FROM {$wpdb->prefix}ecre_referrers WHERE user_id = %d",
						$user_id
					)
				);
			}

			// Delete the settings.
			$result = $database->delete_user_reward_setting( $user_id, $setting_key ? $setting_key : null );

			if ( $result ) {
				// Handle referral coupon reset if needed.
				if ( $is_referral_reset && $referrer_info && $referrer_info->referral_coupon_id ) {
					// Get global settings for reset values.
					$global_settings = get_option( 'ecre_settings', array() );
					$global_discount = isset( $global_settings['referralDiscount'] ) ?
						floatval( $global_settings['referralDiscount'] ) : 10;

					// Get global coupon type with fallback.
					$global_coupon_type = 'percent'; // Default fallback.
					if ( isset( $global_settings['referralCouponType']['value'] ) ) {
						$global_coupon_type = sanitize_text_field( $global_settings['referralCouponType']['value'] );
					} elseif ( isset( $global_settings['referralCouponType'] ) && is_array( $global_settings['referralCouponType'] ) ) {
						$global_coupon_type = sanitize_text_field( $global_settings['referralCouponType']['value'] ?? 'percent' );
					}

					// Get currency symbol for excerpt.
					$currency_symbol = function_exists( 'ecre_pro_custom_currency_symbol' ) ?
						ecre_pro_custom_currency_symbol() : '$';

					// Create discount display text using global type.
					$discount_text = ( 'percent' === $global_coupon_type ) ?
						$global_discount . '%' :
						$global_discount . $currency_symbol;

					// Update the coupon amount back to global default.
					update_post_meta( $referrer_info->referral_coupon_id, 'coupon_amount', $global_discount );

					// Remove the custom referral meta.
					delete_post_meta( $referrer_info->referral_coupon_id, 'ecre_custom_referral' );

					// Update post excerpt and content with global discount.
					wp_update_post(
						array(
							'ID'           => $referrer_info->referral_coupon_id,
							'post_excerpt' => $discount_text . ' off coupon',
							'post_content' => $discount_text . ' off coupon',
						)
					);
				}

				$remaining_settings = $database->get_user_custom_settings( $user_id );

				// Update referrers table flags.
				global $wpdb;
				$update_data = array( 'updated_at' => current_time( 'mysql' ) );

				if ( empty( $remaining_settings ) ) {
					// No custom settings remaining - reset both flags.
					$update_data['custom_rewards'] = 0;
					$update_data['custom_referrals'] = 0;
				} else {
					// Check if any referral settings remain.
					$remaining_referral_settings = array_intersect( $referral_settings_keys, array_keys( $remaining_settings ) );
					if ( empty( $remaining_referral_settings ) ) {
						$update_data['custom_referrals'] = 0;
					}

					// Check if any reward settings remain.
					$reward_settings_keys = array(
						'rewardPoint',
						'redeemPoint',
						'redeemLimit',
						'enableRedeemLimit',
						'redeemDiscount',
						'rewardType',
						'rewardDiscount',
						'rewardDiscountCapping',
						'enableRewardExpiry',
						'rewardCouponValidity',
						'enableRewardCouponUsageLimit',
						'rewardCouponUsageLimit',
						'rewardMinimumPurchaseAmount',
					);
					$remaining_reward_settings = array_intersect( $reward_settings_keys, array_keys( $remaining_settings ) );
					if ( empty( $remaining_reward_settings ) ) {
						$update_data['custom_rewards'] = 0;
					}
				}

				$wpdb->update(
					$wpdb->prefix . 'ecre_referrers',
					$update_data,
					array( 'user_id' => $user_id ),
					array( '%s' ),
					array( '%d' )
				);

				wp_send_json_success(
					array(
						'message'             => $setting_key ?
							sprintf( "Setting '%s' reset to global default", $setting_key ) :
							'All settings reset to global defaults',
						'has_custom_settings' => ! empty( $remaining_settings ),
						'coupon_reset'        => $is_referral_reset && $referrer_info, // Add this flag.
					)
				);
			} else {
				wp_send_json_error( 'Failed to reset settings' );
			}
		}

		/**
		 * Handle AJAX request to issue reward points manually
		 */
		public function ecre_issue_reward_points_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			$user_id = intval( $_POST['user_id'] ?? 0 );
			$points  = intval( $_POST['points'] ?? 0 );

			if ( ! $user_id || ! $points ) {
				wp_send_json_error( 'Invalid user ID or points value' );
				return;
			}

			try {
				$database = new \ECRE\Ecre_Database();
				$result   = $database->issue_reward_points( $user_id, $points, 'manual_admin' );

				if ( $result ) {
					// Update custom_rewards flag in ecre_referrers table.
					$this->update_custom_rewards_flag( $user_id );

					wp_send_json_success(
						array(
							'message'       => 'Reward points issued successfully',
							'points_issued' => $points,
						)
					);
				} else {
					// ADD more specific error.
					wp_send_json_error( 'Database operation failed - check if reward_points table exists' );
				}
			} catch ( Exception $e ) {
				wp_send_json_error( 'Error: ' . $e->getMessage() );
			}
		}

		/**
		 * Handle AJAX request to issue reward coupon manually
		 */
		public function ecre_issue_reward_coupon_handle() {
			check_ajax_referer( 'ecre_admin_nonce', 'nonce' );

			$user_id            = intval( $_POST['user_id'] ?? 0 );
			$discount_amount    = floatval( $_POST['discount_amount'] ?? 0 );
			$discount_capping   = floatval( $_POST['discount_capping'] ?? 0 );
			$enable_expiry      = intval( $_POST['enable_expiry'] ?? 0 );
			$validity_days      = intval( $_POST['validity_days'] ?? 0 );
			$enable_usage_limit = intval( $_POST['enable_usage_limit'] ?? 0 );
			$usage_limit        = intval( $_POST['usage_limit'] ?? 1 );
			$minimum_purchase   = floatval( $_POST['minimum_purchase'] ?? 0 );
			$reward_type        = isset( $_POST['reward_type'] ) ? sanitize_text_field( wp_unslash( $_POST['reward_type'] ) ) : '';

			if ( ! $user_id || ! $discount_amount ) {
				wp_send_json_error( 'Invalid user ID or discount amount' );
				return;
			}

			try {
				$result = $this->generate_manual_reward_coupon(
					$user_id,
					$discount_amount,
					$discount_capping,
					$enable_expiry,
					$validity_days,
					$enable_usage_limit,
					$usage_limit,
					$minimum_purchase,
					$reward_type
				);

				if ( $result ) {
					// Update custom_rewards flag in ecre_referrers table.
					$this->update_custom_rewards_flag( $user_id );
					wp_send_json_success(
						array(
							'message'     => 'Reward coupon issued successfully',
							'coupon_code' => $result,
						),
					);
				} else {
					wp_send_json_error( 'Failed to generate reward coupon' );
				}
			} catch ( Exception $e ) {
				wp_send_json_error( 'Error: ' . $e->getMessage() );
			}
		}

		/**
		 * Generates a manual reward coupon for a user with various customizable options.
		 *
		 * This function creates a unique coupon code for a user, allowing customization of the discount type, discount amount,
		 * discount capping, expiry date, usage limit, and minimum purchase amount. It uses WooCommerce's `shop_coupon` post type
		 * to generate the coupon and saves the relevant metadata (such as discount type, coupon amount, usage limit, etc.).
		 * Additionally, it stores the coupon data in a custom database table for reward coupons.
		 *
		 * @since 1.0.0
		 *
		 * @param int    $user_id             The ID of the user for whom the reward coupon is generated.
		 * @param float  $discount_amount     The discount amount to be applied (either as a percentage or fixed amount).
		 * @param float  $discount_capping    The maximum discount capping for the coupon (if applicable).
		 * @param bool   $enable_expiry       Whether the coupon should have an expiry date.
		 * @param int    $validity_days       The number of days the coupon is valid for (used if expiry is enabled).
		 * @param bool   $enable_usage_limit Whether the coupon should have a usage limit.
		 * @param int    $usage_limit        The maximum number of times the coupon can be used.
		 * @param float  $minimum_purchase   The minimum purchase amount required to use the coupon.
		 * @param string $reward_type         The type of reward (e.g., 'percent' or 'fixed') for the coupon.
		 *
		 * @return string|false The generated coupon code if successful, or `false` if there was an issue generating the coupon.
		 */
		private function generate_manual_reward_coupon( $user_id, $discount_amount, $discount_capping, $enable_expiry, $validity_days, $enable_usage_limit, $usage_limit, $minimum_purchase, $reward_type ) {
			// Generate unique coupon code.
			$coupon_code     = ecre_generate_unique_coupon_code();
			$currency_symbol = ecre_custom_currency_symbol();

			$discount = ( 'percent' === $reward_type ) ? $discount_amount . '%' : $discount_amount . $currency_symbol;

			// Create WooCommerce coupon.
			$coupon = array(
				'post_title'   => $coupon_code,
				'post_content' => $discount . 'off coupon',
				'post_excerpt' => $discount . 'off coupon',
				'post_status'  => 'publish',
				'post_author'  => $user_id,
				'post_type'    => 'shop_coupon',
			);

			$coupon_id = wp_insert_post( $coupon );

			if ( ! $coupon_id ) {
				return false;
			}

			// Set coupon meta.
			update_post_meta( $coupon_id, 'discount_type', $reward_type );
			update_post_meta( $coupon_id, 'coupon_amount', $discount_amount );
			update_post_meta( $coupon_id, 'individual_use', 'yes' );
			update_post_meta( $coupon_id, 'reward_user_id', $user_id );
			if ( $enable_usage_limit && $usage_limit > 0 ) {
				update_post_meta( $coupon_id, 'usage_limit', $usage_limit );
			}

			// Set minimum purchase amount.
			if ( $minimum_purchase > 0 ) {
				update_post_meta( $coupon_id, 'minimum_amount', $minimum_purchase );
			}

			// Set maximum discount (capping).
			if ( $discount_capping > 0 ) {
				update_post_meta( $coupon_id, 'maximum_amount', $discount_capping );
			}

			// Set expiry date.
			if ( $enable_expiry && $validity_days > 0 ) {
				$expiry_date = gmdate( 'Y-m-d', strtotime( "+{$validity_days} days" ) );
				update_post_meta( $coupon_id, 'date_expires', $expiry_date );
			}

			// Store in reward coupons table.
			if ( class_exists( '\ECRE\Ecre_Database' ) ) {
				$database = new \ECRE\Ecre_Database();

				$coupon_data = array(
					'referrer_user_id' => $user_id,
					'order_id'         => 0,
					'coupon_code'      => $coupon_code,
					'coupon_id'        => $coupon_id,
					'discount_type'    => $reward_type,
					'discount_amount'  => $discount_amount,
					'usage_limit'      => $enable_usage_limit ? $usage_limit : 0,
					'usage_count'      => 0,
					'status'           => 'active',
					'expires_at'       => $enable_expiry && $validity_days > 0 ? gmdate( 'Y-m-d H:i:s', strtotime( "+{$validity_days} days" ) ) : null,
				);
				$database->store_reward_coupon_data( $coupon_data );
			}

			return $coupon_code;
		}

		/**
		 * Update custom_rewards flag for a user when they receive custom rewards.
		 *
		 * @since 1.0.0
		 *
		 * @param int $user_id The user ID to update the flag for.
		 *
		 * @return void
		 */
		private function update_custom_rewards_flag( $user_id ) {
			global $wpdb;

			// First ensure the user has a record in ecre_referrers table.
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$wpdb->prefix}ecre_referrers WHERE user_id = %d",
					$user_id
				)
			);

			if ( ! $exists ) {
				// Create referrer record if it doesn't exist.
				$wpdb->insert(
					$wpdb->prefix . 'ecre_referrers',
					array(
						'user_id'              => $user_id,
						'total_referrals'      => 0,
						'total_sales'          => 0.00,
						'total_rewards_issued' => 0,
						'total_discount'       => 0.00,
						'conversion_rate'      => 0.00,
						'custom_rewards'       => 1, // Set to 1 since we're issuing a custom reward.
						'custom_referrals'     => 0,
					)
				);
			} else {
				// Update existing record to set custom_rewards = 1.
				$wpdb->update(
					$wpdb->prefix . 'ecre_referrers',
					array(
						'custom_rewards' => 1,
						'updated_at'     => current_time( 'mysql' ),
					),
					array( 'user_id' => $user_id ),
					array( '%d', '%s' ),
					array( '%d' )
				);
			}
		}

		/**
		 * Update custom_referrals flag for a user when they have custom referral settings.
		 *
		 * @since 1.0.0
		 *
		 * @param int $user_id The user ID to update the flag for.
		 *
		 * @return void
		 */
		private function update_custom_referrals_flag( $user_id ) {
			global $wpdb;

			// First ensure the user has a record in ecre_referrers table.
			$exists = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT id FROM {$wpdb->prefix}ecre_referrers WHERE user_id = %d",
					$user_id
				)
			);

			if ( ! $exists ) {
				// Create referrer record if it doesn't exist.
				$wpdb->insert(
					$wpdb->prefix . 'ecre_referrers',
					array(
						'user_id'              => $user_id,
						'total_referrals'      => 0,
						'total_sales'          => 0.00,
						'total_rewards_issued' => 0,
						'total_discount'       => 0.00,
						'conversion_rate'      => 0.00,
						'custom_rewards'       => 0,
						'custom_referrals'     => 1, // Set to 1 since we're setting custom referrals.
					)
				);
			} else {
				// Update existing record to set custom_referrals = 1.
				$wpdb->update(
					$wpdb->prefix . 'ecre_referrers',
					array(
						'custom_referrals' => 1,
						'updated_at'       => current_time( 'mysql' ),
					),
					array( 'user_id' => $user_id ),
					array( '%d', '%s' ),
					array( '%d' )
				);
			}
		}
	}
}