<?php



if (!defined('ABSPATH')) {



  exit; // Exit if accessed directly.



}



// Load email template class

if (!class_exists('SensFRX_email_template')) {

	require_once plugin_dir_path( __FILE__ ) . 'email-templates/class-sensfrx-email-template.php';

}



class SensFRX_API_Callback_Handling  {



	/**

	 * Permission callback for admin-only endpoints

	 * Provides comprehensive authentication checking

	 * 

	 * @return bool True if user has permission, false otherwise

	 */

	public function sensfrx_admin_permission_check() {

		// Method 1: Check if user is logged in and has capability

		if ( is_user_logged_in() && current_user_can( 'manage_options' ) ) {

			return true;

		}

		

		// Method 2: Try to authenticate from cookie

		$user_id = get_current_user_id();

		if ( $user_id > 0 ) {

			$user = get_userdata( $user_id );

			if ( $user && user_can( $user, 'manage_options' ) ) {

				return true;

			}

		}

		

		// Method 3: Check WordPress cookie directly

		if ( ! empty( $_COOKIE ) ) {



			foreach ( $_COOKIE as $name => $value ) {

				if ( strpos( $name, 'wordpress_logged_in_' ) === 0 ) {



					$user_id = wp_validate_auth_cookie( $value, 'logged_in' );



					if ( $user_id && user_can( $user_id, 'manage_options' ) ) {

						return true;

					}

				}

			}

		}

		

		// All authentication methods failed

		return false;

	}



	/**

	 * Permission callback for webhook endpoints

	 * Verifies the HMAC-SHA256 signature sent by Sensfrx API

	 * 

	 * Security: Signature verification is REQUIRED by default (secure by default)

	 * Can be disabled via 'sensfrx_require_webhook_signature' option if needed

	 * 

	 * @param WP_REST_Request $request The REST API request object

	 * @return bool True if signature is valid, false otherwise

	 */

	public function sensfrx_webhook_permission_check( $request ) {

		// Get the signature from request header

		$received_signature = $request->get_header( 'x-signature' );

		

		// Check if signature requirement can be bypassed (for backward compatibility only)

		// Default: true (require signature) - SECURE BY DEFAULT

		// Set to false only if Sensfrx API doesn't send signatures yet

		$require_signature = get_option( 'sensfrx_require_webhook_signature', true );

		

		// If no signature provided

		if ( empty( $received_signature ) ) {

			error_log( sprintf(

				'SensFRX Webhook: No signature provided | Signature Required: %s | IP: %s',

				$require_signature ? 'YES' : 'NO',

				isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : 'unknown'

			) );

			

			// SECURE BY DEFAULT: Deny requests without signature

			if ( $require_signature ) {

				return false; // Security: Deny unsigned requests

			} else {

				// Only allow if explicitly configured (not recommended)

				error_log( 'SensFRX Webhook: WARNING - Allowing unsigned webhook (insecure configuration)' );

				return true; // Backward compatibility mode

			}

		}

		

		// Get request body

		$body = $request->get_body();

		

		// Get the route being called to determine which secret to use

		$route = $request->get_route();

		

		// DEBUG: Log stored secrets for investigation

		$transaction_secret = get_option( 'sensfrx_transaction_webhook_signing_secret', '' );

		$registration_secret = get_option( 'sensfrx_webhook_signing_secret', '' );

		

		// Determine which secret to use based on the webhook type

		if ( strpos( $route, 'sensfrx__transaction_webhook' ) !== false ) {

			$secret = $transaction_secret;

		} else {

			$secret = $registration_secret;

		}

		

		// Fallback to hardcoded secret if no stored secret (backward compatibility)

		if ( empty( $secret ) ) {

			$secret = '9d1b7f5568f4c4eb0ffb8c33b3a3a0ed9fa4e3ae9f9a6c9cbb2289ec0fc5b1f1';

			error_log( 'SensFRX Webhook DEBUG: Using FALLBACK hardcoded secret (no stored secret found)' );

		}

		

		// Calculate expected signature

		$expected_signature = hash_hmac( 'sha256', $body, $secret );

		

		// Compare signatures (timing-safe comparison)

		if ( ! hash_equals( $expected_signature, $received_signature ) ) {

			error_log( sprintf(

				'SensFRX Webhook: Invalid signature | IP: %s | Expected: %s | Received: %s',

				isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( $_SERVER['REMOTE_ADDR'] ) : 'unknown',

				substr( $expected_signature, 0, 10 ) . '...',

				substr( $received_signature, 0, 10 ) . '...'

			) );

			return false;

		}

		

		// Signature valid

		return true;

	}



  	public function sensfrx_route_callback_handling() {



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/sensfrx_webhook', array(



			'methods' => 'POST',



			'callback' => 'sensfrx_handle_webhook',



			'permission_callback' => function () {

				return true; // or add signature / secret validation

			},



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/sensfrx__transaction_webhook', array(



			'methods' => 'POST',



			'callback' => 'sensfrx_handle_transaction_webhook',



			'permission_callback' => function () {

				return true; // or add signature / secret validation

			},



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/sensfrx_api_callback_handling', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_options_pid_skey_update',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_options', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_options',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_policy_options', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_policy_options',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_policy_options', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_policy_options',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_notification_settings', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_notification_settings',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_notification_settings', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_notification_settings',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_recent_activity_options', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_recent_activity_options',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_default_policy_options', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_default_policy_options',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_default_policy_options', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_default_policy_options',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_license_info', array(



			'methods'  => 'GET',



			'callback' => 'get_sensfrx_license_info',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_fraud_rate', array(



			'methods'  => 'GET',



			'callback' => 'get_sensfrx_fraud_rate',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_stats', array(



			'methods'  => 'GET',



			'callback' => 'get_sensfrx_stats_data',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_blacklist', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_blacklist',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_blacklist', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_blacklist',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_delete_blacklist', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_delete_blacklist',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_delete_whitelist', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_delete_whitelist',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_whitelist', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_whitelist',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_whitelist', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_whitelist',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_advance_rules', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_advance_rules',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_advance_policy', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_advanced_advanced_rules',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_trans_review', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_trans_review',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_trans_bulk_review', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_trans_bulk_review',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_register_review', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_register_review',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/post_sensfrx_reg_bulk_review', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_reg_bulk_review',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_export', array(



			'methods'  => 'GET',



			'callback' => 'get_export_info',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_sensfrx_review_count', array(



			'methods'  => 'GET',



			'callback' => 'get_review_count_info',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		// Modern Fraud Review endpoints

		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/review-queue', array(



			'methods'  => 'GET',



			'callback' => 'get_sensfrx_review_queue',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/review-action', array(



			'methods'  => 'POST',



			'callback' => 'post_sensfrx_review_action',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/review-note', array(



			'methods'  => 'POST',



			'callback' => 'post_sensfrx_review_note',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/review-count', array(



			'methods'  => 'GET',



			'callback' => 'get_sensfrx_review_count',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		// NOTE: License info uses /get_license_info endpoint (defined earlier)



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_activity_log', array(



			'methods'  => 'GET',



			'callback' => 'get_sensfrx_activity_log',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/fraud-cases-list', array(



			'methods'  => 'GET',



			'callback' => 'get_fraud_cases',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/onboarding-login-link', array(



			'methods'  => 'GET',



			'callback' => 'sensfrx_get_login_link',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/protection-stats', array(



			'methods'  => 'GET',



			'callback' => 'get_protection_stats',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/get_email_modify', array(



			'methods'  => 'POST',



			'callback' => 'get_sensfrx_email_modify',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/save_email_modify', array(



			'methods'  => 'POST',



			'callback' => 'sensfrx_post_email_modify',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/sendCodeAgain', array(



			'methods' => 'POST',



			'callback' => 'sendOTPAgain',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		// NEW: OAuth/OTP Flow Routes - Integrated with Core-API

		// These endpoints proxy to core-API for centralized OTP management, analytics, and Mailgun email delivery

		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/oauth/send-otp', array(



			'methods' => 'POST',



			'callback' => 'oauth_send_otp_handler',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/oauth/verify-otp', array(



			'methods' => 'POST',



			'callback' => 'oauth_verify_otp_handler',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/oauth/resend-otp', array(



			'methods' => 'POST',



			'callback' => 'oauth_resend_otp_handler',



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		// Getting Started Checklist - Update Item

		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/update-checklist', array(



			'methods' => 'POST',



			'callback' => array( $this, 'update_checklist_item' ),



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		// Getting Started Checklist - Dismiss

		register_rest_route('sensfrx-fraud-prevention-for-woocommerce', '/dismiss-getting-started', array(



			'methods' => 'POST',



			'callback' => array( $this, 'dismiss_getting_started' ),



			'permission_callback' => array( $this, 'sensfrx_admin_permission_check' ),



		));



		if ( ! function_exists( 'sendOTPAgain' ) ) {



			function sendOTPAgain(WP_REST_Request $request) {

				$params = json_decode($request->get_body(), true);

				$action = isset($params['action']) ? $params['action'] : '';

				$options = get_option('sensfrx_options', SensFRX::default_options());

				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');

				$obj = new SensFRX\SensFRX([

					'property_id' => $options['sensfrx_property_id'],

					'property_secret' => $options['sensfrx_property_secret']

				]);

				if (!empty($action) && 'step-1' == $action) {

					$email = isset($params['email']) ? $params['email'] : '';

					if (empty($email)) {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'Invalid or missing email.',

							'data' => $params,

						]);

					}

					$adminEmail = false;

					$admins = get_users(['role' => 'administrator']);

					foreach ($admins as $admin) {

						if (strtolower($admin->user_email) === strtolower($email)) {

							$adminEmail = true;

							break;

						}

					}

					if ($adminEmail) {

						global $wp_version;

						$version = $wp_version;

						$postDataArray = [

							'email' => $email,

							'web_platform_type' => 'WordPress',

							'web_platform_version' => $version,

							'plugin_version' => SENSFRX_VERSION,



						];

						$getPropertySecrets = $obj->postPropertySecrets($postDataArray);

						if (

							isset($getPropertySecrets['status']) &&

							$getPropertySecrets['status'] === 'success' &&

							isset($getPropertySecrets['data']) &&

							is_array($getPropertySecrets['data']) &&

							isset($getPropertySecrets['data']['propertyId']) &&

							isset($getPropertySecrets['data']['propertySecret'])

						) {

							$propertyId = $getPropertySecrets['data']['propertyId'];

							$propertySecret = $getPropertySecrets['data']['propertySecret'];

							$options['sensfrx_property_id'] = $propertyId;

							$options['sensfrx_property_secret'] = $propertySecret;

							$update_status = update_option('sensfrx_options', $options);

							if (!$update_status) {

								return rest_ensure_response([

									'status' => 'error',

									'message' => 'There was an issue setting up the property secrets. Please try again later.',

									'data' => $action,

									'step_ahead' => '1'

								]);

							} else {

								return rest_ensure_response([

									'status' => 'success',

									'message' => 'It is admin.',

									'step_ahead' => '3'

								]);	

							}

						} else {

							return rest_ensure_response([

								'status' => 'error',

								'message' => 'The API did not respond correctly. Please try again later.',

								'data' => $action,

								'step_ahead' => '1'

							]);

						}

					} else {

						$otp = rand(100000, 999999);

						$expires = time() + 300;

						set_transient('sensfrx_otp_' . md5($email), ['otp' => $otp, 'expires' => $expires], 300);

						wp_mail($email, 'Sensfrx OTP Verification', "Your OTP is: $otp\n\nThis OTP is valid for 5 minutes.");

						return rest_ensure_response([

							'status' => 'success',

							'message' => 'It is not admin.',

							'step_ahead' => '2',

							'email' => $email

						]);

					}

				} else if (!empty($action) && 'resend_otp' == $action) {

					$email = isset($params['email']) ? $params['email'] : '';

					if (empty($email) || !is_email($email)) {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'Invalid or missing email.',

							'data' => $params,

						]);

					}

					$otp = rand(100000, 999999);

					$expires = time() + 300; // 5 minutes from now

					// Save OTP in transient

					set_transient('sensfrx_otp_' . md5($email), [

						'otp'     => $otp,

						'expires' => $expires

					], 300);

					// Send OTP via email

					$subject = 'Sensfrx OTP Verification';

					$message = "Your OTP is: $otp\n\nThis OTP is valid for 5 minutes.";

					$headers = ['Content-Type: text/plain; charset=UTF-8'];

					$mail_sent = wp_mail($email, $subject, $message, $headers);

					if ($mail_sent) {

						return rest_ensure_response([

							'status' => 'success',

							'message' => 'OTP sent successfully.',

							'email' => $email

						]);

					} else {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'Failed to send OTP.',

						]);

					}

				} else if (!empty($action) && 'verify_otp' == $action) {

					$verifyOTP = isset($params['verifyOTP']) ? $params['verifyOTP'] : '';

					if (empty($verifyOTP)) {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'OTP not received.',

							'data' => $params,

						]);

					}

					$email = isset($params['email']) ? $params['email'] : '';

					if (empty($email) || !is_email($email)) {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'Invalid or missing email.',

							'data' => $params,

						]);

					}

					$entered_otp = $verifyOTP;

					$stored = get_transient('sensfrx_otp_' . md5($email));

					if ($stored && $stored['otp'] == $entered_otp && time() <= $stored['expires']) {

						delete_transient('sensfrx_otp_' . md5($email));

						update_option('sensfrx_verified_email', $email);

						global $wp_version;

						$version = $wp_version;

						$postDataArray = [

							'email' => $email,

							'web_platform_type' => 'WordPress',

							'web_platform_version' => $version,

							'plugin_version' => SENSFRX_VERSION,



						];

						$getPropertySecrets = $obj->postPropertySecrets($postDataArray);

						if (

							isset($getPropertySecrets['status']) &&

							$getPropertySecrets['status'] === 'success' &&

							isset($getPropertySecrets['data']) &&

							is_array($getPropertySecrets['data']) &&

							isset($getPropertySecrets['data']['propertyId']) &&

							isset($getPropertySecrets['data']['propertySecret'])

						) {

							$propertyId = $getPropertySecrets['data']['propertyId'];

							$propertySecret = $getPropertySecrets['data']['propertySecret'];

							$options['sensfrx_property_id'] = $propertyId;

							$options['sensfrx_property_secret'] = $propertySecret;

							$update_status = update_option('sensfrx_options', $options);

							if (!$update_status) {

								return rest_ensure_response([

									'status' => 'error',

									'message' => 'There was an issue setting up the property secrets. Please try again later.',

									'data' => $params,

								]);

							} else {

								return rest_ensure_response([

									'status' => 'success',

									'message' => 'OTP Verified.',

									'data' => $params,

								]);

							}

						} else {

							return rest_ensure_response([

								'status' => 'error',

								'message' => 'The API did not respond correctly. Please try again later.',

								'data' => $params,

							]);

						}

					} else {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'Incorrect OTP.',

							'data' => $params,

						]);

					}

				} else if (!empty($action) && 'redirectGet' == $action) {

					$redirectResponse = $obj->redirectBefore();

					if (!empty($redirectResponse) && 'success' == $redirectResponse['status']) {

						$status = $redirectResponse['status'];

						$loginLink = $redirectResponse['login_link'];

						return rest_ensure_response([

							'status' => 'success',

							'message' => 'OTP sent successfully.',

							'login_link' => $loginLink

						]);

					} else {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'Something Went Wrong, Please try again after sometime',

							'data' => $action,

						]);

					}

				} else {

					return rest_ensure_response([

						'status' => 'error',

						'message' => 'Invalid action.',

						'data' => $action,

					]);

				}

			}



		}



		/**

		 * OAuth Send OTP Handler

		 * Sends OTP via core-API with Mailgun email delivery

		 */

		function oauth_send_otp_handler(WP_REST_Request $request) {

			$params = $request->get_json_params();

			$email = isset($params['email']) ? sanitize_email($params['email']) : '';

			$options = get_option('sensfrx_options', SensFRX::default_options());

			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');

			$obj = new SensFRX\SensFRX([

				'property_id' => $options['sensfrx_property_id'],

				'property_secret' => $options['sensfrx_property_secret']

			]);

			if (empty($email)) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Email is required'

				]);

			}



			$adminEmail = false;

			$admins = get_users(['role' => 'administrator']);

			foreach ($admins as $admin) {

				if (strtolower($admin->user_email) === strtolower($email)) {

					$adminEmail = true;

					break;

				}

			}

			$domain = get_site_url();

			if ($adminEmail) {

				global $wp_version;

				$version = $wp_version;

				$postDataArray = [

					'email' => $email,

					'web_platform_type' => 'WordPress',

					'web_platform_version' => $version,

					'plugin_version' => SENSFRX_VERSION,

					'domain' => $domain,



				];

				$getPropertySecrets = $obj->postPropertySecrets($postDataArray);

				if (

					isset($getPropertySecrets['status']) &&

					$getPropertySecrets['status'] === 'success' &&

					isset($getPropertySecrets['data']) &&

					is_array($getPropertySecrets['data']) &&

					isset($getPropertySecrets['data']['propertyId']) &&

					isset($getPropertySecrets['data']['propertySecret'])

				) {

					$propertyId = $getPropertySecrets['data']['propertyId'];

					$propertySecret = $getPropertySecrets['data']['propertySecret'];

					$options['sensfrx_property_id'] = $propertyId;

					$options['sensfrx_property_secret'] = $propertySecret;

					$update_status = update_option('sensfrx_options', $options);

					if (!$update_status) {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'There was an issue setting up the property secrets. Please try again later.',

							'data' => $action,

							'step_ahead' => '1'

						]);

					} else {

						return rest_ensure_response([

							'status' => 'success',

							'message' => 'It is admin.',

							'step_ahead' => '3'

						]);	

					}

				} else {

					return rest_ensure_response([

						'status' => 'error',

						'message' => 'The API did not respond correctly. Please try again later.',

						'data' => $getPropertySecrets,

						'step_ahead' => '1',

					]);

				}

			} else {



				// Get plugin and platform information

				$plugin_version = defined('SENSFRX_VERSION') ? SENSFRX_VERSION : '2.0.19';

				global $wp_version;

				$platform_version = $wp_version;

				$domain = get_site_url();



				// Get options and initialize SDK

				$options = get_option('sensfrx_options', SensFRX::default_options());

				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				$obj = new SensFRX\SensFRX([

					'property_id' => $options['sensfrx_property_id'],

					'property_secret' => $options['sensfrx_property_secret']

				]);



				// Prepare OAuth payload

				$oauthData = [

					'email' => $email,

					'domain' => $domain,

					'plugin_version' => $plugin_version,

					'web_platform_type' => 'woocommerce',

					'web_platform_version' => $platform_version

				];



				// Call SDK method

				$result = $obj->oauthSendOtp($oauthData);



				// Store email in transient for verification step

				if (isset($result['status']) && $result['status'] === 'success') {

					set_transient('sensfrx_otp_email_' . md5($email), $email, 300);

				}



				return rest_ensure_response($result);

			}

		}



		/**

		 * OAuth Verify OTP Handler

		 * Verifies OTP against core-API

		 */

		function oauth_verify_otp_handler(WP_REST_Request $request) {

			$params = $request->get_json_params();

			$email = isset($params['email']) ? sanitize_email($params['email']) : '';

			$otp = isset($params['otp']) ? sanitize_text_field($params['otp']) : '';



			if (empty($email) || empty($otp)) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Email and OTP are required'

				]);

			}



			// Get options and initialize SDK

			$options = get_option('sensfrx_options', SensFRX::default_options());

			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => $options['sensfrx_property_id'],

				'property_secret' => $options['sensfrx_property_secret']

			]);



			// Prepare OAuth payload

			$oauthData = [

				'email' => $email,

				'otp' => $otp

			];



			// Call SDK method

			$result = $obj->oauthVerifyOtp($oauthData);



			// Store temp token if verification successful

			if (isset($result['status']) && $result['status'] === 'success' && isset($result['temp_token'])) {

				$temp_token = $result['temp_token'];

				set_transient('sensfrx_temp_token_' . md5($email), $temp_token, 300);

				global $wp_version;

				$version = $wp_version;

				

				// Get domain from WordPress

				$domain = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field($_SERVER['HTTP_HOST']) : '';

				if (empty($domain) && isset($_SERVER['SERVER_NAME'])) {

					$domain = sanitize_text_field($_SERVER['SERVER_NAME']);

				}

				

				$postDataArray = [

					'email' => $email,

					'temp_token' => $temp_token,

					'web_platform_type' => 'WordPress',

					'web_platform_version' => $version,

					'plugin_version' => SENSFRX_VERSION,

					'domain' => $domain,

				];



				$getPropertySecrets = $obj->oauthRegister($postDataArray);

				if (

					isset($getPropertySecrets['status']) &&

					$getPropertySecrets['status'] === 'success' &&

					isset($getPropertySecrets['data']) &&

					is_array($getPropertySecrets['data']) &&

					isset($getPropertySecrets['data']['propertyId']) &&

					isset($getPropertySecrets['data']['propertySecret'])

				) {

					$propertyId = $getPropertySecrets['data']['propertyId'];

					$propertySecret = $getPropertySecrets['data']['propertySecret'];

					$options['sensfrx_property_id'] = $propertyId;

					$options['sensfrx_property_secret'] = $propertySecret;

					$update_status = update_option('sensfrx_options', $options);

					if (!$update_status) {

						return rest_ensure_response([

							'status' => 'error',

							'message' => 'There was an issue setting up the property secrets. Please try again later.',

							'data' => $params,

						]);

					} else {

						return rest_ensure_response($result);

					}

				} else {

					// Log the actual API response for debugging

					error_log('SensFRX OAuth Register Error Response: ' . print_r($getPropertySecrets, true));

					error_log('SensFRX OAuth Register Request was: ' . print_r($postDataArray, true));

					

					// Include API error message if available

					$errorMessage = 'The API did not respond correctly. Please try again later.';

					if (isset($getPropertySecrets['message'])) {

						$errorMessage .= ' API Error: ' . $getPropertySecrets['message'];

					}

					

					return rest_ensure_response([

						'status' => 'error',

						'message' => $errorMessage,

						'data' => $params,

						'debug' => isset($getPropertySecrets['message']) ? $getPropertySecrets['message'] : 'Unknown API error',

					]);

				}

			}



			return rest_ensure_response($result);

		}



		/**

		 * OAuth Resend OTP Handler

		 * Resends OTP via core-API with rate limiting

		 */

		function oauth_resend_otp_handler(WP_REST_Request $request) {

			$params = $request->get_json_params();

			$email = isset($params['email']) ? sanitize_email($params['email']) : '';



			if (empty($email)) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Email is required'

				]);

			}



			// Get options and initialize SDK

			$options = get_option('sensfrx_options', SensFRX::default_options());

			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => $options['sensfrx_property_id'],

				'property_secret' => $options['sensfrx_property_secret']

			]);



			// Prepare OAuth payload

			$oauthData = [

				'email' => $email

			];



			// Call SDK method

			$result = $obj->oauthResendOtp($oauthData);



			return rest_ensure_response($result);

		}



		function sensfrx_handle_webhook(WP_REST_Request $request) {



			$body = $request->get_body();



			$data = json_decode($body, true);



			if (is_null($data)) {



				return new WP_REST_Response(array(



					'status' => 'error',



					'message' => 'Invalid JSON data received',



					'received_body' => $body



				), 400);



			}



			$response_data = array(



				'status' => 'success',



				'message' => 'Sensfrx Webhook received and processed successfully',



				'received_data' => $data,



			);



			if (isset($data['status']) && isset($data['severity']) && isset($data['user']) && isset($data['user']['user_id'])) {



				$sensfrx_status  = $data['status'];



				$severity  = $data['severity'];



				$user  = $data['user'];



				$userId = $user['user_id'];



				$email = ( isset($user['email']) && !empty($user['email'])?$user['email']:false );



				$tableName = $wpdb->prefix . 'sensfrx_webhook_logout';



				if (1 == $userId || '1' == $userId) {



					global $wpdb;



					$tableName = $wpdb->prefix . 'sensfrx_webhook_logout';



					$result = wp_cache_get('sensfrx_admin_webhookcall_data', 'sensfrx_group');



					if ($result !== false) {



						$result = $wpdb->delete(



							$tableName,



							array('client_id' => $userId),



							array('%d') // Format for the client_id, assuming it's an integer



						); 



						$cache_set = wp_cache_replace('sensfrx_admin_webhookcall_data', $result, 'sensfrx_group', 86400);



						if (!$cache_set || false == $cache_set) {



							error_log('SensFRX Webhook: Failed to update cache.');



						}



					} else {



						$result = $wpdb->delete(



							$tableName,



							array('client_id' => $userId),



							array('%d') // Format for the client_id, assuming it's an integer



						); 



						$cache_set = wp_cache_set('sensfrx_admin_webhookcall_data', $result, 'sensfrx_group', 86400);



						if (!$cache_set || false == $cache_set) {



							error_log('SensFRX Webhook: Failed to set cache.');



						}



					}



				} else {



					if ( 'allow' == $sensfrx_status ) {



						global $wpdb;



						$tableName = $wpdb->prefix . 'sensfrx_webhook_logout';



						$result = wp_cache_get('sensfrx_admin_webhookcall123_data', 'sensfrx_group');



						if ($result !== false) {



							$result = $wpdb->delete(



								$tableName,



								array('client_id' => $userId),



								array('%d') // Format for the client_id, assuming it's an integer



							); 



							$cache_set = wp_cache_replace('sensfrx_admin_webhookcall123_data', $result, 'sensfrx_group', 86400);



							if (!$cache_set || false == $cache_set) {



								error_log('SensFRX Webhook: Failed to update cache.');



							}



						} else {



							$result = $wpdb->delete(



								$tableName,



								array('client_id' => $userId),



								array('%d') // Format for the client_id, assuming it's an integer



							); 



							$cache_set = wp_cache_set('sensfrx_admin_webhookcall123_data', $result, 'sensfrx_group', 86400);



							if (!$cache_set || false == $cache_set) {



								error_log('SensFRX Webhook: Failed to set cache.');



							}



						} 



					} elseif ( 'deny' == $sensfrx_status && 'critical' == $severity ) {



						global $wpdb;



						$result = wp_cache_get('sensfrx_admin_webhookcall_deny_data', 'sensfrx_group');



						if ($result !== false) {



							$tableName = $wpdb->prefix . 'sensfrx_webhook_logout';



							$data = array(



								'client_id' => $userId,



							);



							$insert = $wpdb->insert($tableName, $data);



							$cache_set = wp_cache_replace('sensfrx_admin_webhookcall_deny_data', $result, 'sensfrx_group', 86400);



							if (!$cache_set || false == $cache_set) {



								error_log('SensFRX Webhook: Failed to update cache.');



							}



						} else {



							$tableName = $wpdb->prefix . 'sensfrx_webhook_logout';



							$data = array(



								'client_id' => $userId,



							);



							$insert = $wpdb->insert($tableName, $data);



							$cache_set = wp_cache_set('sensfrx_admin_webhookcall_deny_data', $result, 'sensfrx_group', 86400);



							if (!$cache_set || false == $cache_set) {



								error_log('SensFRX Webhook: Failed to set cache.');



							}



						}



						// Send email notification to user (consistent with real-time login deny)

						// Load SensFRX class if needed for default_policy_options

						if (!class_exists('SensFRX') && defined('SENSFRX_DIR')) {

							require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');

						}

						

						$default_policy_options = class_exists('SensFRX') && method_exists('SensFRX', 'default_policy_options') 

							? SensFRX::default_policy_options() 

							: array();

						

						$sensfrx_policy_options = get_option('sensfrx_policy_options', $default_policy_options);

						$checkbox_deny = isset($sensfrx_policy_options['sensfrx_deny_email']) ? $sensfrx_policy_options['sensfrx_deny_email'] : false;



						if ($checkbox_deny) {



							$checkbox_deny = true;



						} else {



							$checkbox_deny = false;



						}



						if ( true == $checkbox_deny && !empty($email) ) {



							// Get user data from WordPress to get first name

							$wp_user = get_userdata($userId);

							$first_name = $wp_user ? ($wp_user->display_name ? $wp_user->display_name : ($wp_user->user_nicename ? $wp_user->user_nicename : '')) : '';



							// If no display name, try to get from user meta

							if (empty($first_name) && $wp_user) {

								$first_name = get_user_meta($userId, 'first_name', true);

								if (empty($first_name)) {

									$first_name = $wp_user->user_login;

								}

							}



							$to = $email;



							$site_title = get_bloginfo('name');



							// Get default email content (no database customization)

							$default_email = SensFRX_email_template::get_default_message('login_deny');

							$login_deny_subject = $default_email['subject'];

							$login_deny_message = $default_email['message'];



							$date = date('Y M d');



							$time = date('H:i:s');



							$replacements = [



								'{$client_full_name}' => $first_name,



								'{$default_brand_name}' => $site_title,



								'{$date}' => $date,



								'{$time}' => $time,



							];



							// Use universal email wrapper for professional formatting

							$mailResult = SensFRX_email_template::wrap_and_send( $to, $login_deny_subject, $login_deny_message, $site_title, $replacements );



						} else {



							if (empty($email)) {

								error_log('SensFRX Webhook: Login deny email NOT sent - No email address provided for user_id: ' . $userId);

							} else {

								error_log('SensFRX Webhook: Login deny email NOT sent - Deny email policy is disabled');

							}



						}



					}



				}	



			}



			return new WP_REST_Response($response_data, 200);



		}



		function sensfrx_handle_transaction_webhook(WP_REST_Request $request) {



			$body = $request->get_body();



			$data = json_decode($body, true);



			if (is_null($data)) {



				return new WP_REST_Response(array(



					'status' => 'error',



					'message' => 'Sensfrx Transaction Webhook Invalid JSON data received',



					'received_body' => $body



				), 400);



			}



			$response_data = array(



				'status' => 'success',



				'message' => 'Sensfrx Webhook received and processed successfully',



				'received_data' => $data,



			);



			if ( isset($data['status']) && isset($data['severity']) && isset($data['order_id']) && isset($data['risk_score']) ) {



				$order_id = $data['order_id'];



				$order_risk_score = $data['risk_score'];



				$sensfrx_order = wc_get_order($order_id);



				if (isset($order_risk_score) && $order_risk_score == "0" && isset($data['status']) && $data['status'] == "allow" ) {



					if ($sensfrx_order) {



						global $wpdb;



						$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_pre_payment_order' );



						$existing_record = $wpdb->get_var(



							$wpdb->prepare(

								// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %d placeholder.

								"SELECT * FROM {$table_name_shadow_table} WHERE pre_order_id = %d",



								$order_id



							)



						);



						if ( 0 == $existing_record || '0' == $existing_record ) {



							$sensfrx_order->update_status('processing', 'Sensfrx - Order status updated to Processing.');



							$user_email = $sensfrx_order->get_billing_email();



							// Get default email content (no database customization)

							$default_email = SensFRX_email_template::get_default_message('transaction_review_approve');

							$subject = $default_email['subject'];

							$message = $default_email['message'];



							$date = date('Y M d');

							$time = date('H:i:s');



							$replacements = [

								'{$client_full_name}' => $sensfrx_order->get_billing_first_name(),

								'{$order_id}' => $order_id,

								'{$date}' => $date,

								'{$time}' => $time,

								'{$default_brand_name}' => get_bloginfo('name'),

							];



							// Use universal email wrapper for professional formatting

							SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



						} else {



						error_log( 'SensFRX Webhook FLOW: PRE-PAYMENT order - NOT updating status, only sending payment email for order ' . $order_id );



						$user_email = $sensfrx_order->get_billing_email();



						$payment_url = $sensfrx_order->get_checkout_payment_url();



						// Get default email content (no database customization)

						$default_email = SensFRX_email_template::get_default_message('transaction_review_approve_payment');

						$subject = $default_email['subject'];

						$message = $default_email['message'];



						$date = date('Y M d');

						$time = date('H:i:s');



						$replacements = [

							'{$client_full_name}' => $sensfrx_order->get_billing_first_name(),

							'{$order_id}' => $order_id,

							'{$payment_url}' => $payment_url,

							'{$date}' => $date,

							'{$time}' => $time,

							'{$default_brand_name}' => get_bloginfo('name'),

						];



						// Use universal email wrapper for professional formatting

						SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



						}



						$trans_id_display = isset($data['trans_id']) ? $data['trans_id'] : 'N/A';

						$insert_data_log = "Order #" . $order_id . " (Trans: " . $trans_id_display . ") | Approved via webhook review | Status: Allow | Risk: Low";

						

						$inserted_id = SensFRX_DB_Helper::insert_activity_log('Webhook - Order Review', $insert_data_log);



						if ( $existing_record > 0 ) {



							$delete_result = $wpdb->delete(



								$table_name_shadow_table,



								array( 'pre_order_id' => $order_id ),



								array( '%d' )



							);



						}



					} else {



						$trans_id_display = isset($data['trans_id']) ? $data['trans_id'] : 'N/A';

						$insert_data = "Order #" . $order_id . " (Trans: " . $trans_id_display . ") | Approval failed | Reason: Order not found in WooCommerce";

						SensFRX_DB_Helper::insert_activity_log('Webhook - Order Review', $insert_data);



					}



				}



				if (isset($order_risk_score) && $order_risk_score == "100" && isset($data['status']) && $data['status'] == "deny") {



					global $wpdb;



					$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_pre_payment_order' );



					$existing_record = $wpdb->get_var(



						$wpdb->prepare(

							// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %d placeholder.

							"SELECT * FROM {$table_name_shadow_table} WHERE pre_order_id = %d",



							$order_id



						)



					);



					$sensfrx_order->update_status('cancelled', 'Sensfrx - Order marked as cancelled due to fraudulent activity.');



					$refund_args = array(



						'amount'         => $sensfrx_order->get_total(),



						'order_id'       => $order_id,



						'reason'         => 'Refund due to detected fraudulent activity.',



						'refund_payment' => true, 



					);



				$user_email = $sensfrx_order->get_billing_email();



				// Get default email content (no database customization)

				$default_email = SensFRX_email_template::get_default_message('transaction_review_deny');

				$subject = $default_email['subject'];

				$message = $default_email['message'];



				$date = date('Y M d');

				$time = date('H:i:s');



				$replacements = [

					'{$client_full_name}' => $sensfrx_order->get_billing_first_name(),

					'{$order_id}' => $order_id,

					'{$date}' => $date,

					'{$time}' => $time,

					'{$default_brand_name}' => get_bloginfo('name'),

				];



				// Use universal email wrapper for professional formatting

				SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



					$user_email_ato = $email;



					$trans_id_display = isset($data['trans_id']) ? $data['trans_id'] : 'N/A';

					$insert_data_log = "Order #" . $order_id . " (Trans: " . $trans_id_display . ") | Rejected via webhook review | Status: Deny | Risk: Critical";



					SensFRX_DB_Helper::insert_activity_log('Webhook - Order Review', $insert_data_log);

					

					if ( $existing_record > 0 ) {



						$delete_result = $wpdb->delete(



							$table_name_shadow_table,



							array( 'pre_order_id' => $order_id ),



							array( '%d' )



						);



					}



					try {



						$refund = wc_create_refund($refund_args);



						if (is_wp_error($refund)) {



							$sensfrx_order->add_order_note('Refund failed: ' . $refund->get_error_message());



						} else {



							$sensfrx_order->add_order_note('Refund processed successfully for the cancelled order.');



						}



					} catch (Exception $e) {



						$sensfrx_order->add_order_note('Error during refund: ' . $e->getMessage());



					}



				}



			}



			if ( isset($data['status']) && isset($data['severity']) && isset($data['reg_id']) && isset($data['risk_score']) ) {



				$reg_id = $data['reg_id'];



				$order_risk_score = $data['risk_score'];



				$userName = $data['username'];



				$eMail = $data['email'];



				if (isset($order_risk_score) && $order_risk_score == "0" && isset($data['status']) && $data['status'] == "allow" ) {



					$user_id = wp_create_user($userName, wp_generate_password(), $eMail);



					if (!is_wp_error($user_id)) {



						wp_send_new_user_notifications($user_id, 'user');



						$insert_data = "The account was approve successfully for Email ID " . $eMail . ".";

						SensFRX_DB_Helper::insert_activity_log('Webhook - Account Review', $insert_data);



					} else {



						$error_message = $user_id->get_error_message();



						$subject = "Account Creation Error";



						$body = "Dear ". $userName .",\n\nWe encountered an issue while creating your account:\n\n" . $error_message . "\n\nPlease try again with a different username or contact support for assistance.";



						$headers = array('Content-Type: text/plain; charset=UTF-8');



						wp_mail($eMail, $subject, $body, $headers);



						$insert_data = "The account was not approve successfully for Email ID " . $eMail . ". Encountered an issue while creating the account";

						SensFRX_DB_Helper::insert_activity_log('Webhook - Account Review', $insert_data);



					}



				}



				if (isset($order_risk_score) && $order_risk_score == "100" && isset($data['status']) && $data['status'] == "deny" ) {



					$subject = "Account Rejected";



					$body = "Dear ". $userName ." ,\n\nWe regret to inform you that your account has been rejected by the admin. Please contact support for further assistance.\n\nThank you.";



					$headers = array('Content-Type: text/plain; charset=UTF-8');



					wp_mail($eMail, $subject, $body, $headers);



					$insert_data = "The account was reject successfully for Email ID " . $eMail . ".";

					SensFRX_DB_Helper::insert_activity_log('Webhook - Account Review', $insert_data);



				}



			}



			return new WP_REST_Response($response_data, 200);



		}



		function sensfrx_options_pid_skey_update(WP_REST_Request $request) {



			$property_id = sanitize_text_field($request->get_param('property_id'));



			$property_secret = sanitize_text_field($request->get_param('property_secret'));







			if (!$property_id || !$property_secret) {



				return new WP_Error('missing_params', 'Property ID and Secret are required.', array('status' => 400));



			}







			$options = get_option('sensfrx_options', SensFRX::default_options());



			// Update only the necessary fields



			$options['sensfrx_property_id'] = $property_id;



			$options['sensfrx_property_secret'] = $property_secret;







			// Save the updated array back to the database



			$update_status = update_option('sensfrx_options', $options);



			if (!$update_status) {



				return new WP_Error('update_failed', 'No Changes Found.', ['status' => 500]);



			}



			return rest_ensure_response(['message' => 'Settings updated successfully']);



		}



		function sensfrx_get_options() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			// SECURITY FIX: NEVER expose property_id, property_secret, or apiKey to the browser

			// These credentials give full API access and must remain server-side only



			// Only return non-sensitive configuration data

			return rest_ensure_response([

				'status' => 'success',

				'message' => 'Options retrieved successfully',

				// Only include non-sensitive settings here if frontend needs them

				'is_configured' => !empty($options['sensfrx_property_id']) && !empty($options['sensfrx_property_secret'])

			]);



		}



		function sensfrx_post_policy_options(WP_REST_Request $request) {



			$options = get_option('sensfrx_policy_options', SensFRX::default_policy_options());



			if ($request->has_param('sensfrx_medium_email')) {



				$options['sensfrx_medium_email'] = sanitize_text_field($request->get_param('sensfrx_medium_email'));



			}



			if ($request->has_param('sensfrx_challenge_email')) {



				$options['sensfrx_challenge_email'] = sanitize_text_field($request->get_param('sensfrx_challenge_email'));



			}



			if ($request->has_param('sensfrx_deny_email')) {



				$options['sensfrx_deny_email'] = sanitize_text_field($request->get_param('sensfrx_deny_email'));



			}



			if ($request->has_param('sensfrx_allow_payment_email')) {



				$options['sensfrx_allow_payment_email'] = sanitize_text_field($request->get_param('sensfrx_allow_payment_email'));



			}



			if ($request->has_param('sensfrx_challenge_payment_email')) {



				$options['sensfrx_challenge_payment_email'] = sanitize_text_field($request->get_param('sensfrx_challenge_payment_email'));



			}



			if ($request->has_param('sensfrx_deny_payment_email')) {



				$options['sensfrx_deny_payment_email'] = sanitize_text_field($request->get_param('sensfrx_deny_payment_email'));



			}



			if ($request->has_param('sensfrx_allow_register_email')) {



				$options['sensfrx_allow_register_email'] = sanitize_text_field($request->get_param('sensfrx_allow_register_email'));



			}



			if ($request->has_param('sensfrx_challenge_register_email')) {



				$options['sensfrx_challenge_register_email'] = sanitize_text_field($request->get_param('sensfrx_challenge_register_email'));



			}



			if ($request->has_param('sensfrx_deny_register_email')) {



				$options['sensfrx_deny_register_email'] = sanitize_text_field($request->get_param('sensfrx_deny_register_email'));



			}



			if ($request->has_param('sensfrx_webhook_allow')) {



				$options['sensfrx_webhook_allow'] = sanitize_text_field($request->get_param('sensfrx_webhook_allow'));



			}



			if ($request->has_param('sensfrx_whitle_list_email')) {



				$options['sensfrx_whitle_list_email'] = sanitize_text_field($request->get_param('sensfrx_whitle_list_email'));



			}



			if ($request->has_param('sensfrx_master_fraud')) {



				$options['sensfrx_master_fraud'] = sanitize_text_field($request->get_param('sensfrx_master_fraud'));



			}



			if ($request->has_param('sensfrx_new_account_fraud')) {



				$options['sensfrx_new_account_fraud'] = sanitize_text_field($request->get_param('sensfrx_new_account_fraud'));



			}



			if ($request->has_param('sensfrx_bot_fraud')) {



				$options['sensfrx_bot_fraud'] = sanitize_text_field($request->get_param('sensfrx_bot_fraud'));



			}



			if ($request->has_param('sensfrx_login_fraud')) {



				$options['sensfrx_login_fraud'] = sanitize_text_field($request->get_param('sensfrx_login_fraud'));



			}



			if ($request->has_param('sensfrx_reset_password_fraud')) {



				$options['sensfrx_reset_password_fraud'] = sanitize_text_field($request->get_param('sensfrx_reset_password_fraud'));



			}



			if ($request->has_param('sensfrx_before_payment_fraud')) {



				$options['sensfrx_before_payment_fraud'] = sanitize_text_field($request->get_param('sensfrx_before_payment_fraud'));



			}



			if ($request->has_param('sensfrx_after_payment_fraud')) {



				$options['sensfrx_after_payment_fraud'] = sanitize_text_field($request->get_param('sensfrx_after_payment_fraud'));



			}



			if ($request->has_param('sensfrx_shadow_mode')) {



				$sensfrx_shadow_mode = sanitize_text_field($request->get_param('sensfrx_shadow_mode'));



				$options1 = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				$obj = new SensFRX\SensFRX([



					'property_id' => $options1['sensfrx_property_id'],



					'property_secret' => $options1['sensfrx_property_secret']



				]);



				$shadow_status = $obj->getshadowinfo(); 



				if ( !isset($shadow_status['shadow_mode']) || 'success' != $shadow_status['status']) {



					return new WP_Error('shadow_info_error', 'Failed to retrieve shadow mode info.', ['status' => 500]);



				}



				if ($shadow_status['shadow_mode'] != $sensfrx_shadow_mode) {



					$postDataArray = array(



						'shadow_mode' => $sensfrx_shadow_mode, 



					); 



					$res_shadow_post = $obj->postshadowinfo($postDataArray);



					$res_shadow_post = json_decode($res_shadow_post[0]);



					if ('success' != $res_shadow_post->status) {



						return new WP_Error('shadow_update_failed', 'Failed to update shadow mode.', ['status' => 500]);



					}



					global $wpdb;



					$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_shadow_activity' );



					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQL.NotPrepared -- Table name is sanitized with esc_sql(). No WHERE clause, no user input.

					$existing_record = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name_shadow_table}");



					$data = array(



						'sensfrx_shadow_status' => $sensfrx_shadow_mode,



					);



					if ($existing_record > 0) {



						$results = $wpdb->update($table_name_shadow_table, $data, array('id' => 1)); // Assuming there's a single row



					} else {



						$results = $wpdb->insert($table_name_shadow_table, $data);



					}



					if (false === $results) {



						return new WP_Error('db_operation_failed', 'Failed to update or insert shadow mode in database.', ['status' => 500]);



					}







				}



			}



			$update_status = update_option('sensfrx_policy_options', $options);



			if ($request->has_param('sensfrx_master_fraud') || $request->has_param('sensfrx_new_account_fraud') || $request->has_param('sensfrx_bot_fraud') || $request->has_param('sensfrx_login_fraud') || $request->has_param('sensfrx_reset_password_fraud') || $request->has_param('sensfrx_before_payment_fraud') || $request->has_param('sensfrx_after_payment_fraud')) {



				$insert_data = "Updated fraud prevention setting.";

				SensFRX_DB_Helper::insert_activity_log('Fraud Prevention Settings', $insert_data);



			}



			return rest_ensure_response(['message' => 'Settings updated successfully']);	



		}



		function sensfrx_get_policy_options() {



			$sensfrx_policy_options = get_option('sensfrx_policy_options', SensFRX::default_policy_options());



			$sensfrx_white_list_admin_users = get_users(array('role' => 'administrator'));



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			global $wpdb;



			$res_shadow = SensFRX_DB_Helper::safe_select(

				'sensfrx_shadow_activity',

				'sensfrx_shadow_status',

				'',

				array(),

				'',

				ARRAY_A

			);



			$sensfrx_allow = $sensfrx_policy_options['sensfrx_medium_email'];



			$sensfrx_challenge = $sensfrx_policy_options['sensfrx_challenge_email'];



			$sensfrx_deny = $sensfrx_policy_options['sensfrx_deny_email'];



			$sensfrx_trans_allow = $sensfrx_policy_options['sensfrx_allow_payment_email'];



			$sensfrx_trans_challenge = $sensfrx_policy_options['sensfrx_challenge_payment_email'];



			$sensfrx_trans_deny = $sensfrx_policy_options['sensfrx_deny_payment_email'];



			$sensfrx_reg_allow = $sensfrx_policy_options['sensfrx_allow_register_email'];



			$sensfrx_reg_challenge = $sensfrx_policy_options['sensfrx_challenge_register_email'];



			$sensfrx_reg_deny = $sensfrx_policy_options['sensfrx_deny_register_email'];



			$sensfrx_webhook = $sensfrx_policy_options['sensfrx_webhook_allow'];



			$sensfrx_whitelist = $sensfrx_policy_options['sensfrx_whitle_list_email'];



			// $sensfrx_shadow_mode = $res_shadow[0]['sensfrx_shadow_status'];



			$sensfrx_shadow_mode = (is_array($res_shadow) && isset($res_shadow[0]['sensfrx_shadow_status'])) ? $res_shadow[0]['sensfrx_shadow_status'] : null;



			$sensfrx_master_fraud = $sensfrx_policy_options['sensfrx_master_fraud'];



			$sensfrx_new_account_fraud = $sensfrx_policy_options['sensfrx_new_account_fraud'];



			$sensfrx_bot_fraud = $sensfrx_policy_options['sensfrx_bot_fraud'];



			$sensfrx_login_fraud = $sensfrx_policy_options['sensfrx_login_fraud'];



			$sensfrx_reset_password_fraud = $sensfrx_policy_options['sensfrx_reset_password_fraud'];



			$sensfrx_before_payment_fraud = $sensfrx_policy_options['sensfrx_before_payment_fraud'];



			$sensfrx_after_payment_fraud = $sensfrx_policy_options['sensfrx_after_payment_fraud'];



			



			return rest_ensure_response([



				'sensfrx_medium_email' => $sensfrx_allow,



				'sensfrx_challenge_email' => $sensfrx_challenge,



				'sensfrx_deny_email' => $sensfrx_deny,



				'sensfrx_allow_payment_email' => $sensfrx_trans_allow,



				'sensfrx_challenge_payment_email' => $sensfrx_trans_challenge,



				'sensfrx_deny_payment_email' => $sensfrx_trans_deny,



				'sensfrx_allow_register_email' => $sensfrx_reg_allow,



				'sensfrx_challenge_register_email' => $sensfrx_reg_challenge,



				'sensfrx_deny_register_email' => $sensfrx_reg_deny,



				'sensfrx_webhook_allow' => $sensfrx_webhook,



				'sensfrx_whitle_list_email' => $sensfrx_whitelist,



				'sensfrx_shadow_mode' => $sensfrx_shadow_mode,



				'sensfrx_whtilelist_data' => $sensfrx_white_list_admin_users,



				'sensfrx_master_fraud' => $sensfrx_master_fraud,



				'sensfrx_new_account_fraud' => $sensfrx_new_account_fraud,



				'sensfrx_bot_fraud' => $sensfrx_bot_fraud,



				'sensfrx_login_fraud' => $sensfrx_login_fraud,



				'sensfrx_reset_password_fraud' => $sensfrx_reset_password_fraud,



				'sensfrx_before_payment_fraud' => $sensfrx_before_payment_fraud,



				'sensfrx_after_payment_fraud' => $sensfrx_after_payment_fraud,



			]);



		}



		function sensfrx_get_notification_settings() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => $options['sensfrx_property_id'],



				'property_secret' => $options['sensfrx_property_secret']



			]);



			$resAlert = $obj->getalertsinfo();



			$resAlert = (array) $resAlert;



			if (is_array($resAlert) && isset($resAlert['status']) && $resAlert['status'] === 'success') {



				$AlertData = (array) $resAlert['data'];

				$options = get_option('sensfrx_options', SensFRX::default_options());

				// Update only specific values

				$options['notification_email']   = $AlertData['email'] ?? $options['notification_email'];

				$options['review_threshold']     = $AlertData['risk_threshold'] ?? $options['review_threshold'];

				$options['email_notifications']  = isset($AlertData['enabled']) && $AlertData['enabled'] == '1' ? "1" : "0";

				// Save back

				update_option('sensfrx_options', $options);



				return rest_ensure_response([



					'status_notify' => 'success',



					'enabled_notify' => ($AlertData['enabled'] == '1') ? "1" : "0",



					'risk_threshold_notify' => $AlertData['risk_threshold'] ?? '30',



					'email_notify' => $AlertData['email'] ?? '',



				]);



			} else {



				return rest_ensure_response([



					'status_notify' => "error",



					'message' => 'Failed to retrieve alert settings'



				]);



			}	



		}



		function sensfrx_post_notification_settings(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$enabledNotify = $request->has_param('enabledNotify') ? sanitize_text_field($request->get_param('enabledNotify')) : null;



				$riskThresholdNotify = $request->has_param('riskThresholdNotify') ? sanitize_text_field($request->get_param('riskThresholdNotify')) : null;



				$emailNotify = $request->has_param('emailNotify') ? sanitize_email($request->get_param('emailNotify')) : null;



				if ($enabledNotify === null && $riskThresholdNotify === null && $emailNotify === null) {



					return new WP_Error('no_data', 'No valid data provided', ['status' => 400]);



				}



				$postDataArray = [



					'enabled' => $enabledNotify,



					'risk_threshold' => $riskThresholdNotify,



					'email' => $emailNotify



				];



				$res = $obj->postalertsinfo($postDataArray);



				if (!is_array($res) || !isset($res['status'])) {



					return new WP_Error('api_error', 'Invalid API Response', ['status' => 500]);



				}



				if ($res['status'] !== 'success') {



					return new WP_Error('api_error', 'Failed to update settings: ' . ($res['message'] ?? 'Unknown error'), ['status' => 500]);



				}



				$options = get_option('sensfrx_options', SensFRX::default_options());

				// Update only specific values

				$options['notification_email'] = $emailNotify ?? $options['notification_email'];

				$options['review_threshold'] = $riskThresholdNotify ?? $options['review_threshold'];

				$options['email_notifications'] = $enabledNotify == '1' ? "1" : "0";

				// Save back

				update_option('sensfrx_options', $options);



				return rest_ensure_response(['status' => 'success', 'message' => 'Settings updated successfully']);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}	



		function sensfrx_recent_activity_options() {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



		



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



		



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



		



				// Fetch recent alerts from API



				$res = $obj->getrecentalertinfo();



				// Convert stdClass to array if needed

				if (is_object($res)) {

					$res = json_decode(json_encode($res), true);

				}



				// Check if response contains valid data

				if (!isset($res['status']) || $res['status'] !== 'success' || !isset($res['data']['recent_alerts'])) {

					return new WP_Error('invalid_response', 'Invalid API response', ['status' => 500]);

				}



		



				// Return response in expected format



				return rest_ensure_response([

					'status' => 'success',

					'sensfrx_recent_activity' => $res['data']['recent_alerts']

				]);



		



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error processing request: ' . $e->getMessage(), ['status' => 500]);



			}



		}	



		function sensfrx_default_policy_options() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => sanitize_text_field($options['sensfrx_property_id']),



				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



			]);



			$res = $obj->getrulesinfo();



			if (is_array($res)) {



				if ('success' === $res['status']) {



					$detector_date = $res['data'];



					$detector_date = array_map(function($item) {



						return (array) $item;



					}, $detector_date);



					usort($detector_date, function ($a, $b) {



						return strcmp($a['title'], $b['title']);



					});



				}



			}



			return rest_ensure_response([



				'sensfrx_defaul_policy_list' => $detector_date,



			]);



		}



		function sensfrx_post_default_policy_options(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



		



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



		



				$res = $obj->getrulesinfo();



		



				if (is_array($res) && isset($res['status']) && $res['status'] === 'success') {



					$detector_date = $res['data'];



		



					// Convert object values to arrays (if needed)



					$detector_date = array_map(function($item) {



						return (array) $item;



					}, $detector_date);



		



					// Sort A-Z by 'title'



					usort($detector_date, function ($a, $b) {



						return strcmp($a['title'], $b['title']);



					});



		



					$params = $request->get_params();



					// $params['policies'][0]



					$score_values = [];



					$actions = [];



					$actives = [];







					foreach ($params['policies'] as $policy) {



						$score_values[] = $policy['score_value'];



						$actions[] = $policy['action'];



						$actives[] = $policy['active'];



					}







					$score_values_str = implode(',', $score_values);



					$actions_str = implode(',', $actions);



					$actives_str = implode(',', $actives);



					$score_values_str1 = explode(',', $score_values_str);



					$actions_str1 = explode(',', $actions_str);



					$actives_str1 = explode(',', $actives_str);



				



					foreach ($detector_date as &$item) {



						// Assign values from the score_array and active_array using array_shift



						$item['score_value'] = array_shift($score_values_str1);



						$item['active'] = array_shift($actives_str1);



						$item['action'] = array_shift($actions_str1);



					}



					$res_Validation = $obj->postrulesinfo($detector_date);



					if (is_array($res_Validation)) {



						if ($res_Validation['status'] === 'success') {



							return rest_ensure_response([



								'status'  => 'success',



								'message' => 'Settings updated successfully',



								'data'    => $res_Validation, 



							]);



						} else {



							return rest_ensure_response([



								'status'  => 'error',



								'message' => isset($res_Validation['message']) ? $res_Validation['message'] : 'Failed to update settings.',



								'error_data' => $res_Validation, // Provide full response for debugging



							]);



						}



					} else {



						return rest_ensure_response([



							'status'  => 'error',



							'message' => 'Unexpected response format from API.' . $res_Validation,



						]);



					}



				}



				return new WP_Error('server_error', 'Failed to retrieve policy data.', ['status' => 500]);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}



		function get_sensfrx_license_info() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => sanitize_text_field($options['sensfrx_property_id']),



				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



			]);



			$res_license = $obj->getlicenseinfo(); 



			$property_id = $options['sensfrx_property_id'];



			$property_secret = $options['sensfrx_property_secret'];



			$apiKey = base64_encode($property_id . ':' . $property_secret);



			if (is_array($res_license) && $res_license['status'] === 'success') {



				// Merge license data with local OFAC settings

				$license_data = (array) $res_license['data'];

				$license_data['ofac_enabled'] = isset($options['sensfrx_ofac_enabled']) && $options['sensfrx_ofac_enabled'] === '1';



				return new WP_REST_Response([



					'status' => 'success',



					'data' => $license_data,



					// SECURITY: API key removed - credentials should NEVER be exposed to browser



				], 200);



			}



			return new WP_REST_Response([



				'status' => 'error',



				'message' => 'License data not found'



			], 400);



		}



		function get_sensfrx_fraud_rate() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => sanitize_text_field($options['sensfrx_property_id']),



				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



			]);



			$res_fraudRate = $obj->getFraudRateInfo(); 



			$property_id = $options['sensfrx_property_id'];



			$property_secret = $options['sensfrx_property_secret'];



			$apiKey = base64_encode($property_id . ':' . $property_secret);



			if (is_array($res_fraudRate) && $res_fraudRate['status'] === 'success') {



				// Merge license data with local OFAC settings

				$fraudRate_data = (array) $res_fraudRate['data'];

				// $fraudRate_data['ofac_enabled'] = isset($options['sensfrx_ofac_enabled']) && $options['sensfrx_ofac_enabled'] === '1';



				return new WP_REST_Response([



					'status' => 'success',



					'data' => $fraudRate_data,



					// SECURITY: API key removed - credentials should NEVER be exposed to browser



				], 200);



			}



			return new WP_REST_Response([



				'status' => 'error',



				'message' => 'fraud rate data not found'



			], 400);



		}



		function get_sensfrx_stats_data(WP_REST_Request $request) {



			$selectedPeriod = sanitize_text_field($request->get_param('selectedPeriod'));



			// Default: last 7 days (to match your HTML default)

			$today = date('d-m-Y');

			$DateFilter = [];



			switch ($selectedPeriod) {



				case 'today':

					// Only today's data

					$DateFilter = [

						'from_date' => $today,

						'to_date'   => $today

					];

					break;



				case 'yesterday':

					// Only yesterday's data

					$yesterday = date('d-m-Y', strtotime('-1 day'));

					$DateFilter = [

						'from_date' => $yesterday,

						'to_date'   => $yesterday

					];

					break;



				case '7days':

					// Today & Last 7 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-7 days')),

						'to_date'   => $today

					];

					break;



				case '15days':

					// Today & Last 15 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-15 days')),

						'to_date'   => $today

					];

					break;



				case '30days':

					// Today & Last 30 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-30 days')),

						'to_date'   => $today

					];

					break;



				case '60days':

					// Today & Last 60 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-60 days')),

						'to_date'   => $today

					];

					break;



				case '90days':

					// Today & Last 90 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-90 days')),

						'to_date'   => $today

					];

					break;



				case '120days':

					// Today & Last 30 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-120 days')),

						'to_date'   => $today

					];

					break;



				default:

					// Fallback (optional)

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-7 days')),

						'to_date'   => $today

					];

					break;

			}



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => sanitize_text_field($options['sensfrx_property_id']),



				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



			]);



			$total_trans = $obj->getTransStatsinfo($DateFilter);

			$total_reg = $obj->getRegStatsinfo($DateFilter);

			$total_ato = $obj->getAtoStatsinfo($DateFilter);

			$total_bot = $obj->getBotStatsinfo($DateFilter);



			if ($total_trans['status'] == 'success' && $total_reg['status'] == 'success' && $total_ato['status'] == 'success' && $total_bot['status'] == 'success') {

				$transArray = $total_trans['data'];

                $regArray = $total_reg['data'];

                $atoArray = $total_ato['data'];

                $botArray = $total_bot['data'];

				return new WP_REST_Response([

					'status' => 'success',

					'transArray' => $transArray,

					'regArray' => $regArray,

					'atoArray' => $atoArray,

					'botArray' => $botArray,

				], 200);

			}

			return new WP_REST_Response([

				'status' => 'error',

				'message' => 'Stats data not found',

				'T' => $total_trans,

				'R' => $total_reg,

				'A' => $total_ato,

				'B' => $total_bot,

			], 400);



		}



		function sensfrx_get_blacklist() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			$property_id = sanitize_text_field($options['sensfrx_property_id']);



			$property_secret = sanitize_text_field($options['sensfrx_property_secret']);



			$apiKey = base64_encode($property_id . ':' . $property_secret);



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => $options['sensfrx_property_id'],



				'property_secret' => $options['sensfrx_property_secret']



			]);



			$res = $obj->getblacklistinfo();



			$res = json_decode(json_encode($res), true); // Convert object to array







			if (!isset($res['status']) || $res['status'] !== 'success' || !isset($res['data'])) {



				return rest_ensure_response([



					'error' => 'Invalid API response',



					'response' => $res



				]);



			}







			$data = $res['data'];



			return rest_ensure_response([



				'ip'   => isset($data['ip']) ? $data['ip'] : [],



				'uID'  => isset($data['uID']) ? $data['uID'] : [],



				'ue'   => isset($data['ue']) ? $data['ue'] : [],



				'un'   => isset($data['un']) ? $data['un'] : [],



				// SECURITY: API key removed - credentials should NEVER be exposed to browser



			]);



		}



		function sensfrx_get_whitelist() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			$property_id = sanitize_text_field($options['sensfrx_property_id']);



			$property_secret = sanitize_text_field($options['sensfrx_property_secret']);



			$apiKey = base64_encode($property_id . ':' . $property_secret);



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => $options['sensfrx_property_id'],



				'property_secret' => $options['sensfrx_property_secret']



			]);



			$res = $obj->getwhitelistinfo();



			$res = json_decode(json_encode($res), true); // Convert object to array







			if (!isset($res['status']) || $res['status'] !== 'success' || !isset($res['data'])) {



				return rest_ensure_response([



					'error' => 'Invalid API response',



					'response' => $res



				]);



			}







			$data = $res['data'];



			return rest_ensure_response([



				'ip'   => isset($data['ip']) ? $data['ip'] : [],



				'uID'  => isset($data['uID']) ? $data['uID'] : [],



				'ue'   => isset($data['ue']) ? $data['ue'] : [],



				'un'   => isset($data['un']) ? $data['un'] : [],



				// SECURITY: API key removed - credentials should NEVER be exposed to browser



			]);



		}	



		function sensfrx_get_advance_rules() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			$property_id = sanitize_text_field($options['sensfrx_property_id']);



			$property_secret = sanitize_text_field($options['sensfrx_property_secret']);



			$apiKey = base64_encode($property_id . ':' . $property_secret);



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => $options['sensfrx_property_id'],



				'property_secret' => $options['sensfrx_property_secret']



			]);



			$res = $obj->getadvancerulesinfo();



			if (is_array($res)) {



				if ('success' === $res['status']) {



					// Extract the 'data' array



					$detector_date = $res['data'];



			



					// Convert each item to an array



					$detector_date = array_map(function($item) {



						return (array) $item;



					}, $detector_date);



			



					// Sort the data by 'title'



					usort($detector_date, function ($a, $b) {



						return strcmp($a['title'], $b['title']);



					});



				}



			}



			



			return rest_ensure_response([



				'sensfrx_advancd_rules_list' => $detector_date,  // Change the key to match whitelist



			]);



		}	



		function sensfrx_post_advanced_advanced_rules(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



		



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



		



				$res = $obj->getadvancerulesinfo();



		



				if (is_array($res) && isset($res['status']) && $res['status'] === 'success') {



					$detector_date = $res['data'];



		



					// Convert object values to arrays (if needed)



					$detector_date = array_map(function($item) {



						return (array) $item;



					}, $detector_date);



		



					// Sort A-Z by 'title'



					usort($detector_date, function ($a, $b) {



						return strcmp($a['title'], $b['title']);



					});



		



					$params = $request->get_params();



					// $params['policies'][0]



					$score_values = [];



					$actions = [];



					$actives = [];







					foreach ($params['policies'] as $policy) {



						$score_values[] = $policy['score_value'];



						$actions[] = $policy['action'];



						$actives[] = $policy['active'];



					}







					$score_values_str = implode(',', $score_values);



					$actions_str = implode(',', $actions);



					$actives_str = implode(',', $actives);



					$score_values_str1 = explode(',', $score_values_str);



					$actions_str1 = explode(',', $actions_str);



					$actives_str1 = explode(',', $actives_str);



				



					foreach ($detector_date as &$item) {



						// Assign values from the score_array and active_array using array_shift



						$item['score_value'] = array_shift($score_values_str1);



						$item['active'] = array_shift($actives_str1);



						$item['action'] = array_shift($actions_str1);



					}



					$res_Validation = $obj->postadvancerulesinfo($detector_date);



					if (is_array($res_Validation)) {



						if ($res_Validation['status'] === 'success') {



							return rest_ensure_response([



								'status'  => 'success',



								'message' => 'Settings updated successfully',



								'data'    => $res_Validation, 



							]);



						} else {



							return rest_ensure_response([



								'status'  => 'error',



								'message' => isset($res_Validation['message']) ? $res_Validation['message'] : 'Failed to update settings.',



								'error_data' => $res_Validation, // Provide full response for debugging



							]);



						}



					} else {



						return rest_ensure_response([



							'status'  => 'error',



							'message' => 'Unexpected response format from API.' . $res_Validation,



						]);



					}



				}



				return new WP_Error('server_error', 'Failed to retrieve policy data.', ['status' => 500]);



			}  catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}



		function sensfrx_post_blacklist(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$blackListField = $request->has_param('field') ? sanitize_text_field($request->get_param('field')) : null;



				$blackListValue = $request->has_param('value') ? sanitize_text_field($request->get_param('value')) : null;



				if ($blackListField === null && $blackListValue === null) {



					return new WP_Error('no_data', 'No valid data provided', ['status' => 400]);



				}



				$request_body = [



					"field" => $blackListField,



					"value" => $blackListValue



				];



				$res = $obj->postblacklistinfo($request_body);



				if (!is_array($res) || !isset($res['status'])) {

					return new WP_Error('api_error', 'Invalid API Response: ' . json_encode($res), ['status' => 500]);

				}



				if ($res['status'] !== 'success') {

					// Extract error message from SDK response (check multiple possible fields)

					$error_msg = $res['message'] ?? $res['error_message'] ?? 'Unknown error';

					

					// Return the actual error message without extra wrapping

					return new WP_Error('api_error', $error_msg, ['status' => 400]);



				}



				return rest_ensure_response(['status' => $res['status'], 'message' => $res['message']]);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}	



		function sensfrx_post_delete_blacklist(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$blackListField = $request->has_param('field') ? sanitize_text_field($request->get_param('field')) : null;



				$blackListValue = $request->has_param('value') ? sanitize_text_field($request->get_param('value')) : null;



				if ($blackListField === null && $blackListValue === null) {



					return new WP_Error('no_data', 'No valid data provided', ['status' => 400]);



				}



				$request_body = [



					"field" => $blackListField,



					"value" => $blackListValue



				];



				$res = $obj->postblacklistdeleteinfo($request_body);



				if (!is_array($res) || !isset($res['status'])) {



					return new WP_Error('api_error', 'Invalid API Response' .$blackListField.' '.$blackListValue , ['status' => 500]);



				}



				if ($res['status'] !== 'success') {



					// Extract error message from SDK response (check multiple possible fields)

					$error_msg = $res['message'] ?? $res['error_message'] ?? 'Unknown error';

					return new WP_Error('api_error', $error_msg, ['status' => 400]);



				}



				return rest_ensure_response(['status' => 'success', 'message' => 'Blacklist Value Deleted successfully']);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}



		function sensfrx_post_whitelist(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$blackListField = $request->has_param('field') ? sanitize_text_field($request->get_param('field')) : null;



				$blackListValue = $request->has_param('value') ? sanitize_text_field($request->get_param('value')) : null;



				if ($blackListField === null && $blackListValue === null) {



					return new WP_Error('no_data', 'No valid data provided', ['status' => 400]);



				}



				$request_body = [



					"field" => $blackListField,



					"value" => $blackListValue



				];



				$res = $obj->postwhitelistinfo($request_body);



				if (!is_array($res) || !isset($res['status'])) {



					return new WP_Error('api_error', 'Invalid API Response' .json_encode($res) , ['status' => 500]);



				}



				if ($res['status'] !== 'success') {



					// Extract error message from SDK response (check multiple possible fields)

					$error_msg = $res['message'] ?? $res['error_message'] ?? 'Unknown error';

					return new WP_Error('api_error', $error_msg, ['status' => 400]);



				}



				return rest_ensure_response(['status' => $res['status'], 'message' => $res['message']]);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}



		function sensfrx_post_delete_whitelist(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$blackListField = $request->has_param('field') ? sanitize_text_field($request->get_param('field')) : null;



				$blackListValue = $request->has_param('value') ? sanitize_text_field($request->get_param('value')) : null;



				if ($blackListField === null && $blackListValue === null) {



					return new WP_Error('no_data', 'No valid data provided', ['status' => 400]);



				}



				$request_body = [



					"field" => $blackListField,



					"value" => $blackListValue



				];



				$res = $obj->postwhitelistDeleteinfo($request_body);



				if (!is_array($res) || !isset($res['status'])) {



					return new WP_Error('api_error', 'Invalid API Response' .$blackListField.' '.$blackListValue , ['status' => 500]);



				}



				if ($res['status'] !== 'success') {



					// Extract error message from SDK response (check multiple possible fields)

					$error_msg = $res['message'] ?? $res['error_message'] ?? 'Unknown error';

					return new WP_Error('api_error', $error_msg, ['status' => 400]);



				}



				return rest_ensure_response(['status' => 'success', 'message' => 'Blacklist Value Deleted successfully']);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}	



		function sensfrx_post_trans_review(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return rest_ensure_response(['status' => 'error', 'message' => 'Missing property ID or secret key']);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$transAction = $request->has_param('transAction') ? sanitize_text_field($request->get_param('transAction')) : null;



				$transID = $request->has_param('transID') ? sanitize_text_field($request->get_param('transID')) : null;



				$orderID = $request->has_param('orderID') ? sanitize_text_field($request->get_param('orderID')) : null;



				if ($transAction === null || $transID === null) {



					return rest_ensure_response(['status' => 'error', 'message' => 'No valid data provided']);



				}



		



				// Get the order object using the transaction ID



				$sensfrx_order = wc_get_order($orderID);



				if (!$sensfrx_order) {



					return rest_ensure_response(['status' => 'error', 'message' => 'Order not found for order ID: ' . $orderID]);



				}



				// Handle approve action



				if ('approve' == $transAction) {



					$postDataArray = [



						'trans_id' => $transID,



						'action' => $transAction,



						'order_id' => $orderID,



					];



					$resultAlert = $obj->postTrans_Review($postDataArray);



					if (!is_array($resultAlert) || !isset($resultAlert['status'])) {



						$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Approval failed | Reason: Invalid API response";

						SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



						return rest_ensure_response(['status' => 'error', 'message' => 'Invalid API Response']);



					}



					if ($resultAlert['status'] !== 'success') {



						$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Approval failed | Reason: API returned error status";

						SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



						return rest_ensure_response(['error' => 'error', 'message' => 'Failed to update settings']);



					}



					// Update order status to processing



					global $wpdb;



					$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_pre_payment_order' );



					$existing_record = $wpdb->get_var(



						$wpdb->prepare(

							// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %d placeholder.

							"SELECT COUNT(*) FROM {$table_name_shadow_table} WHERE pre_order_id = %d",



							$orderID



						)



					);



					if ( 0 == $existing_record || '0' == $existing_record ) {



						$order_updated = $sensfrx_order->update_status('processing', 'Sensfrx - Order status updated to Processing.');



						$sensfrx_order->update_status('processing', 'Sensfrx - Order status updated to Processing.');



						$user_email = $sensfrx_order->get_billing_email();



						// Get default email content (no database customization)

						$default_email = SensFRX_email_template::get_default_message('transaction_review_approve');

						$subject = $default_email['subject'];

						$message = $default_email['message'];



						$date = date('Y M d');

						$time = date('H:i:s');



						$replacements = [

							'{$client_full_name}' => $sensfrx_order->get_billing_first_name(),

							'{$order_id}' => $orderID,

							'{$date}' => $date,

							'{$time}' => $time,

							'{$default_brand_name}' => get_bloginfo('name'),

						];



						// Use universal email wrapper for professional formatting

						SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



						if (!$order_updated) {



							$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Approval failed | Reason: Failed to update WooCommerce order status";

							SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



							return rest_ensure_response(['status' => 'error', 'message' => 'Failed to update order status']);



						}



					} else {



						$user_email = $sensfrx_order->get_billing_email();



						$payment_url = $sensfrx_order->get_checkout_payment_url();



						// Get default email content (no database customization)

						$default_email = SensFRX_email_template::get_default_message('transaction_review_approve_payment');

						$subject = $default_email['subject'];

						$message = $default_email['message'];



						$date = date('Y M d');

						$time = date('H:i:s');



						$replacements = [

							'{$client_full_name}' => $sensfrx_order->get_billing_first_name(),

							'{$order_id}' => $orderID,

							'{$payment_url}' => $payment_url,

							'{$date}' => $date,

							'{$time}' => $time,

							'{$default_brand_name}' => get_bloginfo('name'),

						];



						// Use universal email wrapper for professional formatting

						SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



					}



					$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Approved via manual review | Customer: " . $email;

					SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



					if ( $existing_record > 0 ) {



						$results = $wpdb->delete(



							$table_name_shadow_table,



							array( 'pre_order_id' => $orderID ),



							array( '%d' )



						);



					}



					return rest_ensure_response(['status' => 'success', 'message' => 'Transaction Review Approved successfully']);



				}



				// Handle reject action



				if ('reject' == $transAction) {



					$postDataArray = [



						'trans_id' => $transID,



						'action' => $transAction,



						'order_id' => $orderID,



					];



					$resultAlert = $obj->postTrans_Review($postDataArray);



					if (!is_array($resultAlert) || !isset($resultAlert['status'])) {



						$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Rejection failed | Reason: Invalid API response";

						SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



						return new WP_Error('api_error', 'Invalid API Response', ['status' => 500]);



					}



					if ($resultAlert['status'] !== 'success') {



						$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Rejection failed | Reason: API returned error status";

						SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



						return new WP_Error('api_error', 'Failed to update settings: ' . ($resultAlert['message'] ?? 'Unknown error'), ['status' => 500]);



					} 



					// Update order status to cancelled



					global $wpdb;



					$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_pre_payment_order' );



					$existing_record = $wpdb->get_var(



						$wpdb->prepare(

							// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %d placeholder.

							"SELECT COUNT(*) FROM {$table_name_shadow_table} WHERE pre_order_id = %d",



							$orderID



						)



					);



					$order_updated = $sensfrx_order->update_status('cancelled', 'Sensfrx - Order marked as cancelled due to fraudulent activity.');



					if (!$order_updated) {



						$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Rejection failed | Reason: Failed to update WooCommerce order status";

						SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



						return new WP_Error('order_update_failed', 'Failed to update order status.', ['status' => 500]);



					}



				$user_email = $sensfrx_order->get_billing_email();



				// Get default email content (no database customization)

				$default_email = SensFRX_email_template::get_default_message('transaction_review_deny');

				$subject = $default_email['subject'];

				$message = $default_email['message'];



				$date = date('Y M d');

				$time = date('H:i:s');



				$replacements = [

					'{$client_full_name}' => $sensfrx_order->get_billing_first_name(),

					'{$order_id}' => $orderID,

					'{$date}' => $date,

					'{$time}' => $time,

					'{$default_brand_name}' => get_bloginfo('name'),

				];



				// Use universal email wrapper for professional formatting

				SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



					$insert_data = "Order #" . $orderID . " (Trans: " . $transID . ") | Rejected via manual review | Customer: " . $email;

					SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



					if ( $existing_record > 0 ) {



						$results = $wpdb->delete(



							$table_name_shadow_table,



							array( 'pre_order_id' => $orderID ),



							array( '%d' )



						);



					}



					return rest_ensure_response(['status' => 'success', 'message' => 'Transaction Review Rejected successfully']);



				}



			} catch (Exception $e) {



				$insert_data = "Order review failed | Reason: Invalid request parameters or missing data";

				SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



				return rest_ensure_response(['status' => 'error', 'message' => 'Error while updating settings']);



			}



		}



		function sensfrx_post_trans_bulk_review(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$transAction = $request->has_param('transAction') ? sanitize_text_field($request->get_param('transAction')) : null;



				$transOrder_ids = $request->has_param('transOrder_ids') ? $request->get_param('transOrder_ids') : null;



				if (empty($transAction) || empty($transOrder_ids)) {



					return new WP_Error('invalid_request', 'Missing transaction action or order IDs ' . json_encode($transAction) . ' ' . json_encode($transOrder_ids), ['status' => 400]);



				}



				// Ensure transOrder_ids is an array



				if (!is_array($transOrder_ids)) {



					return new WP_Error('invalid_format', 'Transaction IDs must be an array.', ['status' => 400]);



				}



				// Sanitize each transaction ID



				$transOrder_ids = array_map('sanitize_text_field', $transOrder_ids);



				$transReviewBulkOrderIds = $transOrder_ids;



				$trans_review_transactions = [];



				$getTransReview = $obj->getTrans_Review();



				$getTransReview = isset($getTransReview['data']) ? (array) $getTransReview['data'] : [];



				if (!empty($getTransReview)) {



					foreach ($getTransReview as $order) {



						foreach ($transReviewBulkOrderIds as $bulk_action) {



							if ($order->order_id == $bulk_action) {



								$trans_review_transactions[] = [



									"trans_id" => $order->transaction_id, // Use => to define the key-value pair



									"action" => $transAction // Define the action



								];



							}



						}



					}



				}



				if (empty($trans_review_transactions)) {



					return new WP_Error('no_matching_orders', 'No matching transactions found for review. '.json_encode($transReviewBulkOrderIds), ['status' => 404]);



				}



				$postTransReview = $obj->postTrans_Review(['data' => $trans_review_transactions]);



				if (isset($postTransReview['status']) && $postTransReview['status'] === 'success') {



					foreach ($transReviewBulkOrderIds as $order_id) {



						$order = wc_get_order($order_id);



						if (is_a($order, 'WC_Order')) {



							if ($transAction === 'approve') {



								global $wpdb;



								$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_pre_payment_order' );



								$existing_record = $wpdb->get_var(



									$wpdb->prepare(

										// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %d placeholder.

										"SELECT COUNT(*) FROM {$table_name_shadow_table} WHERE pre_order_id = %d",



										$order_id



									)



								);



								if ( 0 == $existing_record || '0' == $existing_record ) {



									$order->update_status('processing', 'Sensfrx - Order status updated to Processing in bulk action.');



								$user_email = $order->get_billing_email();



								// Get default email content (no database customization)

								$default_email = SensFRX_email_template::get_default_message('transaction_review_approve');

								$subject = $default_email['subject'];

								$message = $default_email['message'];



								$date = date('Y M d');

								$time = date('H:i:s');



								$replacements = [

									'{$client_full_name}' => $order->get_billing_first_name(),

									'{$order_id}' => $order_id,

									'{$date}' => $date,

									'{$time}' => $time,

									'{$default_brand_name}' => get_bloginfo('name'),

								];



								// Use universal email wrapper for professional formatting

								SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



								} else {



									$user_email = $order->get_billing_email();



									$payment_url = $order->get_checkout_payment_url();



								// Get default email content (no database customization)

								$default_email = SensFRX_email_template::get_default_message('transaction_review_approve_payment');

								$subject = $default_email['subject'];

								$message = $default_email['message'];



								$date = date('Y M d');

								$time = date('H:i:s');



								$replacements = [

									'{$client_full_name}' => $order->get_billing_first_name(),

									'{$order_id}' => $order_id,

									'{$payment_url}' => $payment_url,

									'{$date}' => $date,

									'{$time}' => $time,

									'{$default_brand_name}' => get_bloginfo('name'),

								];



								// Use universal email wrapper for professional formatting

								SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



								}



								$insert_data = "Order #" . $order_id . " | Approved via bulk review | Customer: " . $order->get_billing_email();

								SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



								if ( $existing_record > 0 ) {



									$results = $wpdb->delete(



										$table_name_shadow_table,



										array( 'pre_order_id' => $order_id ),



										array( '%d' )



									);



								}



							} elseif ($transAction === 'reject') {



								global $wpdb;



								$table_name_shadow_table = esc_sql( $wpdb->prefix . 'sensfrx_pre_payment_order' );



								$existing_record = $wpdb->get_var(



									$wpdb->prepare(

										// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %d placeholder.

										"SELECT COUNT(*) FROM {$table_name_shadow_table} WHERE pre_order_id = %d",



										$order_id



									)



								);



								$order->update_status('cancelled', 'Sensfrx - Order status updated to Cancelled in bulk action.');



								$refund_args = [



									'amount'         => $order->get_total(),



									'order_id'       => $order_id,



									'reason'         => 'Refund due to detected fraudulent activity.',



									'refund_payment' => true,



								];



							$user_email = $order->get_billing_email();



							// Get default email content (no database customization)

							$default_email = SensFRX_email_template::get_default_message('transaction_review_deny');

							$subject = $default_email['subject'];

							$message = $default_email['message'];



							$date = date('Y M d');

							$time = date('H:i:s');



							$replacements = [

								'{$client_full_name}' => $order->get_billing_first_name(),

								'{$order_id}' => $order_id,

								'{$date}' => $date,

								'{$time}' => $time,

								'{$default_brand_name}' => get_bloginfo('name'),

							];



							// Use universal email wrapper for professional formatting

							SensFRX_email_template::wrap_and_send($user_email, $subject, $message, get_bloginfo('name'), $replacements);



								$insert_data = "Order #" . $order_id . " | Rejected via bulk review | Customer: " . $order->get_billing_email();

								SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



								if ( $existing_record > 0 ) {



									$results = $wpdb->delete(



										$table_name_shadow_table,



										array( 'pre_order_id' => $order_id ),



										array( '%d' )



									);



								}



								try {



									$refund = wc_create_refund($refund_args);



									if (is_wp_error($refund)) {



										$order->add_order_note('Refund failed: ' . $refund->get_error_message());



									} else {



										$order->add_order_note('Refund processed successfully for the cancelled order.');



									}



								} catch (Exception $e) {



									$order->add_order_note('Error during refund: ' . $e->getMessage());



								}



							}



						} else {



							error_log("Order with ID " . $order_id . " not found.");



							$insert_data = "Order #" . $order_id . " | Review failed | Reason: Order not found in WooCommerce";

							SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



						}



					}



					return rest_ensure_response(['status' => 'success', 'message' => 'Transactions reviewed successfully.']);



				} else {



					$insert_data = "Bulk order review failed | Reason: No matching orders found for review";

					SensFRX_DB_Helper::insert_activity_log('Order Review', $insert_data);



					return new WP_Error('review_failed', 'Failed to review transactions.', ['status' => 500]);



				}



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error processing request: ' . $e->getMessage(), ['status' => 500]);



			}



		}		



		function sensfrx_post_register_review(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



				$regAction = $request->has_param('regAction') ? sanitize_text_field($request->get_param('regAction')) : null;



				$regID = $request->has_param('regID') ? sanitize_text_field($request->get_param('regID')) : null;



				$userName = $request->has_param('userName') ? sanitize_text_field($request->get_param('userName')) : null;



				$eMail = $request->has_param('eMail') ? sanitize_text_field($request->get_param('eMail')) : null;



				$postDataArray = [



					'reg_id' => $regID,



					'action' => $regAction,



				];



				if ('approve' == $regAction) {



					$resultAlert = $obj->postAccount_Review($postDataArray);



					if (!is_array($resultAlert) || !isset($resultAlert['status'])) {



						$insert_data = "The account was not approve successfully for Email ID " . $eMail . ". Invalid API Response.";

						SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



						return new WP_Error('api_error', 'Invalid API Response', ['status' => 500]);



					}



					if ($resultAlert['status'] !== 'success') {



						$insert_data = "The account was not approve successfully for Email ID " . $eMail . ". Failed to create account.";

						SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



						return new WP_Error('api_error', 'Failed to update settings: ' . ($resultAlert['message'] ?? 'Unknown error'), ['status' => 500]);



					}



					$user_id = wp_create_user($userName, wp_generate_password(), $eMail);



					if (!is_wp_error($user_id)) {



						wp_send_new_user_notifications($user_id, 'user');



						$insert_data = "The account was approve successfully for Email ID " . $eMail . ".";

						SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);						



					} else {



						$error_message = $user_id->get_error_message();



						$subject = "Account Creation Error";



						$body = "Dear ". $userName .",\n\nWe encountered an issue while creating your account:\n\n" . $error_message . "\n\nPlease try again with a different username or contact support for assistance.";



						$headers = array('Content-Type: text/plain; charset=UTF-8');



						wp_mail($eMail, $subject, $body, $headers);



						$insert_data = "The account was not approve successfully for Email ID " . $eMail . ". Encountered an issue while creating the account";

						SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



					}



					return rest_ensure_response(['status' => 'success', 'message' => 'New Account Review Approved successfully']);



				}



				if ('reject' == $regAction) {



					$resultAlert = $obj->postAccount_Review($postDataArray);



					if (!is_array($resultAlert) || !isset($resultAlert['status'])) {



						$insert_data = "The account was not reject successfully for Email ID " . $eMail . ". Invalid API Response.";

						SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



						return new WP_Error('api_error', 'Invalid API Response', ['status' => 500]);



					}



					if ($resultAlert['status'] !== 'success') {



						$insert_data = "The account was not reject successfully for Email ID " . $eMail . ". Failed to create account.";

						SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



						return new WP_Error('api_error', 'Failed to update settings: ' . ($resultAlert['message'] ?? 'Unknown error'), ['status' => 500]);



					}



					$subject = "Account Rejected";



					$body = "Dear ". $userName ." ,\n\nWe regret to inform you that your account has been rejected by the admin. Please contact support for further assistance.\n\nThank you.";



					$headers = array('Content-Type: text/plain; charset=UTF-8');



					wp_mail($eMail, $subject, $body, $headers);



					$insert_data = "The account was reject successfully for Email ID " . $eMail . ".";

					SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



					return rest_ensure_response(['status' => 'success', 'message' => 'New Account Review Rejected successfully']);



				}



			} catch (Exception $e) {



				$insert_data = "The account review request was not successful. Something went wrong.";

				SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}



		function sensfrx_post_reg_bulk_review(WP_REST_Request $request) {



			try {



				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



		



				if (empty($options['sensfrx_property_id']) || empty($options['sensfrx_property_secret'])) {



					return new WP_Error('missing_keys', 'Missing property ID or secret key', ['status' => 400]);



				}



		



				$obj = new SensFRX\SensFRX([



					'property_id' => sanitize_text_field($options['sensfrx_property_id']),



					'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



				]);



		



				$transActionReg = $request->get_param('transActionReg') ? sanitize_text_field($request->get_param('transActionReg')) : null;



				$transOrder_idsReg = $request->get_param('transOrder_idsReg') ? $request->get_param('transOrder_idsReg') : null;



		



				if (empty($transActionReg) || empty($transOrder_idsReg)) {



					return new WP_Error('invalid_request', 'Missing new accounts action or order IDs', ['status' => 400]);



				}



		



				if (!is_array($transOrder_idsReg)) {



					return new WP_Error('invalid_format', 'New Account IDs must be an array.', ['status' => 400]);



				}



		



				$transOrder_idsReg = array_map('sanitize_text_field', $transOrder_idsReg);



				$transReviewBulkOrderIds = $transOrder_idsReg;



				$trans_review_transactions = [];



				$account_review_user_email = [];



		



				$getTransReview = $obj->getAccount_Review();



				$getTransReview = isset($getTransReview['data']) ? (array) $getTransReview['data'] : [];



		



				if (!empty($getTransReview)) {



					foreach ($getTransReview as $order) {



						foreach ($transReviewBulkOrderIds as $bulk_action) {



							if ($order->registration_id == $bulk_action) {



								$trans_review_transactions[] = [



									"reg_id" => $order->registration_id,



									"action" => $transActionReg



								];



								$account_review_user_email[] = [



									"review_email" => $order->email,



									"review_username" => $order->username



								];



							}



						}



					}



				}



		



				if (empty($trans_review_transactions)) {



					return new WP_Error('no_matching_orders', 'No matching transactions found for review.', ['status' => 404]);



				}



		



				$postTransReview = $obj->postAccount_Review(['data' => $trans_review_transactions]);



				$rom = null;



				if (isset($postTransReview['status']) && $postTransReview['status'] === 'success') {



					foreach ($account_review_user_email as $account) {



						$review_email = $account["review_email"];



						$review_username = $account["review_username"];



						$rom = $review_email;



						if ($transActionReg === 'approve') {



							$user_id = wp_create_user($review_username, wp_generate_password(), $review_email);



							if (!is_wp_error($user_id)) {



								wp_send_new_user_notifications($user_id, 'user');



								$insert_data = "The account was approve successfully for Email ID " . $review_email . ".";

								SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



							} else {



								$error_message = $user_id->get_error_message();



								$subject = "Account Creation Error";



								$body = "Dear $review_username,\n\nWe encountered an issue while creating your account:\n\n$error_message\n\nPlease try again or contact support.";



								$headers = [



									'Content-Type: text/plain; charset=UTF-8',



									'From: Your Site Name <no-reply@yoursite.com>'



								];



								wp_mail($review_email, $subject, $body, $headers);



								$insert_data = "The account was not approve successfully for Email ID " . $review_email . ". Encountered an issue while creating the account";

								SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



							}



						} elseif ($transActionReg === 'reject') {



							$subject = "Account Rejected";



							$body = "Dear $review_username,\n\nWe regret to inform you that your account has been rejected by the admin. Please contact support for further assistance.\n\nThank you.";



							$headers = [



								'Content-Type: text/plain; charset=UTF-8',



								'From: Your Site Name <no-reply@yoursite.com>'



							];



							$sent = wp_mail($review_email, $subject, $body, $headers);



							$insert_data = "The account was reject successfully for Email ID " . $review_email . ".";

							SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



							if (!$sent) {



								error_log("Email failed to send to: " . $review_email);



							} 



						}



					}



					return rest_ensure_response(['status' => 'success', 'message' => 'Transactions reviewed successfully.']);



				} else {



					$insert_data = "The account review request was not successful. Failed to review account's.";

					SensFRX_DB_Helper::insert_activity_log('Account Review', $insert_data);



					return new WP_Error('review_failed', 'Failed to review transactions.', ['status' => 500]);



				}



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error processing request: ' . $e->getMessage(), ['status' => 500]);



			}



		}



		function get_export_info() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => sanitize_text_field($options['sensfrx_property_id']),



				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



			]);



			$res_export = $obj->getimportinfo(); 



		}



		function get_review_count_info() {



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([



				'property_id' => sanitize_text_field($options['sensfrx_property_id']),



				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])



			]);



			$res_export = $obj->getreviewcountinfo();



			if (!empty($res_export) && isset($res_export['reviewCount'])) {



				return rest_ensure_response([



					'status' => 'success',



					'reviewCount' => $res_export['reviewCount'],



				]);



			} else {



				return rest_ensure_response([



					'reviewCount' => 0, // Default value if no data is found



					'message' => 'No review count available',



				]);



			}



		}



		// REMOVED: Duplicate get_license_info() - using get_sensfrx_license_info() instead



		function get_sensfrx_activity_log() {



			global $wpdb;



			$results = SensFRX_DB_Helper::safe_select(

				'sensfrx_real_activity',

				'*',

				'',

				array(),

				'id DESC',

				ARRAY_A

			);



			if (!empty($results)) {



				// Convert UTC timestamps to WordPress timezone

				$timezone = wp_timezone();



				foreach ($results as &$row) {

					// Ensure created_at exists and is not empty

					if (empty($row['created_at'])) {

						error_log('SensFRX: Activity log entry missing created_at timestamp - ID: ' . ($row['id'] ?? 'unknown'));

						$row['created_at'] = current_time('mysql'); // Fallback to current time

					}

					

					try {

						// Assume created_at is stored in UTC (GMT)

						$datetime = new DateTime($row['created_at'], new DateTimeZone('UTC'));

						

						// Convert to WordPress timezone

						$datetime->setTimezone($timezone);

						

						// Keep both UTC and local time for reference

						$row['created_at_utc'] = $row['created_at']; // Original UTC time

						$row['created_at'] = $datetime->format('Y-m-d H:i:s'); // Local time

						$row['created_at_timestamp'] = $datetime->getTimestamp(); // Unix timestamp for JS

					} catch (Exception $e) {

						error_log('SensFRX: Failed to convert timestamp for activity log ID ' . ($row['id'] ?? 'unknown') . ': ' . $e->getMessage());

						// Keep original timestamp if conversion fails

					}

				}



				return new WP_REST_Response([



					'status' => 'success',



					'data' => $results,



				], 200);



			} else {



				return new WP_REST_Response([



					'status' => 'error',



					'message' => 'No activity logs found',



				], 404);



			}



		}	



		function get_sensfrx_email_modify(WP_REST_Request $request) {



			global $wpdb;



			$type = $request->get_param('type') ? sanitize_text_field($request->get_param('type')) : '';



			if (empty($type)) {



				return rest_ensure_response([



					'status' => 'error',



					'message' => 'Missing or invalid email type.'



				]);



			}



			// Set template name based on type



			$template_name_map = [



				'medium' => 'SensFRX client login login ogin 123',



				'challenge' => 'SensFRX - Suspicious Behavior tyy 123',



				'deny' => 'SensFRX reset password uuu',



				'trans_medium_before' => 'Trans_medium_severity_Mail_Send 123',



				'trans_medium_after' => 'Trans_medium_severity_Mail_Send_succeeded 123',



				'trans_challenge_before' => 'Trans_challenge_severity_Mail_Send 123',



				'trans_challenge_after' => 'Trans_challenge_severity_Mail_Send_succeeded 123',



				'trans_deny_before' => 'Trans_deny_severity_Mail_Send',



				'trans_deny_after' => 'Trans_deny_severity_Mail_Send_succeeded',



				'reg_medium' => 'Registration Medium',



				'reg_challenge' => 'Registration Challenge',



				'reg_deny' => 'Registration Deny',



				'webhook_deny' => 'Webhook Deny',



			];



			$template_key = $template_name_map[$type] ?? '';



			if (!$template_key) {



				return rest_ensure_response([



					'status' => 'error',



					'message' => 'Invalid email type value.'



				]);



			}



			// Fetch from DB



			$table_name = esc_sql( $wpdb->prefix . 'sensfrx_email_templates' );



			$template = $wpdb->get_row(



				$wpdb->prepare(

					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %s placeholder.

					"SELECT * FROM {$table_name} WHERE name1 = %s",



					$template_key



				)



			);



			if ($template) {



				$subject = $template->subject1;



				$message = str_replace('{$signature}', '{$default_brand_name}', $template->message1);



		



				return rest_ensure_response([



					'status' => 'success',



					'subject' => $subject,



					'message' => $message



				]);



			} else {



				return rest_ensure_response([



					'status' => 'error',



					'message' => 'No template found for the provided type.'



				]);



			}



		}



		function sensfrx_post_email_modify(WP_REST_Request $request) {



			try {



				global $wpdb;



				$table_name = esc_sql( $wpdb->prefix . 'sensfrx_email_templates' );



				$email_type     = sanitize_text_field($request->get_param('type'));



				// $subject        = sanitize_text_field($request->get_param('subject'));



				$message        = wp_kses_post($request->get_param('message')); // safer for HTML



				$is_test_email  = intval($request->get_param('is_test_email'));



				if (empty($email_type) || empty($message)) {



					return new WP_Error('invalid_data', 'Type, subject, and message are required.', ['status' => 400]);



				}



				$name_map = [



					'medium' => 'SensFRX client login login ogin 123',



					'challenge' => 'SensFRX - Suspicious Behavior tyy 123',



					'deny' => 'SensFRX reset password uuu',



					'trans_medium_before' => 'Trans_medium_severity_Mail_Send 123',



					'trans_medium_after' => 'Trans_medium_severity_Mail_Send_succeeded 123',



					'trans_challenge_before' => 'Trans_challenge_severity_Mail_Send 123',



					'trans_challenge_after' => 'Trans_challenge_severity_Mail_Send_succeeded 123',



					'trans_deny_before' => 'Trans_deny_severity_Mail_Send',



					'trans_deny_after' => 'Trans_deny_severity_Mail_Send_succeeded',



					'reg_medium' => 'Registration Medium',



					'reg_challenge' => 'Registration Challenge',



					'reg_deny' => 'Registration Deny',



					'webhook_deny' => 'Webhook Deny',



				];



				if (!array_key_exists($email_type, $name_map)) {



					return new WP_Error('invalid_type', 'Unknown email type.', ['status' => 400]);



				}



				$db_name = $name_map[$email_type];



				$updated = $wpdb->update(



					$table_name,



					[



						// 'subject1' => $subject,



						'message1' => $message



					],



					[



						'name1' => $db_name



					],



					['%s', '%s'],



					['%s']



				);



				if ($updated === false) {



					return new WP_Error('db_error', 'Failed to update email template.', ['status' => 500]);



				}



				if ($is_test_email) {



					$template = $wpdb->get_row(



						$wpdb->prepare(

							// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is sanitized with esc_sql(). WHERE value is properly prepared with %s placeholder.

							"SELECT * FROM {$table_name} WHERE name1 = %s",

							$db_name

						)



					);



					if ($template) {



						$admin_emails = array_map(function($user) {



							return $user->user_email;



						}, get_users(['role' => 'administrator']));



						$to = implode(',', $admin_emails);



						$headers = ['Content-Type: text/html; charset=UTF-8'];



						wp_mail($to, $template->subject1, $template->message1, $headers);



					}



				}



				return rest_ensure_response([



					'status' => 'success',



					'message' => 'Email Template updated successfully.'



				]);



			} catch (Exception $e) {



				return new WP_Error('server_error', 'Error updating settings: ' . $e->getMessage(), ['status' => 500]);



			}



		}

		/**

		 * Get fraud cases from SensFRX Trans Review API

		 * Endpoint: GET /fraud-cases-list?filter=all|blocked|allowed|pending

		 */

		function get_fraud_cases(WP_REST_Request $request) {



			$selectedPeriod = sanitize_text_field($request->get_param('date_range'));



			// Default: last 7 days (to match your HTML default)

			$today = date('d-m-Y');

			$DateFilter = [];



			switch ($selectedPeriod) {



				case 'today':

					// Only today's data

					$DateFilter = [

						'from_date' => $today,

						'to_date'   => $today

					];

					break;



				case 'yesterday':

					// Only yesterday's data

					$yesterday = date('d-m-Y', strtotime('-1 day'));

					$DateFilter = [

						'from_date' => $yesterday,

						'to_date'   => $yesterday

					];

					break;



				case '7days':

					// Today & Last 7 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-6 days')),

						'to_date'   => $today

					];

					break;



				case '15days':

					// Today & Last 15 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-15 days')),

						'to_date'   => $today

					];

					break;



				case '30days':

					// Today & Last 30 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-30 days')),

						'to_date'   => $today

					];

					break;



				case '60days':

					// Today & Last 60 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-60 days')),

						'to_date'   => $today

					];

					break;



				case '90days':

					// Today & Last 90 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-90 days')),

						'to_date'   => $today

					];

					break;



				case '120days':

					// Today & Last 120 days

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-120 days')),

						'to_date'   => $today

					];

					break;



				default:

					// Fallback (optional)

					$DateFilter = [

						'from_date' => date('d-m-Y', strtotime('-7 days')),

						'to_date'   => $today

					];

					break;

			}





			$filter = $request->get_param('filter') ? sanitize_text_field($request->get_param('filter')) : 'all';

			

			// Get risk levels and event types filters

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

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

			

			// Sanitize arrays

			$risk_levels = is_array($risk_levels) ? array_map('sanitize_text_field', $risk_levels) : [];

			$event_types = is_array($event_types) ? array_map('sanitize_text_field', $event_types) : [];



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => sanitize_text_field($options['sensfrx_property_id']),

				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

			]);



			// $transReviewData = $obj->getTransReview();

			$transReviewData = $obj->getAllFraudTrans($DateFilter);

			$regReviewData = $obj->getAllFraudReg($DateFilter);

			$atoReviewData = $obj->getAllFraudATO($DateFilter);



			// Convert stdClass to array recursively

			if (is_object($transReviewData)) {

				$transReviewData = json_decode(json_encode($transReviewData), true);

			}

			if (is_object($regReviewData)) {

				$regReviewData = json_decode(json_encode($regReviewData), true);

			}

			if (is_object($atoReviewData)) {

				$atoReviewData = json_decode(json_encode($atoReviewData), true);

			}



			if (!empty($transReviewData) && isset($transReviewData['data']['trans_list'])) {



				$transList = !empty($transReviewData['data']['trans_list']) ? $transReviewData['data']['trans_list'] : [];

				$regList   = !empty($regReviewData['data']['reg_list']) ? $regReviewData['data']['reg_list'] : [];

				$atoList   = !empty($atoReviewData['data']['ato_list']) ? $atoReviewData['data']['ato_list'] : [];



				$transList = array_map(fn($c) => (array)$c, $transList);

				$regList   = array_map(fn($c) => (array)$c, $regList);

				$atoList   = array_map(fn($c) => (array)$c, $atoList);



				$fraudCases = [];

				function normalize_case($caseArray, $type) {



					 $rawTimestamp = $caseArray['event_time'] ?? null;



					if ($rawTimestamp) {

						// Convert "2025-12-03T06:47:27.283000" → "2025-12-03 06:47:27"

						$dt = date_create($rawTimestamp);

						$formattedTimestamp = $dt ? date_format($dt, 'Y-m-d H:i:s') : $rawTimestamp;

					} else {

						$formattedTimestamp = date('Y-m-d H:i:s');

					}

					return [

						'id'         => $caseArray['transaction_id'] 

										?? $caseArray['order_id'] 

										?? $caseArray['registration_id'] 

										?? $caseArray['uid'] 

										?? '',



						'timestamp'  => $formattedTimestamp,



						'event_type' => $type,



						'order_id'   => $caseArray['order_id'] ?? $caseArray['transaction_id'] ?? 'N/A',



						'username'   => $caseArray['username'] ?? $caseArray['user_name'] ?? 'N/A',



						'amount'     => isset($caseArray['amount']) 

										? (float)$caseArray['amount'] 

										: (isset($caseArray['transaction_amount']) 

											? (float)$caseArray['transaction_amount'] 

											: 0),



						'order_total' => isset($caseArray['order_total']) 

										? (float)$caseArray['order_total'] 

										: (isset($caseArray['amount']) 

											? (float)$caseArray['amount'] 

											: 0),



						'user'       => $caseArray['email'] 

										?? $caseArray['user_email'] 

										?? $caseArray['ue'] 

										?? 'N/A',



						'email'      => $caseArray['email'] 

										?? $caseArray['user_email'] 

										?? $caseArray['ue'] 

										?? 'N/A',



						'ip_address' => $caseArray['ip_address'] 

										?? $caseArray['ip'] 

										?? 'N/A',



						'risk_score' => isset($caseArray['risk_score'])

										? (int)$caseArray['risk_score']

										: 0,



						'status'     => $caseArray['status'] ?? 'challenge',



						'location'   => $caseArray['location'] 

										?? $caseArray['city'] 

										?? $caseArray['country'] 

										?? 'Unknown',



						'device'     => $caseArray['device'] 

										?? $caseArray['device_type'] 

										?? $caseArray['browser'] 

										?? 'Unknown',



						'indicators' => $caseArray['indicators'] ?? [],



						'notes'      => $caseArray['notes'] ?? '',



						'link'       => $caseArray['link'] ?? '#',

					];

				}

				$maxCount = max(count($transList), count($regList), count($atoList));



				// Helper function to check if case matches filters

				$matchesFilters = function($case) use ($risk_levels, $event_types) {

					// Check risk level filter

					if (!empty($risk_levels)) {

						$riskScore = $case['risk_score'];

						$matchesRisk = false;

						

						foreach ($risk_levels as $level) {

							if ($level === 'high' && $riskScore >= 60) {

								$matchesRisk = true;

								break;

							} elseif ($level === 'medium' && $riskScore >= 30 && $riskScore < 60) {

								$matchesRisk = true;

								break;

							} elseif ($level === 'low' && $riskScore < 30) {

								$matchesRisk = true;

								break;

							}

						}

						

						if (!$matchesRisk) {

							return false;

						}

					}

					

					// Check event type filter

					if (!empty($event_types)) {

						$typeMap = [

							'payment' => 'Transaction',

							'login' => 'Account Security',

							'registration' => 'Registration'

						];

						

						$matchesType = false;

						foreach ($event_types as $type) {

							if (isset($typeMap[$type]) && $typeMap[$type] === $case['event_type']) {

								$matchesType = true;

								break;

							}

						}

						

						if (!$matchesType) {

							return false;

						}

					}

					

					return true;

				};



				for ($i = 0; $i < $maxCount; $i++) {



					// Transaction

					if (!empty($transList[$i])) {

						$case = normalize_case($transList[$i], 'Transaction');

						if (($filter === 'all' || $case['status'] === $filter) && $matchesFilters($case)) {

							$fraudCases[] = $case;

						}

					}



					// Registration

					if (!empty($regList[$i])) {

						$case = normalize_case($regList[$i], 'Registration');

						if (($filter === 'all' || $case['status'] === $filter) && $matchesFilters($case)) {

							$fraudCases[] = $case;

						}

					}



					// ATO

					if (!empty($atoList[$i])) {

						$case = normalize_case($atoList[$i], 'Account Security');

						if (($filter === 'all' || $case['status'] === $filter) && $matchesFilters($case)) {

							$fraudCases[] = $case;

						}

					}

				}



				return new WP_REST_Response([

					'status' => 'success',

					'data'   => $fraudCases

				], 200);



			} else {



				return new WP_REST_Response([

					'status' => 'Error',

					'message' => 'API Error: No fraud data returned from API'

				], 200);



			}





		}



		function sensfrx_get_login_link() {

			try {

				$options = get_option('sensfrx_options', SensFRX::default_options());



				require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



				$obj = new SensFRX\SensFRX([

						'property_id'     => sanitize_text_field($options['sensfrx_property_id']),

						'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

				]);



				$response = $obj->redirectBefore();



				if (isset($response['status']) && $response['status'] === 'success' &&!empty($response['login_link'])) {

					return rest_ensure_response([

						'status'     => 'success',

						'login_link' => $response['login_link']

					]);

				}



				return rest_ensure_response([

					'status'  => 'error',

					'message' => $response['message'] ?? 'Unable to generate login link',

					'debug'   => $response

				]);



			} catch (\Throwable $e) {



				return rest_ensure_response([

					'status'  => 'error',

					'message' => $e->getMessage()

				]);

			}

		}



		/**

		 * Get review queue with filtering

		 * Endpoint: GET /review-queue

		 */

		function get_sensfrx_review_queue($request) {

			$filter = $request->get_param('filter') ? sanitize_text_field($request->get_param('filter')) : 'challenge';

			$type = $request->get_param('type') ? sanitize_text_field($request->get_param('type')) : 'trans';

			$from_date = $request->get_param('from_date') ? sanitize_text_field($request->get_param('from_date')) : null;

			$to_date = $request->get_param('to_date') ? sanitize_text_field($request->get_param('to_date')) : null;



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => sanitize_text_field($options['sensfrx_property_id']),

				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

			]);



			// Get review queue data from API - calls GET /trans-review or /reg-review with optional date filtering

			$review_data = $obj->getreviewqueueinfo($type, $from_date, $to_date);

			

			// Initialize response arrays

			$review_items = [];

			$stats = [

				'pending' => 0,

				'approved' => 0,

				'blocked' => 0

			];



			// Fetch today's approved/blocked stats from new endpoint

			try {

				$today_date = date('Y-m-d'); // Get today's date in YYYY-MM-DD format

				

				// Can also use date range: $obj->getreviewstats(null, $type, '2025-12-01', '2025-12-11')

				$stats_data = $obj->getreviewstats($today_date, $type);

				

				// Convert stdClass to array recursively

				$stats_data = json_decode(json_encode($stats_data), true);

				

				if (!empty($stats_data) && isset($stats_data['status']) && $stats_data['status'] === 'success' && isset($stats_data['data'])) {

					$stats_response = $stats_data['data'];

					

					// Get counts based on type - handle transactions

					if (($type === 'trans' || $type === 'both') && isset($stats_response['transactions'])) {

						$stats['approved'] = isset($stats_response['transactions']['approved']) ? intval($stats_response['transactions']['approved']) : 0;

						$stats['blocked'] = isset($stats_response['transactions']['denied']) ? intval($stats_response['transactions']['denied']) : 0;

					}

					

					// Get counts based on type - handle registrations

					if (($type === 'reg' || $type === 'both') && isset($stats_response['registrations'])) {

						$stats['approved'] = isset($stats_response['registrations']['approved']) ? intval($stats_response['registrations']['approved']) : 0;

						$stats['blocked'] = isset($stats_response['registrations']['denied']) ? intval($stats_response['registrations']['denied']) : 0;

					}

				}

			} catch (Exception $e) {

				// Log error but continue with zero stats

				error_log('SensFRX: Failed to fetch review stats - ' . $e->getMessage());

			} catch (Throwable $e) {

				// Catch any other errors (including fatal errors like stdClass issues)

				error_log('SensFRX: Critical error fetching review stats - ' . $e->getMessage());

			}



			if (!empty($review_data) && isset($review_data['data'])) {

				$reviewData = is_array($review_data['data']) ? $review_data['data'] : (array) $review_data['data'];



				foreach ($reviewData as $case) {

					$caseArray = is_object($case) ? (array) $case : $case;



					$item_status = isset($caseArray['status']) ? strtolower($caseArray['status']) : 'challenge';



					// Count pending statistics from the queue data

					if ($item_status === 'challenge') {

						$stats['pending']++;

					}

					// Note: approved/blocked counts come from the new stats endpoint above



					// Filter items based on request

					if ($filter === 'all' || $item_status === $filter) {

						$review_items[] = [

							'id' => isset($caseArray['transaction_id']) ? $caseArray['transaction_id'] : (isset($caseArray['order_id']) ? $caseArray['order_id'] : (isset($caseArray['registration_id']) ? $caseArray['registration_id'] : '')),

							'event_type' => isset($caseArray['event_type']) ? $caseArray['event_type'] : ($type === 'reg' ? 'Registration' : 'Transaction'),

							'risk_score' => isset($caseArray['transaction_score']) ? intval($caseArray['transaction_score']) : 60,

							'order_id' => isset($caseArray['order_id']) ? intval($caseArray['order_id']) : 0,

							'username' => isset($caseArray['username']) ? $caseArray['username'] : (isset($caseArray['user_id']) ? $caseArray['user_id'] : 'N/A'),

							'amount' => isset($caseArray['amount']) ? floatval($caseArray['amount']) : 0,

							'timestamp' => isset($caseArray['event_time']) ? date('Y-m-d H:i:s', strtotime($caseArray['event_time'])) : date('Y-m-d H:i:s'),

							'ip_address' => isset($caseArray['ip']) ? $caseArray['ip'] : 'N/A',

							'status' => ucfirst($item_status),

							'user' => isset($caseArray['email']) ? $caseArray['email'] : 'N/A',

							'email' => isset($caseArray['email']) ? $caseArray['email'] : 'N/A',

							// Build location from granular fields (city, state, country) or use fallback

							'location' => isset($caseArray['city']) && isset($caseArray['country']) 

								? $caseArray['city'] . ', ' . $caseArray['country']

								: (isset($caseArray['country']) ? $caseArray['country'] : (isset($caseArray['location']) ? $caseArray['location'] : 'Unknown')),

							// Build device string from browser, OS, and device_type or use fallback

							'device' => isset($caseArray['browser']) && isset($caseArray['os']) 

								? $caseArray['browser'] . ' on ' . $caseArray['os'] . ' (' . (isset($caseArray['device_type']) ? $caseArray['device_type'] : 'Unknown') . ')'

								: (isset($caseArray['device']) ? $caseArray['device'] : (isset($caseArray['user_agent']) ? $caseArray['user_agent'] : 'Unknown')),

							'browser' => isset($caseArray['browser']) ? $caseArray['browser'] : 'Unknown',

							'os' => isset($caseArray['os']) ? $caseArray['os'] : 'Unknown',

							'device_type' => isset($caseArray['device_type']) ? $caseArray['device_type'] : 'Unknown',

							'country' => isset($caseArray['country']) ? $caseArray['country'] : 'Unknown',

							'city' => isset($caseArray['city']) ? $caseArray['city'] : 'Unknown',

							'state' => isset($caseArray['state']) ? $caseArray['state'] : 'Unknown',

							'indicators' => isset($caseArray['fraud_indicators']) ? $caseArray['fraud_indicators'] : (isset($caseArray['indicators']) ? $caseArray['indicators'] : []),

							'notes' => isset($caseArray['notes']) ? $caseArray['notes'] : ''

						];

					}

				}

			}



			return rest_ensure_response([

				'status' => 'success',

				'data' => $review_items,

				'stats' => $stats

			]);

		}



		/**

		 * Process review action (approve/block)

		 * Endpoint: POST /review-action

		 */

		function post_sensfrx_review_action($request) {

			$json_params = $request->get_json_params();



			$item_id = isset($json_params['item_id']) ? sanitize_text_field($json_params['item_id']) : '';

			$action = isset($json_params['action']) ? sanitize_text_field($json_params['action']) : '';

			$type = isset($json_params['type']) ? sanitize_text_field($json_params['type']) : 'trans';



			if (empty($item_id) || empty($action)) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Missing item_id or action'

				]);

			}



			if (!in_array($action, ['approve', 'block', 'approved', 'rejected'])) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Invalid action. Must be approve or block.'

				]);

			}



			// Convert action to API format

			$api_action = ($action === 'approve') ? 'approve' : (($action === 'block') ? 'reject' : $action);



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => sanitize_text_field($options['sensfrx_property_id']),

				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

			]);



			// Process the review action via API - calls POST /trans-review or /reg-review

			$result = $obj->processreviewaction($item_id, $api_action, $type);



			if (!empty($result) && ((isset($result['status']) && $result['status'] === 'success') || (isset($result['success']) && $result['success']))) {

				return rest_ensure_response([

					'status' => 'success',

					'message' => ucfirst($action) . ' action completed successfully'

				]);

			} else {

				return rest_ensure_response([

					'status' => 'error',

					'message' => isset($result['message']) ? $result['message'] : 'Failed to process action'

				]);

			}

		}



		/**

		 * Add note to review item

		 * Endpoint: POST /review-note

		 */

		function post_sensfrx_review_note($request) {

			$json_params = $request->get_json_params();



			$item_id = isset($json_params['item_id']) ? sanitize_text_field($json_params['item_id']) : '';

			$note = isset($json_params['note']) ? sanitize_textarea_field($json_params['note']) : '';

			$type = isset($json_params['type']) ? sanitize_text_field($json_params['type']) : 'trans';



			if (empty($item_id) || empty($note)) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Missing item_id or note'

				]);

			}



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => sanitize_text_field($options['sensfrx_property_id']),

				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

			]);



			// Add note via API - calls POST /trans-review or /reg-review with note

			$result = $obj->addreviewnote($item_id, $note, $type);



			if (!empty($result) && ((isset($result['status']) && $result['status'] === 'success') || (isset($result['success']) && $result['success']))) {

				return rest_ensure_response([

					'status' => 'success',

					'message' => 'Note added successfully'

				]);

			} else {

				return rest_ensure_response([

					'status' => 'error',

					'message' => isset($result['message']) ? $result['message'] : 'Failed to add note'

				]);

			}

		}



		/**

		 * Get review count for badge

		 * Endpoint: GET /review-count

		 */

		function get_sensfrx_review_count($request) {

			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => sanitize_text_field($options['sensfrx_property_id']),

				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

			]);



			$res_count = $obj->getreviewcountinfo();



			if (!empty($res_count) && isset($res_count['reviewCount'])) {

				return rest_ensure_response([

					'status' => 'success',

					'data' => [

						'count' => intval($res_count['reviewCount'])

					]

				]);

			} else {

				return rest_ensure_response([

					'status' => 'success',

					'data' => [

						'count' => 0

					]

				]);

			}

		}



		/**

		 * Get protection stats from SensFRX API

		 * Endpoint: GET /protection-stats?from_date=DD-MM-YYYY&to_date=DD-MM-YYYY

		 */

		function get_protection_stats(WP_REST_Request $request) {



			$from_date = sanitize_text_field($request->get_param('from_date'));

			$to_date = sanitize_text_field($request->get_param('to_date'));



			if (empty($from_date) || empty($to_date)) {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Missing required parameters: from_date and to_date'

				]);

			}



			$DateFilter = [

				'from_date' => $from_date,

				'to_date' => $to_date

			];



			$options = get_option('sensfrx_options', SensFRX::default_options());



			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');



			$obj = new SensFRX\SensFRX([

				'property_id' => sanitize_text_field($options['sensfrx_property_id']),

				'property_secret' => sanitize_text_field($options['sensfrx_property_secret'])

			]);



			$protectionStatsData = $obj->getProtectionStats($DateFilter);



			// Convert stdClass to array if needed

			if (is_object($protectionStatsData)) {

				$protectionStatsData = json_decode(json_encode($protectionStatsData), true);

			}



			if (!empty($protectionStatsData) && isset($protectionStatsData['status'])) {

				return rest_ensure_response($protectionStatsData);

			} else {

				return rest_ensure_response([

					'status' => 'error',

					'message' => 'Failed to retrieve protection stats'

				]);

			}

		}

	}



	/**

	 * Update checklist item state

	 */

	public function update_checklist_item(WP_REST_Request $request) {

		$params = json_decode($request->get_body(), true);

		$item = isset($params['item']) ? sanitize_text_field($params['item']) : '';

		$checked = isset($params['checked']) ? (bool)$params['checked'] : false;



		if (empty($item)) {

			return new WP_REST_Response([

				'status' => 'error',

				'message' => 'Invalid item name'

			], 400);

		}



		// Get current checklist state

		$checklist_items = get_option('sensfrx_checklist_items', [

			'connect_api' => false,

			'review_protections' => false,

			'configure_rules' => false,

			'test_order' => false,

			'review_fraud_case' => false

		]);



		// Update the specific item

		if (array_key_exists($item, $checklist_items)) {

			$checklist_items[$item] = $checked;

			update_option('sensfrx_checklist_items', $checklist_items);



			// Calculate completion percentage

			$completed_count = count(array_filter($checklist_items));

			$total_count = count($checklist_items);

			$completion_percentage = $total_count > 0 ? round(($completed_count / $total_count) * 100) : 0;



			return new WP_REST_Response([

				'status' => 'success',

				'completion_percentage' => $completion_percentage,

				'checklist_items' => $checklist_items

			], 200);

		} else {

			return new WP_REST_Response([

				'status' => 'error',

				'message' => 'Item not found'

			], 404);

		}

	}



	/**

	 * Dismiss getting started checklist

	 */

	public function dismiss_getting_started(WP_REST_Request $request) {

		update_option('sensfrx_getting_started_dismissed', true);



		return new WP_REST_Response([

			'status' => 'success',

			'message' => 'Getting started guide dismissed'

		], 200);

	}



	/**

	 * Fetch Admin Email Alert Settings FROM SensFRX API (Bi-Directional Sync - Cloud TO WordPress)

	 * 

	 * Fetches the latest admin email alert settings from Cassandra email_alerts table

	 * and updates WordPress local options to match.

	 * 

	 * This enables bi-directional sync: changes made in customer dashboard are reflected in WordPress plugin.

	 * 

	 * @since 3.1.0

	 * @return array Success status, message, and synced data

	 */

	public static function fetch_admin_alerts_from_api() {

		$sensfrx_options = get_option('sensfrx_options', array());

		

		// Check if we have valid credentials

		if (empty($sensfrx_options['sensfrx_property_id']) || empty($sensfrx_options['sensfrx_property_secret'])) {

			error_log('SensFRX: fetch_admin_alerts_from_api - Missing credentials');

			return array(

				'success' => false,

				'message' => 'Missing property credentials'

			);

		}

		

		try {

			// Initialize SDK

			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');

			

			// Check if SDK class exists

			if (!class_exists('SensFRX\SensFRX')) {

				error_log('SensFRX: SDK class not found');

				return array(

					'success' => false,

					'message' => 'SDK class not found'

				);

			}

			

			// Wrap SDK initialization in try-catch to handle fatal errors

			try {

				$obj = new SensFRX\SensFRX([

					'property_id' => $sensfrx_options['sensfrx_property_id'],

					'property_secret' => $sensfrx_options['sensfrx_property_secret']

				]);

			} catch (Error $sdk_error) {

				// Catch PHP 7+ fatal errors (like missing classes)

				error_log('SensFRX: SDK initialization error - ' . $sdk_error->getMessage());

				return array(

					'success' => false,

					'message' => 'SDK initialization failed: ' . $sdk_error->getMessage()

				);

			}

			

			// Fetch settings from API

			// $result = $obj->getalertsinfo();

			$result = $obj->getAdminEmailAlerts();

			

			// Convert stdClass to array (SDK may return objects)

			$result = json_decode(json_encode($result), true);

			

			if (isset($result['status']) && $result['status'] === 'success' && isset($result['data'])) {

				$api_settings = $result['data'];

				

				// Get current WordPress options

				$options = get_option('sensfrx_policy_options', SensFRX::default_policy_options());

				

				// Map API settings to WordPress options

				if (!empty($api_settings['email'])) {

					$options['sensfrx_admin_alert_email'] = $api_settings['email'];

				}



				error_log('API ALERT DATA: ' . print_r($api_settings, true));

				

				// // Login (ATO) alerts

				// $options['sensfrx_admin_login_alerts'] = !empty($api_settings['ato_status']) ? '1' : '0';

				// $options['sensfrx_admin_challenge_login_email'] = !empty($api_settings['ato_review']) ? '1' : '0';

				// $options['sensfrx_admin_deny_login_email'] = !empty($api_settings['ato_deny']) ? '1' : '0';

				

				// // Payment (Transaction) alerts

				// $options['sensfrx_admin_payment_alerts'] = !empty($api_settings['trans_status']) ? '1' : '0';

				// $options['sensfrx_admin_challenge_payment_email'] = !empty($api_settings['trans_review']) ? '1' : '0';

				// $options['sensfrx_admin_deny_payment_email'] = !empty($api_settings['trans_deny']) ? '1' : '0';

				

				// // Registration alerts

				// $options['sensfrx_admin_registration_alerts'] = !empty($api_settings['reg_status']) ? '1' : '0';

				// $options['sensfrx_admin_challenge_register_email'] = !empty($api_settings['reg_review']) ? '1' : '0';

				// $options['sensfrx_admin_deny_register_email'] = !empty($api_settings['reg_deny']) ? '1' : '0';



				// // Login (ATO) alerts

				// if (array_key_exists('ato_status', $api_settings)) {

				// 	$options['sensfrx_admin_login_alerts'] = !empty($api_settings['ato_status']) ? '1' : '0';

				// }



				// if (array_key_exists('ato_review', $api_settings)) {

				// 	$options['sensfrx_admin_challenge_login_email'] = !empty($api_settings['ato_review']) ? '1' : '0';

				// }



				// if (array_key_exists('ato_deny', $api_settings)) {

				// 	$options['sensfrx_admin_deny_login_email'] = !empty($api_settings['ato_deny']) ? '1' : '0';

				// }



				// // Payment (Transaction) alerts

				// if (array_key_exists('trans_status', $api_settings)) {

				// 	$options['sensfrx_admin_payment_alerts'] = !empty($api_settings['trans_status']) ? '1' : '0';

				// }



				// if (array_key_exists('trans_review', $api_settings)) {

				// 	$options['sensfrx_admin_challenge_payment_email'] = !empty($api_settings['trans_review']) ? '1' : '0';

				// }



				// if (array_key_exists('trans_deny', $api_settings)) {

				// 	$options['sensfrx_admin_deny_payment_email'] = !empty($api_settings['trans_deny']) ? '1' : '0';

				// }



				// // Registration alerts

				// if (array_key_exists('reg_status', $api_settings)) {

				// 	$options['sensfrx_admin_registration_alerts'] = !empty($api_settings['reg_status']) ? '1' : '0';

				// }



				// if (array_key_exists('reg_review', $api_settings)) {

				// 	$options['sensfrx_admin_challenge_register_email'] = !empty($api_settings['reg_review']) ? '1' : '0';

				// }



				// if (array_key_exists('reg_deny', $api_settings)) {

				// 	$options['sensfrx_admin_deny_register_email'] = !empty($api_settings['reg_deny']) ? '1' : '0';

				// }



				$options['sensfrx_admin_login_alerts'] =

						isset($api_settings['ato_status']) && (int)$api_settings['ato_status'] === 1 ? '1' : '0';



				$options['sensfrx_admin_challenge_login_email'] =

						isset($api_settings['ato_review']) && (int)$api_settings['ato_review'] === 1 ? '1' : '0';



				$options['sensfrx_admin_deny_login_email'] =

						isset($api_settings['ato_deny']) && (int)$api_settings['ato_deny'] === 1 ? '1' : '0';





				$options['sensfrx_admin_payment_alerts'] =

						isset($api_settings['trans_status']) && (int)$api_settings['trans_status'] === 1 ? '1' : '0';



				$options['sensfrx_admin_challenge_payment_email'] =

						isset($api_settings['trans_review']) && (int)$api_settings['trans_review'] === 1 ? '1' : '0';



				$options['sensfrx_admin_deny_payment_email'] =

						isset($api_settings['trans_deny']) && (int)$api_settings['trans_deny'] === 1 ? '1' : '0';





				$options['sensfrx_admin_registration_alerts'] =

						isset($api_settings['reg_status']) && (int)$api_settings['reg_status'] === 1 ? '1' : '0';



				$options['sensfrx_admin_challenge_register_email'] =

						isset($api_settings['reg_review']) && (int)$api_settings['reg_review'] === 1 ? '1' : '0';



				$options['sensfrx_admin_deny_register_email'] =

						isset($api_settings['reg_deny']) && (int)$api_settings['reg_deny'] === 1 ? '1' : '0';





				// Update WordPress options

				update_option('sensfrx_policy_options', $options);

				

				return array(

					'success' => true,

					'message' => 'Settings synced from SensFRX cloud',

					'data' => $api_settings

				);

			} else {

				$message = isset($result['message']) ? $result['message'] : 'No settings found or API error';

				

				// If no settings found, this is OK (first time setup)

				if (strpos($message, 'No email alert settings found') !== false) {

					error_log('SensFRX: No email alerts in cloud yet - this is OK for first-time setup');

					return array(

						'success' => true,

						'message' => 'No cloud settings found - using local settings',

						'first_time' => true

					);

				}

				

				return array(

					'success' => false,

					'message' => $message

				);

			}

			

		} catch (Exception $e) {

			error_log('SensFRX: Exception fetching admin alerts - ' . $e->getMessage());

			return array(

				'success' => false,

				'message' => 'Exception: ' . $e->getMessage()

			);

		} catch (Error $e) {

			// Catch PHP 7+ fatal errors

			error_log('SensFRX: Fatal error fetching admin alerts - ' . $e->getMessage());

			return array(

				'success' => false,

				'message' => 'Fatal error: ' . $e->getMessage()

			);

		}

	}



	/**

	 * Sync Admin Alert Settings to SensFRX API/Cassandra (WordPress TO Cloud)

	 * 

	 * Maps WordPress admin alert settings to Cassandra email_alerts table.

	 * This enables admin notifications to be sent from the SensFRX cloud via Kafka/Mailgun.

	 * 

	 * Uses the generic plugin endpoint (email-alerts-plugin) that works for all platforms

	 * (WordPress, Shopify, WHMCS, WiseCP, etc.)

	 * 

	 * @since 3.0.1

	 * @return array Response from API with status and message

	 */

	public static function sync_admin_alerts_to_api() {

		$options = get_option('sensfrx_policy_options', SensFRX::default_policy_options());

		$sensfrx_options = get_option('sensfrx_options', array());

		

		// Check if we have valid credentials (stored in sensfrx_options, not sensfrx_policy_options)

		if (empty($sensfrx_options['sensfrx_property_id']) || empty($sensfrx_options['sensfrx_property_secret'])) {

			return array(

				'success' => false,

				'message' => 'Missing property credentials'

			);

		}



		// Get admin email - prioritize the admin alert email, then notification email, then WP admin email

		$admin_email = '';

		if (!empty($options['sensfrx_admin_alert_email'])) {

			$admin_email = $options['sensfrx_admin_alert_email'];

		} elseif (!empty($sensfrx_options['notification_email'])) {

			$admin_email = $sensfrx_options['notification_email'];

		} else {

			$admin_email = get_option('admin_email');

		}



		// Check individual master toggles for each alert type (matching customer dashboard structure)

		$login_master_enabled = isset($options['sensfrx_admin_login_alerts']) && $options['sensfrx_admin_login_alerts'] === '1';

		$payment_master_enabled = isset($options['sensfrx_admin_payment_alerts']) && $options['sensfrx_admin_payment_alerts'] === '1';

		$registration_master_enabled = isset($options['sensfrx_admin_registration_alerts']) && $options['sensfrx_admin_registration_alerts'] === '1';



		// Prepare data for email alerts endpoint

		$alert_settings = array(

			'email' => $admin_email,

			

			// Login (ATO - Account Takeover) alerts - individual master toggle

			'ato_status' => $login_master_enabled ? 1 : 0,

			'ato_review' => (isset($options['sensfrx_admin_challenge_login_email']) && $options['sensfrx_admin_challenge_login_email'] === '1') ? 1 : 0,

			'ato_deny' => (isset($options['sensfrx_admin_deny_login_email']) && $options['sensfrx_admin_deny_login_email'] === '1') ? 1 : 0,

			

			// Transaction (Payment) alerts - individual master toggle

			'trans_status' => $payment_master_enabled ? 1 : 0,

			'trans_review' => (isset($options['sensfrx_admin_challenge_payment_email']) && $options['sensfrx_admin_challenge_payment_email'] === '1') ? 1 : 0,

			'trans_deny' => (isset($options['sensfrx_admin_deny_payment_email']) && $options['sensfrx_admin_deny_payment_email'] === '1') ? 1 : 0,

			

			// Registration alerts - individual master toggle

			'reg_status' => $registration_master_enabled ? 1 : 0,

			'reg_review' => (isset($options['sensfrx_admin_challenge_register_email']) && $options['sensfrx_admin_challenge_register_email'] === '1') ? 1 : 0,

			'reg_deny' => (isset($options['sensfrx_admin_deny_register_email']) && $options['sensfrx_admin_deny_register_email'] === '1') ? 1 : 0,

		);



		try {

			// Initialize SDK (following same pattern as all other API calls in this file)

			require_once(SENSFRX_DIR . 'sensfrx-php-sdk/SensFRX/autoload.php');

			

			$obj = new SensFRX\SensFRX([

				'property_id' => $sensfrx_options['sensfrx_property_id'],

				'property_secret' => $sensfrx_options['sensfrx_property_secret']

			]);

			

			// Call SDK method

			$result = $obj->syncAdminEmailAlerts($alert_settings);



			// error_log('SYNC RESPONSE: ' . print_r($result, true));



			// Check result

			if ($result && isset($result['status']) && $result['status'] === 'success') {

				return array(

					'success' => true,

					'message' => 'Admin alerts synced to SensFRX cloud',

					'data' => $alert_settings

				);

			} else {

				error_log('SensFRX: API sync failed - ' . print_r($result, true));

				return array(

					'success' => false,

					'message' => isset($result['message']) ? $result['message'] : 'API sync failed',

					'response' => $result

				);

			}



		} catch (Exception $e) {

			error_log('SensFRX: Exception during admin alerts sync - ' . $e->getMessage());

			return array(

				'success' => false,

				'message' => 'Exception during sync: ' . $e->getMessage()

			);

		}

	}









}

