<?php

namespace Gigneo;

use Exception;
use WC_Cart;
use WC_Session_Handler;
use WC_Validation;
use WP_Query;
use WP_User;
use ZipArchive;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Class Ajax
 *
 * Plugin Ajax class for Gigneo.
 *
 * @since 0.0.1
 */
class Ajax {


	/**
	 * The single instance of the class.
	 *
	 * @var Ajax|null
	 * @since 0.0.1
	 */
	private static $instance = null;

	/**
	 * Register AJAX action hooks.
	 *
	 * @since 0.0.1
	 */
	public function __construct() {
		//Module active/inactive
		add_action( 'wp_ajax_gigneo_module_action', array( $this, 'module_action' ) );
		//Login
		add_action( 'wp_ajax_nopriv_gigneo_auth_login', array( $this, 'auth_login' ) );
		//Forgot Password
		add_action( 'wp_ajax_nopriv_gigneo_auth_forgot_password', array( $this, 'auth_forgot_password' ) );
		//Change Password
		add_action( 'wp_ajax_nopriv_gigneo_auth_change_password', array( $this, 'auth_change_password' ) );
		//Validate Username
		add_action( 'wp_ajax_nopriv_gigneo_username_validate', array( $this, 'auth_username_validate' ) );
		//Register
		add_action( 'wp_ajax_nopriv_gigneo_auth_register', array( $this, 'auth_register' ) );
		//Create Profile
		add_action( 'wp_ajax_gigneo_create_user_profile', array( $this, 'create_profile' ) );
		//Deposit Funds
		add_action( 'wp_ajax_gigneo_deposit_funds', array( $this, 'deposit_funds' ) );
		//Buy Credits
		add_action( 'wp_ajax_gigneo_buy_credits', array( $this, 'buy_credits' ) );
		//Image Crop
		add_action( 'wp_ajax_gigneo_crop_image', array( $this, 'crop_image' ) );
		//Save Profile Setting
		add_action( 'wp_ajax_gigneo_save_profile_setting', array( $this, 'save_profile_setting' ) );
		//Delete Profile Setting
		add_action( 'wp_ajax_gigneo_delete_profile_setting', array( $this, 'delete_profile_setting' ) );
		//Save Account Setting
		add_action( 'wp_ajax_gigneo_save_account_setting', array( $this, 'save_account_setting' ) );
		//Account Notification Setting
		add_action( 'wp_ajax_gigneo_account_notification', array( $this, 'account_notifications' ) );
		//Billing Address
		add_action( 'wp_ajax_gigneo_save_billing_address', array( $this, 'save_billing_address' ) );
		//Update Password
		add_action( 'wp_ajax_gigneo_update_password', array( $this, 'update_account_password' ) );
		//Dismiss Notice
		add_action( 'wp_ajax_gigneo_notice_dismiss', array( $this, 'notice_dismiss' ) );
		//Dismiss Notice
		add_action( 'wp_ajax_gigneo_delete_session', array( $this, 'delete_session' ) );
		//Save Item
		add_action( 'wp_ajax_gigneo_save_item', array( $this, 'gigneo_save_item' ) );
		//Service Archive Filter
		add_action( 'wp_ajax_gigneo_filter_services', array( $this, 'filter_services' ) );
		add_action( 'wp_ajax_nopriv_gigneo_filter_services', array( $this, 'filter_services' ) );
		//Freelancer Archive Filter
		add_action( 'wp_ajax_gigneo_filter_freelancers', array( $this, 'filter_freelancers' ) );
		add_action( 'wp_ajax_nopriv_gigneo_filter_freelancers', array( $this, 'filter_freelancers' ) );
		//Employer Archive Filter
		add_action( 'wp_ajax_gigneo_filter_employers', array( $this, 'filter_employers' ) );
		add_action( 'wp_ajax_nopriv_gigneo_filter_employers', array( $this, 'filter_employers' ) );
		//Job Archive Filter
		add_action( 'wp_ajax_gigneo_filter_jobs', array( $this, 'filter_jobs' ) );
		add_action( 'wp_ajax_nopriv_gigneo_filter_jobs', array( $this, 'filter_jobs' ) );

		//Remove Attachment
		add_action( 'wp_ajax_gigneo_remove_attachment', array( $this, 'remove_attachment' ) );
	}

	/**
	 * Get the class singleton instance.
	 *
	 * @since 0.0.1
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Handle module activation state updates.
	 *
	 * @since 0.0.1
	 */
	public function module_action() {

		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		// Check user capabilities
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Unauthorized access.', 'gigneo' ) ), 403 );
		}

		$module = isset( $_POST['module_id'] ) ? sanitize_text_field( wp_unslash( $_POST['module_id'] ) ) : '';
		$status = isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : '';

		$modules        = Modules::module_list();
		$active_modules = Modules::active_modules();

		if ( empty( $module ) || ! isset( $modules[ $module ] ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
		}

		$module = apply_filters( 'gigneo_ajax_active_module_action', $module );

		if ( 'active' === $status ) {
			if ( ! in_array( $module, $active_modules, true ) ) {
				$active_modules[] = $module;
			}
		} else {
			$key = array_search( $module, $active_modules, true );
			if ( false !== $key ) {
				unset( $active_modules[ $key ] );
			}
		}

		$active_modules = array_values( $active_modules );

		update_option( '_gigneo_active_modules', $active_modules );
		Modules::flush_cache();

		$module_status = in_array( $module, $active_modules, true );

		wp_send_json_success(
			array(
				'message'       => esc_html__( 'Module has been updated.', 'gigneo' ),
				'module_status' => $module_status,
			)
		);
	}

	/**
	 * Handle user login requests.
	 *
	 * @since 0.0.1
	 */
	public function auth_login() {

		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$email       = isset( $_POST['email'] ) ? sanitize_text_field( wp_unslash( $_POST['email'] ) ) : '';
		$remember_me = isset( $_POST['remember_me'] ) ? sanitize_text_field( wp_unslash( $_POST['remember_me'] ) ) : '';

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Passwords must not be sanitized;
		$password = isset( $_POST['password'] ) ? (string) wp_unslash( $_POST['password'] ) : '';

		if ( empty( $email ) || empty( $password ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
		}

		$credentials = array(
			'user_login'    => $email,
			'user_password' => $password,
			'remember'      => 'on' === $remember_me,
		);

		$secure_cookie = is_ssl();

		/*
		 * wp_signon() is used here intentionally to authenticate the user via the
		 * Gigneo marketplace custom login form. This is the WordPress-recommended
		 * approach for programmatic login and respects any security plugins that
		 * hook into the authentication process (e.g. login attempt limiters).
		 * The request is nonce-verified and all credentials are sanitized before use.
		 */
		$user = wp_signon( $credentials, $secure_cookie );

		if ( is_wp_error( $user ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Wrong email or password.', 'gigneo' ) ), 403 );
		}

		$dashboard_page_id = gigneo_option( '_gigneo_ts_template_dashboard' );
		$redirect_url      = ! empty( $dashboard_page_id ) ? get_permalink( $dashboard_page_id ) : home_url();

		$response             = array();
		$response['message']  = esc_html__( 'Successfully logged in. Redirecting...', 'gigneo' );
		$response['redirect'] = $redirect_url;

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle forgot password requests.
	 *
	 * @since 0.0.1
	 */
	public function auth_forgot_password() {

		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

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

		if ( empty( $email ) || ! is_email( $email ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid email address.', 'gigneo' ) ), 403 );
		}

		$user = get_user_by( 'email', $email );

		if ( $user ) {
			// Generate Password Reset Link
			$reset_key = get_password_reset_key( $user );

			//Reset Password url change
			add_filter(
				'woocommerce_get_endpoint_url',
				function ( $url, $endpoint ) {
					$forgot_password_template = gigneo_option( '_gigneo_ts_template_forgot_password' );
					$lost_password_endpoint   = get_option( 'woocommerce_myaccount_lost_password_endpoint' );
					if ( $endpoint === $lost_password_endpoint && ! empty( $forgot_password_template ) ) {
						return get_permalink( $forgot_password_template );
					}

					return $url;
				},
				10,
				4
			);

			$wc_mailer = WC()->mailer();
			$wc_emails = $wc_mailer->get_emails();

			//Reset Password url change
			add_filter(
				'woocommerce_get_endpoint_url',
				function ( $url, $endpoint ) {
					$forgot_password_template = gigneo_option( '_gigneo_ts_template_forgot_password' );
					$lost_password_endpoint   = get_option( 'woocommerce_myaccount_lost_password_endpoint' );
					if ( $endpoint === $lost_password_endpoint && ! empty( $forgot_password_template ) ) {
						return get_permalink( $forgot_password_template );
					}
					return $url;
				},
				10,
				4
			);
			$wc_emails['WC_Email_Customer_Reset_Password']->trigger( $user->user_login, $reset_key );
			wp_send_json_success( array( 'message' => __( 'Password reset email sent successfully.', 'gigneo' ) ), 200 );
		} else {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}
	}

	/**
	 * Handle password change requests.
	 *
	 * @since 0.0.1
	 */
	public function auth_change_password() {
		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$user_id    = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
		$user_login = isset( $_POST['login'] ) ? sanitize_text_field( wp_unslash( $_POST['login'] ) ) : '';
		$key        = isset( $_POST['key'] ) ? sanitize_text_field( wp_unslash( $_POST['key'] ) ) : '';

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Passwords must not be sanitized;
		$password = isset( $_POST['password'] ) ? (string) wp_unslash( $_POST['password'] ) : '';

		if ( empty( $user_id ) || empty( $user_login ) || empty( $password ) || empty( $key ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
		}

		$user = get_user_by( 'ID', $user_id );

		if ( ! $user ) {
			wp_send_json_error( array( 'message' => esc_html__( 'User not found.', 'gigneo' ) ), 409 );
		}

		$check_rest_key = check_password_reset_key( $key, $user->user_login );

		// Verify reset key
		if ( is_wp_error( $check_rest_key ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid or expired reset key.', 'gigneo' ) ), 403 );
		}

		// Password validation
		$password_strength_options = gigneo_password_strength_options();
		$password_validation       = gigneo_option( '_gigneo_ts_password_strength', array( 'length' ) );

		$rules = array(
			'length'    => fn( $p ) => strlen( $p ) < 8,
			'uppercase' => fn( $p ) => ! preg_match( '/[A-Z]/', $p ),
			'lowercase' => fn( $p ) => ! preg_match( '/[a-z]/', $p ),
			'number'    => fn( $p ) => ! preg_match( '/[0-9]/', $p ),
			'special'   => fn( $p ) => ! preg_match( '/[^a-zA-Z0-9]/', $p ),
		);

		foreach ( $password_validation as $rule ) {
			if ( isset( $rules[ $rule ] ) && $rules[ $rule ]( $password ) ) {
				wp_send_json_error( array( 'message' => $password_strength_options[ $rule ] ), 403 );
			}
		}

		remove_action( 'after_password_reset', 'wp_password_change_notification' );

		// Reset the password
		reset_password( $user, $password );

		//Trigger Notification
		$notification_title   = esc_html__( 'Password reset', 'gigneo' );
		$notification_content = esc_html__( 'Your account password has been reset successfully.', 'gigneo' );
		$profile_id           = gigneo_profile_id( $user_id );

		Notifications::trigger_notification( $notification_title, $notification_content, 'account', 'reset_password', $profile_id );

		$login_template = gigneo_option( '_gigneo_ts_template_login' );
		$redirect_url   = ! empty( $login_template ) ? get_permalink( $login_template ) : home_url();

		$response             = array();
		$response['message']  = esc_html__( 'Password has been changed successfully.', 'gigneo' );
		$response['redirect'] = $redirect_url;

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle username validation requests.
	 *
	 * @since 0.0.1
	 */
	public function auth_username_validate() {

		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$username = isset( $_POST['username'] ) ? sanitize_text_field( wp_unslash( $_POST['username'] ) ) : '';

		if ( empty( $username ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required field could not be empty.', 'gigneo' ) ), 403 );
		}

		if ( strlen( $username ) < 4 ) {
			wp_send_json_error( array( 'message' => esc_html__( 'username must include at least 4 characters.', 'gigneo' ) ), 403 );
		}

		if ( ! validate_username( $username ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid username please provide valid username.', 'gigneo' ) ), 403 );
		}

		$slug_posts = get_page_by_path( $username, OBJECT, array( 'gigneo_freelancer', 'gigneo_employer' ) );

		if ( username_exists( $username ) || $slug_posts ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Username is not available.', 'gigneo' ) ), 403 );
		}

		wp_send_json_success( array( 'message' => __( 'Username is available.', 'gigneo' ) ), 200 );
	}

	/**
	 * Handle user registration requests.
	 *
	 * @since 0.0.1
	 */
	public function auth_register() {

		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$register_disable = gigneo_option( '_gigneo_ts_disable_registration', true );

		if ( ! $register_disable ) {
			wp_send_json_error(
				array( 'message' => esc_html__( 'Registration is currently disabled.', 'gigneo' ) ),
				403
			);
		}

		$first_name        = isset( $_POST['first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['first_name'] ) ) : '';
		$last_name         = isset( $_POST['last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['last_name'] ) ) : '';
		$email             = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
		$terms_and_privacy = isset( $_POST['term_and_privacy'] ) ? sanitize_text_field( wp_unslash( $_POST['term_and_privacy'] ) ) : '';
		$role              = isset( $_POST['user_role'] ) ? sanitize_text_field( wp_unslash( $_POST['user_role'] ) ) : '';
		$username          = isset( $_POST['user_name'] ) ? sanitize_text_field( wp_unslash( $_POST['user_name'] ) ) : '';

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Passwords must not be sanitized;
		$password = isset( $_POST['password'] ) ? (string) wp_unslash( $_POST['password'] ) : '';

		if ( empty( $first_name ) || empty( $last_name ) || empty( $email ) || empty( $password ) || empty( $terms_and_privacy ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
		}

		if ( empty( $role ) ) {
			$role = gigneo_option( '_gigneo_ts_default_user_role', 'employer' );
		}

		// Role to capability mapping
		$role_capabilities = array(
			'freelancer' => 'gigneo_freelancer',
			'employer'   => 'gigneo_employer',
		);

		if ( ! isset( $role_capabilities[ $role ] ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		//Password validation
		$password_strength_options = gigneo_password_strength_options();
		$password_validation       = gigneo_option( '_gigneo_ts_password_strength', array( 'length' ) );

		$rules = array(
			'length'    => fn( $p ) => strlen( $p ) < 8,
			'uppercase' => fn( $p ) => ! preg_match( '/[A-Z]/', $p ),
			'lowercase' => fn( $p ) => ! preg_match( '/[a-z]/', $p ),
			'number'    => fn( $p ) => ! preg_match( '/[0-9]/', $p ),
			'special'   => fn( $p ) => ! preg_match( '/[^a-zA-Z0-9]/', $p ),
		);

		foreach ( $password_validation as $rule ) {
			if ( isset( $rules[ $rule ] ) && $rules[ $rule ]( $password ) ) {
				wp_send_json_error( array( 'message' => $password_strength_options[ $rule ] ), 403 );
			}
		}

		$userdata = array(
			'user_login' => $username,
			'user_email' => $email,
			'user_pass'  => $password,
			'role'       => $role_capabilities[ $role ],
		);

		$slug_posts = get_page_by_path( $username, OBJECT, array( 'gigneo_freelancer', 'gigneo_employer' ) );

		if ( username_exists( $username ) || $slug_posts ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Unable to create account with the provided slug.', 'gigneo' ) ) );
		}

		if ( email_exists( $email ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Unable to create account with the provided email.', 'gigneo' ) ), 409 );
		}

		/*
		 * wp_insert_user() is required here to register a new user in the Gigneo
		 * marketplace. This is the WordPress core function for user creation and
		 * is used instead of any custom alternative to ensure full compatibility
		 * with WordPress hooks and third-party plugins. All user data is fully
		 * sanitized and validated before being passed to this function.
		 */
		$user = wp_insert_user( $userdata );

		if ( is_wp_error( $user ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 409 );
		}

		update_user_meta( $user, 'first_name', $first_name );
		update_user_meta( $user, 'last_name', $last_name );

		update_user_meta( $user, 'billing_first_name', $first_name );
		update_user_meta( $user, 'billing_last_name', $last_name );
		update_user_meta( $user, 'billing_email', $email );

		//Create profile
		gigneo_create_profile( $user, $role );

		//Trigger Email
		$wc_mailer = WC()->mailer();
		$wc_emails = $wc_mailer->get_emails();

		$wc_emails['Gigneo_User_Registration']->trigger( $user );

		if ( in_array( 'email_verification', gigneo_active_modules(), true ) ) {
			$verification_link = gigneo_generate_email_verify_link( $user );
			$wc_emails['Gigneo_Email_Verification']->trigger( $user, $verification_link );
		}

		$credentials = array(
			'user_login'    => wp_unslash( $email ),
			'user_password' => $password,
		);

		$secure_cookie = is_ssl();

		/*
		 * wp_signon() is called here to automatically log in the newly registered
		 * user immediately after account creation. This is standard marketplace UX
		 * to avoid requiring the user to log in separately after registering.
		 * The credentials used are the same sanitized values submitted during
		 * registration. The request is nonce-verified.
		 */
		$user = wp_signon( $credentials, $secure_cookie );

		$dashboard_page_id = gigneo_option( '_gigneo_ts_template_dashboard' );
		$redirect_url      = ! empty( $dashboard_page_id ) ? get_permalink( $dashboard_page_id ) : home_url();

		$response             = array();
		$response['message']  = esc_html__( 'Successfully registered. Redirecting...', 'gigneo' );
		$response['redirect'] = $redirect_url;

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle profile creation requests.
	 *
	 * @since 0.0.1
	 */
	public function create_profile() {
		// Check if nonce is valid
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$user_id      = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
		$profile_type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';

		$user = new WP_User( $user_id );

		if ( empty( $user_id ) || empty( $profile_type ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		if ( 'freelancer' !== $profile_type && 'employer' !== $profile_type ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		$user->add_cap( "gigneo_$profile_type" );

		$profile_id = gigneo_create_profile( $user_id, $profile_type );

		if ( ! $profile_id ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		wp_send_json_success( array( 'message' => esc_html__( 'Profile created successfully.', 'gigneo' ) ), 200 );
	}

	/**
	 * Handle deposit fund requests.
	 *
	 * @throws Exception
	 * @since 0.0.1
	 */
	public function deposit_funds() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$amount = isset( $_POST['amount'] ) ? floatval( wp_unslash( $_POST['amount'] ) ) : 0;

		// Validate: amount must be a positive number
		if ( empty( $amount ) || $amount <= 0 ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Please enter a valid amount.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$profile_type = gigneo_profile_type();

		if ( 'freelancer' !== $profile_type && 'employer' !== $profile_type ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$wallet_product_id = gigneo_option( '_gigneo_ts_wallet_product' );
		$wallet_product    = ! empty( $wallet_product_id ) ? wc_get_product( $wallet_product_id ) : false;

		if ( ! $wallet_product ) {
			wp_send_json_error( array( 'message' => esc_html__( 'The wallet product is not configured correctly. Please contact the administrator.', 'gigneo' ) ), 403 );
		}

		// Ensure WooCommerce session and cart are initialized during AJAX
		if ( null === WC()->session ) {
			WC()->session = new WC_Session_Handler();
			WC()->session->init();
		}

		if ( null === WC()->cart ) {
			WC()->cart = new WC_Cart();
			WC()->cart->get_cart();
		}

		WC()->cart->empty_cart();
		WC()->cart->add_to_cart( $wallet_product_id, 1, 0, array(), array( 'wallet_amount' => $amount ) );

		$response             = array();
		$response['message']  = esc_html__( 'Redirecting to checkout...', 'gigneo' );
		$response['redirect'] = wc_get_checkout_url();

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle credit purchase requests.
	 *
	 * @since 0.0.1
	 */
	public function buy_credits() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$credits        = isset( $_POST['credits'] ) ? absint( wp_unslash( $_POST['credits'] ) ) : 0;
		$non_refundable = isset( $_POST['term_and_privacy'] ) ? sanitize_text_field( wp_unslash( $_POST['term_and_privacy'] ) ) : 'no';

		if ( empty( $credits ) || $credits < 0 || 'yes' !== $non_refundable ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required field could not be empty.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$profile_type = gigneo_profile_type();

		if ( 'freelancer' !== $profile_type && 'employer' !== $profile_type ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$credit_rate = gigneo_option( '_gigneo_ts_credit_rate', '1' );
		$credit_rate = abs( $credit_rate ) ?? 1;

		$total_amount   = $credits * $credit_rate;
		$wallet_balance = gigneo_wallet_balance( $profile_id );

		if ( $total_amount > $wallet_balance ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Insufficient wallet balance.', 'gigneo' ) ), 403 );
		}

		$post_id = wp_insert_post(
			array(
				'post_type'   => 'gigneo_invoice',
				'post_status' => 'paid',
				'post_title'  => esc_html__( 'Credit Purchased', 'gigneo' ),
				'post_author' => $current_user->ID,
			)
		);

		if ( is_wp_error( $post_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		$credits = sanitize_text_field( $credits );

		update_post_meta( $post_id, '_gigneo_pm_profile_id', $profile_id );
		update_post_meta( $post_id, '_gigneo_pm_total', -$total_amount );
		update_post_meta( $post_id, '_gigneo_pm_credit', $credits );
		update_post_meta( $post_id, '_gigneo_pm_type', 'credit' );

		//Notification
		$credit_nf_title   = esc_html__( 'Credit purchased', 'gigneo' );
		$credit_nf_content = sprintf(
			// translators: %s is credits
			esc_html__( 'Your purchase was completed successfully. %s credits have been added to your account.', 'gigneo' ),
			esc_html( $credits ),
		);

		Notifications::trigger_notification( $credit_nf_title, $credit_nf_content, 'credit', 'credit_purchased', $profile_id, $post_id );

		wp_send_json_success( array( 'message' => esc_html__( 'Credits purchase successfully.', 'gigneo' ) ), 200 );
	}

	/**
	 * Handle image crop requests.
	 *
	 * @since 0.0.1
	 */
	public function crop_image() {

		// Check if nonce is valid.
		$security = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ),
				),
				403
			);
		}

		/**
		 * Verify attachment exists and user is authorized to edit it.
		 * Prevents IDOR by ensuring users cannot crop arbitrary attachments.
		 */
		global $current_user;
		$platform_access = gigneo_user_have_access();

		if ( empty( $current_user->ID ) || ! $platform_access ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ),
				),
				403
			);
		}

		// phpcs:ignore WordPress.WP.Capabilities.Unknown -- Registered capabilities
		if ( ! user_can( $current_user->ID, 'gigneo_freelancer' ) && ! user_can( $current_user->ID, 'gigneo_employer' ) ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ),
				),
				403
			);
		}

		$post_id       = isset( $_POST['id'] ) ? absint( $_POST['id'] ) : 0;
		$attachment_id = absint( $post_id );

		$attachment = get_post( $attachment_id );

		if ( ! $attachment || 'attachment' !== $attachment->post_type ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'You do not have permission to modify this image.', 'gigneo' ),
				),
				403
			);
		}

		if ( (int) $attachment->post_author !== $current_user->ID ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ),
				),
				403
			);
		}

		$crop_details = isset( $_POST['cropDetails'] ) ? array_map( 'absint', wp_unslash( $_POST['cropDetails'] ) ) : array();

		$dst_width  = $crop_details['width'] ?? 0;
		$dst_height = $crop_details['height'] ?? 0;

		$cropped = wp_crop_image(
			$attachment_id,
			$crop_details['x1'],
			$crop_details['y1'],
			$crop_details['width'],
			$crop_details['height'],
			$dst_width,
			$dst_height
		);

		if ( ! $cropped || is_wp_error( $cropped ) ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'Something went wrong, image could not be processed.', 'gigneo' ),
				)
			);
		}

		$original_path     = get_attached_file( $attachment_id );
		$original_ext      = pathinfo( $original_path, PATHINFO_EXTENSION );
		$original_filename = pathinfo( $original_path, PATHINFO_FILENAME );

		if ( preg_match( '/^\d+(-x)?$/', $original_filename ) ) {
			$post = get_post( $attachment_id );
			if ( $post && $post->post_title ) {
				$original_filename = sanitize_title( $post->post_title );
			}
		}

		$new_filename = $original_filename . '-' . $dst_width . 'x' . $dst_height . '.' . $original_ext;
		$new_path     = dirname( $cropped ) . '/' . $new_filename;

		$suffix = 1;
		while ( file_exists( $new_path ) ) {
			$new_filename = $original_filename . '-' . $dst_width . 'x' . $dst_height . '-' . $suffix . '.' . $original_ext;
			$new_path     = dirname( $cropped ) . '/' . $new_filename;
			++$suffix;
		}

		global $wp_filesystem;

		if ( ! $wp_filesystem ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
			WP_Filesystem();
		}

		$move_result = $wp_filesystem->move( $cropped, $new_path, true );

		if ( ! $move_result ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'Failed to move cropped image file.', 'gigneo' ),
				)
			);
		}

		$cropped = $new_path;

		$object = gigneo_attachment_object( $cropped, $attachment_id );
		unset( $object['ID'] );

		$new_attachment_id = wp_insert_attachment( $object, $cropped );

		if ( ! $new_attachment_id ) {
			wp_send_json_error(
				array(
					'message' => esc_html__( 'Something went wrong.', 'gigneo' ),
				),
				400
			);
		}

		$metadata = wp_generate_attachment_metadata( $new_attachment_id, $cropped );

		// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
		$metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata );

		wp_update_attachment_metadata( $new_attachment_id, $metadata );

		$object['attachment_id'] = $new_attachment_id;
		$object['url']           = wp_get_attachment_url( $new_attachment_id );
		$object['width']         = $dst_width;
		$object['height']        = $dst_height;

		wp_send_json_success( $object );
	}

	/**
	 * Handle profile setting updates.
	 *
	 * @since 0.0.1
	 */
	public function save_profile_setting() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$current_user    = wp_get_current_user();
		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$profile_type    = gigneo_profile_type( $profile_id );

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';

		if ( empty( $type ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
		}

		$response            = array();
		$response['message'] = esc_html__( 'Profile data update successfully.', 'gigneo' );

		//Profile Image
		if ( 'profile_media_image' === $type ) {
			$profile_image = isset( $_POST['attachment_id'] ) ? absint( wp_unslash( $_POST['attachment_id'] ) ) : '';
			$attachment    = get_post( $profile_image );

			if ( empty( $profile_image ) || ! $attachment || 'attachment' !== $attachment->post_type ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}
			if ( (int) $attachment->post_author !== $current_user->ID ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			set_post_thumbnail( $profile_id, $profile_image );

		}

		//Cover Image
		if ( 'profile_media_cover' === $type ) {
			$cover_image = isset( $_POST['attachment_id'] ) ? sanitize_text_field( wp_unslash( $_POST['attachment_id'] ) ) : '';
			$attachment  = get_post( $cover_image );

			if ( empty( $cover_image ) || ! $attachment || 'attachment' !== $attachment->post_type ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			if ( (int) $attachment->post_author !== $current_user->ID ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			update_post_meta( $profile_id, '_gigneo_pm_cover_image', $cover_image );

		}

		//Personal Info
		if ( 'personal-info' === $type ) {
			$first_name    = isset( $_POST['first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['first_name'] ) ) : '';
			$last_name     = isset( $_POST['last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['last_name'] ) ) : '';
			$tagline       = isset( $_POST['tagline'] ) ? sanitize_text_field( wp_unslash( $_POST['tagline'] ) ) : '';
			$phone         = isset( $_POST['phone'] ) ? sanitize_text_field( wp_unslash( $_POST['phone'] ) ) : '';
			$gender        = isset( $_POST['gender'] ) ? sanitize_text_field( wp_unslash( $_POST['gender'] ) ) : '';
			$dob           = isset( $_POST['dob'] ) ? sanitize_text_field( wp_unslash( $_POST['dob'] ) ) : '';
			$visibility    = isset( $_POST['visibility'] ) ? sanitize_text_field( wp_unslash( $_POST['visibility'] ) ) : 'public';
			$qualification = isset( $_POST['qualification'] ) ? sanitize_text_field( wp_unslash( $_POST['qualification'] ) ) : '';

			if ( empty( $first_name ) || empty( $last_name ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			update_post_meta( $profile_id, '_gigneo_pm_first_name', $first_name );
			update_post_meta( $profile_id, '_gigneo_pm_last_name', $last_name );
			update_post_meta( $profile_id, '_gigneo_pm_tagline', $tagline );
			update_post_meta( $profile_id, '_gigneo_pm_phone', $phone );
			update_post_meta( $profile_id, '_gigneo_pm_dob', $dob );
			update_post_meta( $profile_id, '_gigneo_pm_gender', $gender );
			update_post_meta( $profile_id, '_gigneo_pm_visibility', $visibility );
			update_post_meta( $profile_id, '_gigneo_pm_qualification', $qualification );

			//Billing Info
			$billing_phone = get_user_meta( $current_user->ID, 'billing_phone', true );

			if ( ! empty( $phone ) && empty( $billing_phone ) ) {
				update_user_meta( $current_user->ID, 'billing_phone', $phone );
			}

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/media' );
			$media_markup = ob_get_clean();

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/personal-info' );
			$personal_info_markup = ob_get_clean();

			$response['markup']['media']         = $media_markup;
			$response['markup']['personal-info'] = $personal_info_markup;
		}

		//Description
		if ( 'description' === $type ) {
			$allowed_tags = gigneo_allowed_html_tags();
			$description  = isset( $_POST['description'] ) ? wp_kses( wp_unslash( $_POST['description'] ), $allowed_tags ) : '';

			if ( empty( $description ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			update_post_meta( $profile_id, '_gigneo_pm_bio', $description );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/description' );
			$description_markup = ob_get_clean();

			$response['markup']['description'] = $description_markup;
		}

		//Address
		if ( 'address' === $type ) {
			$country_state = isset( $_POST['country_state'] ) ? sanitize_text_field( wp_unslash( $_POST['country_state'] ) ) : '';
			$city          = isset( $_POST['city'] ) ? sanitize_text_field( wp_unslash( $_POST['city'] ) ) : '';
			$area          = isset( $_POST['area'] ) ? sanitize_text_field( wp_unslash( $_POST['area'] ) ) : '';
			$zip_code      = isset( $_POST['zip_code'] ) ? sanitize_text_field( wp_unslash( $_POST['zip_code'] ) ) : '';
			$address       = isset( $_POST['address'] ) ? sanitize_textarea_field( wp_unslash( $_POST['address'] ) ) : '';

			if ( empty( $country_state ) || empty( $zip_code ) || empty( $address ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			list($country, $state) = explode( ':', $country_state );

			if ( ! WC_Validation::is_postcode( $zip_code, $country ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Invalid Postcode / ZIP.', 'gigneo' ) ), 403 );
			}

			do_action( 'gigneo_save_profile_setting_before_address_map', $profile_id, $_POST, $address );

			update_post_meta( $profile_id, '_gigneo_pm_country_state', $country_state );
			update_post_meta( $profile_id, '_gigneo_pm_city', $city );
			update_post_meta( $profile_id, '_gigneo_pm_area', $area );
			update_post_meta( $profile_id, '_gigneo_pm_zip_code', $zip_code );
			update_post_meta( $profile_id, '_gigneo_pm_address', $address );

			//Billing Info
			$billing_postcode = get_user_meta( $current_user->ID, 'billing_postcode', true );
			$billing_country  = get_user_meta( $current_user->ID, 'billing_country', true );
			$billing_state    = get_user_meta( $current_user->ID, 'billing_state', true );
			$billing_city     = get_user_meta( $current_user->ID, 'billing_city', true );
			$billing_address  = get_user_meta( $current_user->ID, 'billing_address_1', true );

			if ( ! empty( $zip_code ) && empty( $billing_postcode ) ) {
				update_user_meta( $current_user->ID, 'billing_postcode', $zip_code );
			}

			if ( ! empty( $country ) && empty( $billing_country ) ) {
				update_user_meta( $current_user->ID, 'billing_country', $country );
			}

			if ( ! empty( $state ) && empty( $billing_state ) ) {
				update_user_meta( $current_user->ID, 'billing_state', $state );
			}

			if ( ! empty( $city ) && empty( $billing_city ) ) {
				update_user_meta( $current_user->ID, 'billing_city', $city );
			}

			if ( ! empty( $address ) && empty( $billing_address ) ) {
				update_user_meta( $current_user->ID, 'billing_address_1', $address );
			}

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/address' );
			$personal_info_markup = ob_get_clean();

			$response['markup']['address'] = $personal_info_markup;
		}

		//Categories
		if ( 'categories' === $type ) {
			$categories    = isset( $_POST['categories'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['categories'] ) ) : array();
			$category_list = gigneo_term_list(
				array(
					'taxonomy' => 'gigneo_facet',
					'parent'   => 0,
				),
				false
			);

			if ( empty( $categories ) || empty( $category_list ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			// Keep only allowed category slugs
			foreach ( $categories as $key => $cat_slug ) {
				if ( ! array_key_exists( $cat_slug, $category_list ) ) {
					unset( $categories[ $key ] );
				}
			}

			$categories = array_values( $categories );
			update_post_meta( $profile_id, '_gigneo_pm_categories', $categories );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/categories' );
			$categories_markup = ob_get_clean();

			$response['markup']['categories'] = $categories_markup;
		}

		//Skill
		if ( 'skill' === $type ) {
			$skills     = isset( $_POST['skills'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['skills'] ) ) : array();
			$skill_list = gigneo_term_list( array( 'taxonomy' => 'gigneo_skill' ), false );

			if ( empty( $skills ) || empty( $skill_list ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			// Keep only allowed tag slugs
			foreach ( $skills as $key => $skill_slug ) {
				if ( ! array_key_exists( $skill_slug, $skill_list ) ) {
					unset( $skills[ $key ] );
				}
			}

			$skills = array_values( $skills );
			update_post_meta( $profile_id, '_gigneo_pm_skills', $skills );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/skills' );
			$skills_markup = ob_get_clean();

			$response['markup']['skills'] = $skills_markup;
		}

		//Portfolio
		if ( 'portfolio' === $type ) {

			$portfolio_meta             = gigneo_post_meta( $profile_id, '_gigneo_pm_portfolio' );
			$portfolio_meta             = ! empty( $portfolio_meta ) ? $portfolio_meta : array();
			$portfolio_id               = isset( $_POST['portfolio_id'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_id'] ) ) : '';
			$portfolio_title            = isset( $_POST['portfolio_title'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_title'] ) ) : '';
			$portfolio_role             = isset( $_POST['portfolio_role'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_role'] ) ) : '';
			$portfolio_type             = isset( $_POST['portfolio_type'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_type'] ) ) : '';
			$portfolio_date             = isset( $_POST['portfolio_date'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_date'] ) ) : '';
			$portfolio_feature_image    = isset( $_POST['portfolio_feature_image'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_feature_image'] ) ) : '';
			$portfolio_preview_image    = isset( $_POST['portfolio_preview_image'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_preview_image'] ) ) : '';
			$portfolio_preview_document = isset( $_POST['portfolio_preview_document'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_preview_document'] ) ) : '';
			$portfolio_preview_video    = isset( $_POST['portfolio_preview_video'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_preview_video'] ) ) : '';
			$portfolio_preview_link     = isset( $_POST['portfolio_preview_link'] ) ? sanitize_text_field( wp_unslash( $_POST['portfolio_preview_link'] ) ) : '';

			if ( empty( $portfolio_title ) || empty( $portfolio_role ) || empty( $portfolio_feature_image ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$portfolio_data = array(
				'value'            => '_',
				'title'            => $portfolio_title,
				'role'             => $portfolio_role,
				'date'             => $portfolio_date,
				'type'             => $portfolio_type,
				'image'            => $portfolio_feature_image,
				'preview_image'    => get_post( $portfolio_preview_image ) ? $portfolio_preview_image : '',
				'preview_document' => get_post( $portfolio_preview_document ) ? $portfolio_preview_document : '',
				'preview_video'    => esc_url_raw( $portfolio_preview_video ),
				'preview_link'     => esc_url_raw( $portfolio_preview_link ),
			);

			if ( '' !== $portfolio_id && isset( $portfolio_meta[ $portfolio_id ] ) ) {
				$portfolio_meta[ $portfolio_id ] = $portfolio_data;
			} else {
				array_unshift( $portfolio_meta, $portfolio_data );
			}

			update_post_meta( $profile_id, '_gigneo_pm_portfolio', $portfolio_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/portfolio' );
			$portfolio_markup = ob_get_clean();

			$response['markup']['portfolio'] = $portfolio_markup;

		}

		//Educations
		if ( 'educations' === $type ) {

			$educations_meta          = gigneo_post_meta( $profile_id, '_gigneo_pm_education' );
			$educations_meta          = ! empty( $educations_meta ) ? $educations_meta : array();
			$education_id             = isset( $_POST['education_id'] ) ? sanitize_text_field( wp_unslash( $_POST['education_id'] ) ) : '';
			$education_school         = isset( $_POST['education_school'] ) ? sanitize_text_field( wp_unslash( $_POST['education_school'] ) ) : '';
			$education_degree         = isset( $_POST['education_degree'] ) ? sanitize_text_field( wp_unslash( $_POST['education_degree'] ) ) : '';
			$education_specialization = isset( $_POST['education_specialization'] ) ? sanitize_text_field( wp_unslash( $_POST['education_specialization'] ) ) : '';
			$education_start_date     = isset( $_POST['education_start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['education_start_date'] ) ) : '';
			$education_end_date       = isset( $_POST['education_end_date'] ) ? sanitize_text_field( wp_unslash( $_POST['education_end_date'] ) ) : '';

			if ( empty( $education_school ) || empty( $education_degree ) || empty( $education_specialization ) || empty( $education_start_date ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$education_data = array(
				'value'          => '_',
				'school'         => $education_school,
				'degree'         => $education_degree,
				'specialization' => $education_specialization,
				'start_date'     => $education_start_date,
				'end_date'       => $education_end_date,
			);

			if ( '' !== $education_id && isset( $educations_meta[ $education_id ] ) ) {
				$educations_meta[ $education_id ] = $education_data;
			} else {
				array_unshift( $educations_meta, $education_data );
			}

			update_post_meta( $profile_id, '_gigneo_pm_education', $educations_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/education' );
			$educations_markup = ob_get_clean();

			$response['markup']['education'] = $educations_markup;

		}

		//Experiences
		if ( 'experiences' === $type ) {

			$experiences_meta       = gigneo_post_meta( $profile_id, '_gigneo_pm_experience' );
			$experiences_meta       = ! empty( $experiences_meta ) ? $experiences_meta : array();
			$experience_id          = isset( $_POST['experience_id'] ) ? sanitize_text_field( wp_unslash( $_POST['experience_id'] ) ) : '';
			$experience_title       = isset( $_POST['experience_title'] ) ? sanitize_text_field( wp_unslash( $_POST['experience_title'] ) ) : '';
			$experience_company     = isset( $_POST['experience_company'] ) ? sanitize_text_field( wp_unslash( $_POST['experience_company'] ) ) : '';
			$experience_start_date  = isset( $_POST['experience_start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['experience_start_date'] ) ) : '';
			$experience_end_date    = isset( $_POST['experience_end_date'] ) ? sanitize_text_field( wp_unslash( $_POST['experience_end_date'] ) ) : '';
			$experience_logo        = isset( $_POST['experience_logo'] ) ? sanitize_text_field( wp_unslash( $_POST['experience_logo'] ) ) : '';
			$experience_description = isset( $_POST['experience_description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['experience_description'] ) ) : '';

			if ( empty( $experience_title ) || empty( $experience_company ) || empty( $experience_start_date ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$experiences_detail = array(
				'value'       => '_',
				'title'       => $experience_title,
				'company'     => $experience_company,
				'start_date'  => $experience_start_date,
				'end_date'    => $experience_end_date,
				'logo'        => $experience_logo,
				'description' => $experience_description,
			);

			if ( '' !== $experience_id && isset( $experiences_meta[ $experience_id ] ) ) {
				$experiences_meta[ $experience_id ] = $experiences_detail;
			} else {
				array_unshift( $experiences_meta, $experiences_detail );
			}

			update_post_meta( $profile_id, '_gigneo_pm_experience', $experiences_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/experience' );
			$experiences_markup = ob_get_clean();

			$response['markup']['experience'] = $experiences_markup;

		}

		//Awards
		if ( 'awards' === $type ) {

			$awards_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_awards' );
			$awards_meta = ! empty( $awards_meta ) ? $awards_meta : array();
			$award_id    = isset( $_POST['award_id'] ) ? sanitize_text_field( wp_unslash( $_POST['award_id'] ) ) : '';
			$award_title = isset( $_POST['award_title'] ) ? sanitize_text_field( wp_unslash( $_POST['award_title'] ) ) : '';
			$award_by    = isset( $_POST['award_by'] ) ? sanitize_text_field( wp_unslash( $_POST['award_by'] ) ) : '';
			$award_date  = isset( $_POST['award_date'] ) ? sanitize_text_field( wp_unslash( $_POST['award_date'] ) ) : '';

			if ( empty( $award_title ) || empty( $award_by ) || empty( $award_date ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$award_data = array(
				'value'    => '_',
				'title'    => $award_title,
				'award_by' => $award_by,
				'date'     => $award_date,
			);

			if ( '' !== $award_id && isset( $awards_meta[ $award_id ] ) ) {
				$awards_meta[ $award_id ] = $award_data;
			} else {
				array_unshift( $awards_meta, $award_data );
			}

			update_post_meta( $profile_id, '_gigneo_pm_awards', $awards_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/awards' );
			$awards_markup = ob_get_clean();

			$response['markup']['awards'] = $awards_markup;

		}

		//Certificates
		if ( 'certificates' === $type ) {

			$certificates_meta        = gigneo_post_meta( $profile_id, '_gigneo_pm_certificates' );
			$certificates_meta        = ! empty( $certificates_meta ) ? $certificates_meta : array();
			$certificate_id           = isset( $_POST['certificate_id'] ) ? sanitize_text_field( wp_unslash( $_POST['certificate_id'] ) ) : '';
			$certificate_title        = isset( $_POST['certificate_title'] ) ? sanitize_text_field( wp_unslash( $_POST['certificate_title'] ) ) : '';
			$certificate_organisation = isset( $_POST['certificate_organisation'] ) ? sanitize_text_field( wp_unslash( $_POST['certificate_organisation'] ) ) : '';
			$certificate_start_date   = isset( $_POST['certificate_start_date'] ) ? sanitize_text_field( wp_unslash( $_POST['certificate_start_date'] ) ) : '';
			$certificate_end_date     = isset( $_POST['certificate_end_date'] ) ? sanitize_text_field( wp_unslash( $_POST['certificate_end_date'] ) ) : '';
			$certificate_image        = isset( $_POST['certificate_image'] ) ? sanitize_text_field( wp_unslash( $_POST['certificate_image'] ) ) : '';

			if ( empty( $certificate_title ) || empty( $certificate_organisation ) || empty( $certificate_start_date ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$certificate_data = array(
				'value'        => '_',
				'title'        => $certificate_title,
				'organisation' => $certificate_organisation,
				'start_date'   => $certificate_start_date,
				'end_date'     => $certificate_end_date,
				'image'        => $certificate_image,
			);

			if ( '' !== $certificate_id && isset( $certificates_meta[ $certificate_id ] ) ) {
				$certificates_meta[ $certificate_id ] = $certificate_data;
			} else {
				array_unshift( $certificates_meta, $certificate_data );
			}

			update_post_meta( $profile_id, '_gigneo_pm_certificates', $certificates_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/certificates' );
			$certificates_markup = ob_get_clean();

			$response['markup']['certificates'] = $certificates_markup;

		}

		//Licenses
		if ( 'licenses' === $type ) {
			$licenses_meta            = gigneo_post_meta( $profile_id, '_gigneo_pm_licenses' );
			$licenses_meta            = ! empty( $licenses_meta ) ? $licenses_meta : array();
			$license_id               = isset( $_POST['license_id'] ) ? sanitize_text_field( wp_unslash( $_POST['license_id'] ) ) : '';
			$license                  = isset( $_POST['license'] ) ? sanitize_text_field( wp_unslash( $_POST['license'] ) ) : '';
			$license_provider         = isset( $_POST['license_provider'] ) ? sanitize_text_field( wp_unslash( $_POST['license_provider'] ) ) : '';
			$license_number           = isset( $_POST['license_number'] ) ? sanitize_text_field( wp_unslash( $_POST['license_number'] ) ) : '';
			$license_verification_url = isset( $_POST['license_verification_url'] ) ? sanitize_text_field( wp_unslash( $_POST['license_verification_url'] ) ) : '';
			$license_issue_date       = isset( $_POST['license_issue_date'] ) ? sanitize_text_field( wp_unslash( $_POST['license_issue_date'] ) ) : '';
			$license_expiry_date      = isset( $_POST['license_expiry_date'] ) ? sanitize_text_field( wp_unslash( $_POST['license_expiry_date'] ) ) : '';
			$license_logo             = isset( $_POST['license_logo'] ) ? sanitize_text_field( wp_unslash( $_POST['license_logo'] ) ) : '';
			$license_note             = isset( $_POST['license_note'] ) ? sanitize_textarea_field( wp_unslash( $_POST['license_note'] ) ) : '';

			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			$license_files = isset( $_FILES['license_files'] ) ? $_FILES['license_files'] : null;

			if ( empty( $license ) || empty( $license_provider ) || empty( $license_issue_date ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$license_term = get_term_by( 'slug', $license, 'gigneo_license' );

			if ( is_wp_error( $license_term ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Selected license is invalid.', 'gigneo' ) ), 403 );
			}

			$license_data = array(
				'value'            => '_',
				'license'          => $license,
				'provider'         => $license_provider,
				'license_number'   => $license_number,
				'verification_url' => esc_url_raw( $license_verification_url ),
				'issue_date'       => $license_issue_date,
				'expiry_date'      => $license_expiry_date,
				'logo'             => $license_logo,
				'note'             => $license_note,
			);

			$files_collection = array();

			if ( $license_files && is_array( $license_files['name'] ) ) {

				$license_extensions = gigneo_option( '_gigneo_ts_license_extensions', array( 'jpg', 'jpeg', 'png', 'doc' ) );
				$license_max_files  = gigneo_option( '_gigneo_ts_license_max_files', '3' );
				$license_max_size   = gigneo_option( '_gigneo_ts_license_max_size', '1' );
				$license_password   = gigneo_option( '_gigneo_ts_license_attachments_password', '' );
				$max_file_size      = $license_max_size * 1024 * 1024;
				$total_files        = count( $license_files['name'] );

				if ( $total_files > $license_max_files ) {
					wp_send_json_error(
						array(
							'message' => sprintf(
								// translators: %s is maximum number of files allowed.
								esc_html__( 'You can only upload up to %s files.', 'gigneo' ),
								esc_html( $license_max_files )
							),
						)
					);
				}

				for ( $i = 0; $i < $total_files; $i++ ) {

					$error    = isset( $license_files['error'][ $i ] ) ? absint( $license_files['error'][ $i ] ) : UPLOAD_ERR_NO_FILE;
					$size     = isset( $license_files['size'][ $i ] ) ? absint( $license_files['size'][ $i ] ) : 0;
					$name     = isset( $license_files['name'][ $i ] ) ? sanitize_file_name( wp_unslash( $license_files['name'][ $i ] ) ) : '';
					$tmp_path = isset( $license_files['tmp_name'][ $i ] ) ? sanitize_text_field( $license_files['tmp_name'][ $i ] ) : '';

					// Validate uploaded file.
					if ( empty( $tmp_path ) || ! is_uploaded_file( $tmp_path ) ) {
						wp_send_json_error(
							array(
								'message' => esc_html__( 'Invalid uploaded file.', 'gigneo' ),
							)
						);
					}

					$ext = strtolower( pathinfo( $name, PATHINFO_EXTENSION ) );

					if ( UPLOAD_ERR_OK !== $error ) {
						wp_send_json_error(
							array(
								'message' => sprintf(
									/* translators: %s is the file name. */
									esc_html__( 'Error uploading file: %s', 'gigneo' ),
									esc_html( $name )
								),
							)
						);
					}

					if ( ! in_array( $ext, $license_extensions, true ) ) {
						wp_send_json_error(
							array(
								'message' => sprintf(
									/* translators: %s is the file name. */
									esc_html__( 'File type not allowed: %s', 'gigneo' ),
									esc_html( $name )
								),
							)
						);
					}

					$filetype = wp_check_filetype_and_ext( $tmp_path, $name );

					if ( empty( $filetype['ext'] ) || empty( $filetype['type'] ) || $filetype['ext'] !== $ext ) {
						wp_send_json_error(
							array(
								'message' => sprintf(
									/* translators: %s is the file name. */
									esc_html__( 'File type not allowed: %s', 'gigneo' ),
									esc_html( $name )
								),
							)
						);
					}

					if ( $size > $max_file_size ) {
						wp_send_json_error(
							array(
								'message' => sprintf(
									/* translators: 1: File name, 2: Maximum file size in MB. */
									esc_html__( '%1$s exceeds the maximum file size of %2$s MB.', 'gigneo' ),
									esc_html( $name ),
									esc_html( $license_max_size )
								),
							)
						);
					}

					$files_collection[] = array(
						'name' => $name,
						'path' => $tmp_path,
					);
				}

				if ( ! class_exists( 'ZipArchive' ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'ZipArchive is not available on this server.', 'gigneo' ) ), 500 );
				}

				global $wpdb;
				// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$table_attachments = $wpdb->prefix . 'gigneo_attachments';
				// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$license_dir = gigneo_upload_dir_path( '/' . gmdate( 'Y' ) . '/' . gmdate( 'm' ) . '/license-verification' );

				if ( ! file_exists( $license_dir ) ) {
					wp_mkdir_p( $license_dir );
				}

				$zip_name = sprintf( 'license-%s-%s.zip', $profile_id, wp_rand( 1000, 9999 ) );
				$zip_path = trailingslashit( $license_dir ) . $zip_name;
				$zip      = new ZipArchive();

				if ( $zip->open( $zip_path, ZipArchive::CREATE ) !== true ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to create ZIP file.', 'gigneo' ) ), 403 );
				}

				// Set password mode
				if ( ! empty( $license_password ) ) {
					$zip->setPassword( $license_password );
				}

				foreach ( $files_collection as $file ) {
					$zip->addFile( $file['path'], $file['name'] );
					if ( ! empty( $license_password ) ) {
						// Add files using password encryption (AES-256)
						$zip->setEncryptionName( $file['name'], ZipArchive::EM_AES_256 );
					}
				}

				$zip->close();
				// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$insert_file = $wpdb->insert(
					$table_attachments,
					array(
						'post_id'         => $current_user->ID,
						'profile_id'      => absint( $profile_id ),
						'name'            => $zip_name,
						'mime_type'       => 'zip',
						'size'            => filesize( $zip_path ),
						'guid'            => str_replace( gigneo_upload_dir_path(), gigneo_upload_dir_url(), $zip_path ),
						'path'            => str_replace( gigneo_upload_dir_path(), '', $zip_path ),
						'post_type'       => $profile_type,
						'uploaded_at'     => current_time( 'mysql' ),
						'uploaded_at_gmt' => current_time( 'mysql', 1 ),
					),
					array( '%d', '%d', '%s', '%s', '%d', '%s', '%s', '%s', '%s', '%s' )
				);
				// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

				if ( false === $insert_file && empty( $wpdb->insert_id ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
				}

				$license_data['attachment_url'] = str_replace( gigneo_upload_dir_path(), gigneo_upload_dir_url(), $zip_path );

			}

			if ( '' !== $license_id && isset( $licenses_meta[ $license_id ] ) ) {

				if ( empty( $license_data['attachment_url'] ) ) {
					$license_data['attachment_url'] = $licenses_meta[ $license_id ]['attachment_url'] ?? '';
				}

				$licenses_meta[ $license_id ] = $license_data;
			} else {
				array_unshift( $licenses_meta, $license_data );
			}

			update_post_meta( $profile_id, '_gigneo_pm_licenses', $licenses_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/licenses' );
			$licenses_markup = ob_get_clean();

			$response['markup']['licenses'] = $licenses_markup;

		}

		//Faqs
		if ( 'faqs' === $type ) {

			$faqs_meta    = gigneo_post_meta( $profile_id, '_gigneo_pm_faqs' );
			$faqs_meta    = ! empty( $faqs_meta ) ? $faqs_meta : array();
			$faq_id       = isset( $_POST['faq_id'] ) ? sanitize_text_field( wp_unslash( $_POST['faq_id'] ) ) : '';
			$faq_question = isset( $_POST['faq_question'] ) ? sanitize_text_field( wp_unslash( $_POST['faq_question'] ) ) : '';
			$faq_answer   = isset( $_POST['faq_answer'] ) ? sanitize_textarea_field( wp_unslash( $_POST['faq_answer'] ) ) : '';

			if ( empty( $faq_question ) || empty( $faq_answer ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$faq_data = array(
				'value'    => '_',
				'question' => $faq_question,
				'answer'   => $faq_answer,
			);

			if ( '' !== $faq_id && isset( $faqs_meta[ $faq_id ] ) ) {
				$faqs_meta[ $faq_id ] = $faq_data;
			} else {
				array_unshift( $faqs_meta, $faq_data );
			}

			update_post_meta( $profile_id, '_gigneo_pm_faqs', $faqs_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/faqs' );
			$faqs_markup = ob_get_clean();

			$response['markup']['faqs'] = $faqs_markup;

		}

		//Languages
		if ( 'languages' === $type ) {
			$languages          = ! empty( $_POST['languages'] ) ? map_deep( wp_unslash( $_POST['languages'] ), 'sanitize_text_field' ) : array();
			$languages_data     = array();
			$languages_taxonomy = array();

			if ( ! empty( $languages ) ) {
				foreach ( $languages as $lang ) {
					$languages_data[]     = array(
						'name'  => sanitize_text_field( $lang['name'] ),
						'level' => sanitize_text_field( $lang['level'] ),
					);
					$languages_taxonomy[] = sanitize_text_field( $lang['name'] );
				}
			}

			wp_set_object_terms( $profile_id, $languages_taxonomy, 'gigneo_language' );
			update_post_meta( $profile_id, '_gigneo_pm_languages', $languages_data );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/languages' );
			$languages_markup = ob_get_clean();

			$response['markup']['languages'] = $languages_markup;

		}

		//Intro Video
		if ( 'intro' === $type ) {
			$intro_poster = isset( $_POST['intro_poster'] ) ? sanitize_text_field( wp_unslash( $_POST['intro_poster'] ) ) : '';
			$intro_video  = isset( $_POST['intro_video'] ) ? sanitize_text_field( wp_unslash( $_POST['intro_video'] ) ) : '';

			$poster_attachment = get_post( $intro_poster );
			if ( $poster_attachment && 'attachment' === $poster_attachment->post_type ) {
				update_post_meta( $profile_id, '_gigneo_pm_intro_poster', $intro_poster );
			} else {
				update_post_meta( $profile_id, '_gigneo_pm_intro_poster', '' );
			}

			$video_attachment = get_post( $intro_video );
			if ( $video_attachment && 'attachment' === $video_attachment->post_type ) {
				update_post_meta( $profile_id, '_gigneo_pm_intro_video', $intro_video );
			} else {
				update_post_meta( $profile_id, '_gigneo_pm_intro_video', '' );
			}

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/intro' );
			$intro_markup = ob_get_clean();

			$response['markup']['intro'] = $intro_markup;
		}

		//Resume
		if ( 'resume' === $type && 'freelancer' === $profile_type ) {
			$resume            = isset( $_POST['resume'] ) ? sanitize_text_field( wp_unslash( $_POST['resume'] ) ) : '';
			$resume_attachment = get_post( $resume );
			if ( $resume_attachment && 'attachment' === $resume_attachment->post_type ) {
				update_post_meta( $profile_id, '_gigneo_pm_resume', $resume );
			}

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/resume' );
			$resume_markup = ob_get_clean();

			$response['markup']['resume'] = $resume_markup;

		}

		//Socials
		if ( 'socials' === $type ) {
			$socials      = isset( $_POST['socials'] ) ? map_deep( wp_unslash( $_POST['socials'] ), 'sanitize_text_field' ) : array();
			$socials_data = array();

			if ( ! empty( $socials ) ) {
				foreach ( $socials as $social ) {
					$socials_data[] = array(
						'type' => $social['type'],
						'url'  => esc_url_raw( $social['url'] ),
					);
				}
			}

			update_post_meta( $profile_id, '_gigneo_pm_socials', $socials_data );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/socials' );
			$socials_markup = ob_get_clean();

			$response['markup']['socials'] = $socials_markup;

		}

		$response = apply_filters( 'gigneo_save_profile_setting_after', $response, $profile_id, $type );

		wp_update_post(
			array(
				'ID'                => $profile_id,
				'post_modified'     => current_time( 'mysql' ),
				'post_modified_gmt' => current_time( 'mysql', 1 ),
			)
		);

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle profile setting deletions.
	 *
	 * @since 0.0.1
	 */
	public function delete_profile_setting() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$type    = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
		$item_id = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;

		if ( empty( $type ) || ! isset( $_POST['id'] ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
		}

		$response            = array();
		$response['markup']  = array();
		$response['message'] = esc_html__( 'Profile update successfully.', 'gigneo' );

		//Education
		if ( 'education' === $type ) {

			$education_id = $item_id;

			$educations_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_education' );

			if ( ! isset( $educations_meta[ $education_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $educations_meta[ $education_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_education', $educations_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/education' );
			$educations_markup = ob_get_clean();

			$response['markup']['education'] = $educations_markup;

		}

		//Experience
		if ( 'experience' === $type ) {

			$experience_id = $item_id;

			$experiences_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_experience' );

			if ( ! isset( $experiences_meta[ $experience_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $experiences_meta[ $experience_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_experience', $experiences_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/experience' );
			$experiences_markup = ob_get_clean();

			$response['markup']['experience'] = $experiences_markup;

		}

		//Portfolio
		if ( 'portfolio' === $type ) {

			$portfolio_id = $item_id;

			$portfolio_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_portfolio' );

			if ( ! isset( $portfolio_meta[ $portfolio_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $portfolio_meta[ $portfolio_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_portfolio', $portfolio_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/portfolio' );
			$portfolio_markup = ob_get_clean();

			$response['markup']['portfolio'] = $portfolio_markup;

		}

		//Certificate
		if ( 'certificate' === $type ) {

			$certificate_id = $item_id;

			$certificates_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_certificates' );

			if ( ! isset( $certificates_meta[ $certificate_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $certificates_meta[ $certificate_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_certificates', $certificates_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/certificates' );
			$certificates_markup = ob_get_clean();

			$response['markup']['certificates'] = $certificates_markup;

		}

		//Award
		if ( 'award' === $type ) {

			$award_id = $item_id;

			$awards_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_awards' );

			if ( ! isset( $awards_meta[ $award_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $awards_meta[ $award_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_awards', $awards_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/awards' );
			$awards_markup = ob_get_clean();

			$response['markup']['awards'] = $awards_markup;

		}

		//License
		if ( 'license' === $type ) {

			$license_id = $item_id;

			$licenses_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_licenses' );

			if ( ! isset( $licenses_meta[ $license_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $licenses_meta[ $license_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_licenses', $licenses_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/licenses' );
			$licenses_markup = ob_get_clean();

			$response['markup']['licenses'] = $licenses_markup;

		}

		//FAQs
		if ( 'faq' === $type ) {

			$faq_id = $item_id;

			$faqs_meta = gigneo_post_meta( $profile_id, '_gigneo_pm_faqs' );

			if ( ! isset( $faqs_meta[ $faq_id ] ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
			}

			unset( $faqs_meta[ $faq_id ] );

			update_post_meta( $profile_id, '_gigneo_pm_faqs', $faqs_meta );

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/profile/faqs' );
			$faqs_markup = ob_get_clean();

			$response['markup']['faqs'] = $faqs_markup;

		}

		$response = apply_filters( 'gigneo_delete_profile_setting_after', $response, $profile_id, $type );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle account setting updates.
	 *
	 * @since 0.0.1
	 */
	public function save_account_setting() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || empty( $profile_id ) || ! $platform_access ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';

		if ( empty( $type ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
		}

		$response            = array();
		$response['markup']  = array();
		$response['message'] = esc_html__( 'Account setting update successfully.', 'gigneo' );

		//Trigger Email
		$wc_mailer = WC()->mailer();
		$wc_emails = $wc_mailer->get_emails();

		//Profile IDs
		$freelancer_profile_id = get_user_meta( $current_user->ID, '_gigneo_um_freelancer_profile_id', true );
		$employer_profile_id   = get_user_meta( $current_user->ID, '_gigneo_um_employer_profile_id', true );

		//User Info
		if ( 'user_info' === $type ) {
			$first_name        = isset( $_POST['first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['first_name'] ) ) : '';
			$last_name         = isset( $_POST['last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['last_name'] ) ) : '';
			$nickname          = isset( $_POST['nickname'] ) ? sanitize_text_field( wp_unslash( $_POST['nickname'] ) ) : '';
			$display_name      = isset( $_POST['display_name'] ) ? sanitize_text_field( wp_unslash( $_POST['display_name'] ) ) : '';
			$biographical_info = isset( $_POST['biographical_info'] ) ? sanitize_textarea_field( wp_unslash( $_POST['biographical_info'] ) ) : '';

			if ( empty( $first_name ) || empty( $last_name || empty( $nickname ) ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$fields = array(
				'first_name'   => $first_name,
				'last_name'    => $last_name,
				'nickname'     => $nickname,
				'display_name' => $display_name,
				'description'  => $biographical_info,
			);

			/*
			 * wp_update_user() is used here to save profile fields (name, nickname,
			 * display name, bio) for the currently logged-in user only. The user ID
			 * is sourced from wp_get_current_user() — never from user input — so
			 * there is no risk of updating another user's account. All field values
			 * are sanitized before being passed to this function.
			 */
			foreach ( $fields as $key => $value ) {
				wp_update_user(
					array(
						'ID' => $current_user->ID,
						$key => $value,
					)
				);
			}

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/account/user-info' );
			$user_info_markup = ob_get_clean();

			$response['markup']['user-info'] = $user_info_markup;
			wp_send_json_success( $response, 200 );
		}

		//Online Status
		if ( 'online_status' === $type ) {
			$offline_for = isset( $_POST['offline_for'] ) ? sanitize_text_field( wp_unslash( $_POST['offline_for'] ) ) : '';

			if ( empty( $offline_for ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			$offline_until = match ( $offline_for ) {
				'hour' => strtotime( '+1 hour' ),
				'week' => strtotime( '+1 week' ),
				'month' => strtotime( '+1 month' ),
				'forever' => 'forever',
				default => '',
			};

			if ( ! empty( $offline_until ) ) {
				update_post_meta( $profile_id, '_gigneo_pm_offline_until', $offline_until );
			} else {
				delete_post_meta( $profile_id, '_gigneo_pm_offline_until' );
			}

			ob_start();
			gigneo_load_template( 'dashboard/setting/parts/account/online-status' );
			$online_status_markup = ob_get_clean();

			$response['markup']['online-status'] = $online_status_markup;
			wp_send_json_success( $response, 200 );
		}

		//Timezone
		if ( 'timezone' === $type ) {
			$response = apply_filters(
				'gigneo_save_timezone_setting',
				$response,
				array(
					'timezone' => isset( $_POST['timezone'] ) ? sanitize_text_field( wp_unslash( $_POST['timezone'] ) ) : '',
				),
				$current_user
			);
			if ( ! empty( $response['markup']['timezone'] ) ) {
				wp_send_json_success( $response, 200 );
			}
		}

		//Deactivate Account
		if ( 'deactivate_account' === $type ) {

			$deactivation_reason = isset( $_POST['deactivation_reason'] ) ? sanitize_text_field( wp_unslash( $_POST['deactivation_reason'] ) ) : '';
			$deactivation_detail = isset( $_POST['deactivation_detail'] ) ? sanitize_textarea_field( wp_unslash( $_POST['deactivation_detail'] ) ) : '';

			if ( empty( $deactivation_reason ) || empty( $deactivation_detail ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			if ( ! empty( $freelancer_profile_id ) ) {
				$updated = wp_update_post(
					array(
						'ID'          => $freelancer_profile_id,
						'post_status' => 'deactivated',
					)
				);
				if ( is_wp_error( $updated ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to deactivate account. Please try again.', 'gigneo' ) ), 500 );
				}
			}

			if ( ! empty( $employer_profile_id ) ) {
				$updated = wp_update_post(
					array(
						'ID'          => $employer_profile_id,
						'post_status' => 'deactivated',
					)
				);
				if ( is_wp_error( $updated ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to deactivate account. Please try again.', 'gigneo' ) ), 500 );
				}
			}

			$deactivation_info = array(
				'reason' => $deactivation_reason,
				'detail' => $deactivation_detail,
			);

			update_user_meta( $profile_id, '_gigneo_um_account_deactivation_info', $deactivation_info );

			if ( in_array( 'deactivate_account', gigneo_active_modules(), true ) ) {
				$wc_emails['Gigneo_Account_Deactivated']->trigger( $current_user->ID );
			}

			wp_logout();

			$response             = array();
			$response['redirect'] = site_url( '/' );
			$response['message']  = esc_html__( 'Account deactivated successfully.', 'gigneo' );

			wp_send_json_success( $response, 200 );
		}

		//Activate Account
		if ( 'activate_account' === $type ) {

			if ( ! empty( $freelancer_profile_id ) ) {
				$updated = wp_update_post(
					array(
						'ID'          => $freelancer_profile_id,
						'post_status' => 'publish',
					)
				);
				if ( is_wp_error( $updated ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to deactivate account. Please try again.', 'gigneo' ) ), 500 );
				}
			}

			if ( ! empty( $employer_profile_id ) ) {
				$updated = wp_update_post(
					array(
						'ID'          => $employer_profile_id,
						'post_status' => 'publish',
					)
				);
				if ( is_wp_error( $updated ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to deactivate account. Please try again.', 'gigneo' ) ), 500 );
				}
			}

			delete_user_meta( $current_user->ID, '_gigneo_um_account_deactivation_info' );

			if ( in_array( 'deactivate_account', gigneo_active_modules(), true ) ) {
				$wc_emails['Gigneo_Account_Activated']->trigger( $current_user->ID );
			}

			$response             = array();
			$response['redirect'] = gigneo_dashboard_url( 'setting', 'account ' );
			$response['message']  = esc_html__( 'Account activated successfully.', 'gigneo' );

			wp_send_json_success( $response, 200 );
		}

		//Remove Account
		if ( 'close_account' === $type ) {

			$close_reason = isset( $_POST['close_reason'] ) ? sanitize_text_field( wp_unslash( $_POST['close_reason'] ) ) : '';
			$close_detail = isset( $_POST['close_detail'] ) ? sanitize_textarea_field( wp_unslash( $_POST['close_detail'] ) ) : '';

			if ( empty( $close_reason ) || empty( $close_detail ) ) {
				wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
			}

			if ( ! empty( $freelancer_profile_id ) ) {
				$updated = wp_update_post(
					array(
						'ID'          => $freelancer_profile_id,
						'post_status' => 'closed',
					)
				);
				if ( is_wp_error( $updated ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to deactivate account. Please try again.', 'gigneo' ) ), 500 );
				}
			}

			if ( ! empty( $employer_profile_id ) ) {
				$updated = wp_update_post(
					array(
						'ID'          => $employer_profile_id,
						'post_status' => 'closed',
					)
				);
				if ( is_wp_error( $updated ) ) {
					wp_send_json_error( array( 'message' => esc_html__( 'Failed to deactivate account. Please try again.', 'gigneo' ) ), 500 );
				}
			}

			$close_info = array(
				'reason' => $close_reason,
				'detail' => $close_detail,
			);

			update_user_meta( $current_user->ID, '_gigneo_um_account_closed_info', $close_info );

			if ( in_array( 'close_account', gigneo_active_modules(), true ) ) {
				$wc_emails['Gigneo_Account_Closed']->trigger( $current_user->ID );
			}

			wp_logout();

			$response             = array();
			$response['redirect'] = site_url( '/' );
			$response['message']  = esc_html__( 'Account closed successfully.', 'gigneo' );

			wp_send_json_success( $response, 200 );
		}

		$response             = array();
		$response['redirect'] = site_url( '/' );
		$response['message']  = esc_html__( 'Account closed successfully.', 'gigneo' );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle account notification updates.
	 *
	 * @since 0.0.1
	 */
	public function account_notifications() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || empty( $profile_id ) || ! $platform_access ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$type  = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : '';
		$value = isset( $_POST['value'] ) ? sanitize_text_field( wp_unslash( $_POST['value'] ) ) : '';

		if ( empty( $type ) || empty( $value ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 400 );
		}
		$allowed_types = apply_filters( 'gigneo_account_notifications_allowed_types', array( 'order', 'chat', 'service', 'job', 'wallet', 'withdraw', 'account' ) );
		if ( ! in_array( $type, $allowed_types, true ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid notification type.', 'gigneo' ) ), 403 );
		}

		$status = ( 'yes' === $value );

		if ( $status ) {
			delete_post_meta( $profile_id, "_gigneo_pm_notification_$type" );
		} else {
			update_post_meta( $profile_id, "_gigneo_pm_notification_$type", 'no' );
		}

		wp_send_json_success( array( 'message' => esc_html__( 'Notification setting updated successfully.', 'gigneo' ) ), 200 );
	}

	/**
	 * Handle billing address updates.
	 *
	 * @since 0.0.1
	 */
	public function save_billing_address() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || empty( $profile_id ) || ! $platform_access ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$response            = array();
		$response['message'] = esc_html__( 'Billing address update successfully.', 'gigneo' );

		$first_name    = isset( $_POST['billing_first_name'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_first_name'] ) ) : '';
		$last_name     = isset( $_POST['billing_last_name'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_last_name'] ) ) : '';
		$email         = isset( $_POST['billing_email'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_email'] ) ) : '';
		$phone         = isset( $_POST['billing_phone'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_phone'] ) ) : '';
		$postcode      = isset( $_POST['billing_postcode'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_postcode'] ) ) : '';
		$country_state = isset( $_POST['billing_country_state'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_country_state'] ) ) : '';
		$city          = isset( $_POST['billing_city'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_city'] ) ) : '';
		$address       = isset( $_POST['billing_address'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_address'] ) ) : '';

		if ( empty( $first_name ) || empty( $last_name ) || empty( $email ) || empty( $postcode ) || empty( $country_state ) || empty( $city ) || empty( $address ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
		}

		$country_state = explode( ':', $country_state );
		$country       = ! empty( $country_state[0] ) ? $country_state[0] : $country_state;
		$state         = ! empty( $country_state[1] ) ? $country_state[1] : '';

		update_user_meta( $current_user->ID, 'billing_first_name', $first_name );
		update_user_meta( $current_user->ID, 'billing_last_name', $last_name );
		update_user_meta( $current_user->ID, 'billing_email', $email );
		update_user_meta( $current_user->ID, 'billing_phone', $phone );
		update_user_meta( $current_user->ID, 'billing_postcode', $postcode );
		update_user_meta( $current_user->ID, 'billing_country', $country );
		update_user_meta( $current_user->ID, 'billing_state', $state );
		update_user_meta( $current_user->ID, 'billing_city', $city );
		update_user_meta( $current_user->ID, 'billing_address_1', $address );

		ob_start();
		gigneo_load_template( 'dashboard/setting/parts/billing/address' );
		$billing_address_markup = ob_get_clean();

		$response['markup']['address'] = $billing_address_markup;

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle account password updates.
	 *
	 * @since 0.0.1
	 */
	public function update_account_password() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$current_password = isset( $_POST['current_password'] ) ? sanitize_text_field( wp_unslash( $_POST['current_password'] ) ) : '';
		$new_password     = isset( $_POST['new_password'] ) ? sanitize_text_field( wp_unslash( $_POST['new_password'] ) ) : '';

		if ( empty( $current_password ) || empty( $new_password ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Required fields could not be empty.', 'gigneo' ) ), 403 );
		}

		// Password validation
		$password_strength_options = gigneo_password_strength_options();
		$password_validation       = gigneo_option( '_gigneo_ts_password_strength', array( 'length' ) );

		$rules = array(
			'length'    => fn( $p ) => strlen( $p ) < 8,
			'uppercase' => fn( $p ) => ! preg_match( '/[A-Z]/', $p ),
			'lowercase' => fn( $p ) => ! preg_match( '/[a-z]/', $p ),
			'number'    => fn( $p ) => ! preg_match( '/[0-9]/', $p ),
			'special'   => fn( $p ) => ! preg_match( '/[^a-zA-Z0-9]/', $p ),
		);

		foreach ( $password_validation as $rule ) {
			if ( isset( $rules[ $rule ] ) && $rules[ $rule ]( $new_password ) ) {
				wp_send_json_error( array( 'message' => $password_strength_options[ $rule ] ), 403 );
			}
		}

		$user = wp_get_current_user();

		if ( ! wp_check_password( $current_password, $user->user_pass, $user->ID ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Incorrect current password.', 'gigneo' ) ), 403 );
		}

		/*
		 * wp_update_user() is used here to update the password of the currently
		 * logged-in user only. The user object is sourced from wp_get_current_user()
		 * and the current password is verified via wp_check_password() before any
		 * update is performed. The new password passes all configured strength rules.
		 * This follows the WordPress-recommended approach for password changes.
		 */
		wp_update_user(
			array(
				'ID'        => $user->ID,
				'user_pass' => $new_password,
			)
		);

		$response            = array();
		$response['message'] = esc_html__( 'Update password successfully.', 'gigneo' );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle notice dismiss requests.
	 *
	 * @since 0.0.1
	 */
	public function notice_dismiss() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

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

		if ( empty( $notice_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid notice.', 'gigneo' ) ), 400 );
		}

		$all_notices = gigneo_register_notice();

		if ( ! isset( $all_notices[ $notice_id ] ) || empty( $all_notices[ $notice_id ]['dismissible'] ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid notice.', 'gigneo' ) ), 400 );
		}

		update_post_meta( $profile_id, '_gigneo_notice_dismissed_' . $notice_id, true );

		$response            = array();
		$response['message'] = esc_html__( 'Notice dismissed successfully.', 'gigneo' );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle session deletion requests.
	 *
	 * @since 0.0.1
	 */
	public function delete_session() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$platform_access = gigneo_user_have_access();
		$profile_id      = gigneo_active_profile_id();
		$current_user    = wp_get_current_user();

		if ( empty( $current_user->ID ) || ! $platform_access || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to do that.', 'gigneo' ) ), 403 );
		}

		$token    = isset( $_POST['id'] ) ? sanitize_text_field( wp_unslash( $_POST['id'] ) ) : '';
		$sessions = get_user_meta( $current_user->ID, 'session_tokens', true );

		if ( empty( $token ) || ! isset( $sessions[ $token ] ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		unset( $sessions[ $token ] );

		update_user_meta( $current_user->ID, 'session_tokens', $sessions );

		ob_start();
		gigneo_load_template( 'dashboard/setting/parts/security/sessions' );
		$payouts_markup = ob_get_clean();

		$response                       = array();
		$response['markup']['sessions'] = $payouts_markup;
		$response['message']            = esc_html__( 'Session removed successfully.', 'gigneo' );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle saving/removing items (freelancer, service, employer, job) to user's saved list.
	 *
	 * @since 0.0.1
	 */
	public function gigneo_save_item() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$post_id = isset( $_POST['id'] ) ? absint( $_POST['id'] ) : 0;

		if ( empty( $post_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		$profile_id   = gigneo_active_profile_id();
		$profile_type = gigneo_profile_type( $profile_id );
		$post_type    = get_post_type( $post_id );

		if ( empty( $profile_id ) || empty( $post_type ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Something went wrong.', 'gigneo' ) ), 403 );
		}

		// Normalize post type (remove 'gigneo_' prefix if present)
		$post_type_slug = str_starts_with( $post_type, 'gigneo_' ) ? substr( $post_type, 7 ) : $post_type;

		// Define allowed save actions per profile type
		$allowed_mappings = array(
			'employer'   => array( 'freelancer', 'service' ),
			'freelancer' => array( 'employer', 'job' ),
		);

		if (
			empty( $allowed_mappings[ $profile_type ] ) ||
			! in_array( $post_type_slug, $allowed_mappings[ $profile_type ], true )
		) {
			wp_send_json_error( array( 'message' => esc_html__( 'You are not allowed to save this item.', 'gigneo' ) ), 403 );
		}

		// Additional restriction for private employer profiles
		if ( 'employer' === $post_type_slug && 'private' === gigneo_employer_profile_access() ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You are not allowed to save this item.', 'gigneo' ) ), 403 );
		}

		// 2. Process Save / Unsave Logic
		$meta_key = "_gigneo_pm_saved_$post_type_slug";
		$saved    = (array) gigneo_post_meta( $profile_id, $meta_key );

		$is_already_saved = in_array( $post_id, $saved, true );

		if ( $is_already_saved ) {
			// Remove from saved list
			$saved   = array_values( array_diff( $saved, array( $post_id ) ) );
			$status  = 'removed';
			$message = esc_html__( 'Removed from your saved list.', 'gigneo' );
		} else {
			// Add to saved list
			$saved[] = $post_id;
			$status  = 'added';
			$message = esc_html__( 'Added to your saved list.', 'gigneo' );
		}

		// Update meta (ensure clean indexed array)
		update_post_meta( $profile_id, $meta_key, array_values( $saved ) );

		wp_send_json_success(
			array(
				'status'  => $status,
				'message' => $message,
			),
			200
		);
	}

	/**
	 * Sanitize filter parameters.
	 *
	 * @since 0.0.1
	 */
	private function sanitize_filter_params( $params ) {
		$sanitized = array();

		foreach ( $params as $key => $value ) {
			$key = sanitize_text_field( $key );
			if ( is_array( $value ) ) {
				$sanitized[ $key ] = array_map( 'sanitize_text_field', $value );
			} else {
				$sanitized[ $key ] = sanitize_text_field( $value );
			}
		}

		return $sanitized;
	}

	/**
	 * Build service query arguments.
	 *
	 * @since 0.0.1
	 */
	private function build_service_query( $args, $shortcode_options = array() ) {

		$search         = ! empty( $args['search'] ) ? sanitize_text_field( $args['search'] ) : '';
		$location       = ! empty( $args['location'] ) ? sanitize_text_field( $args['location'] ) : '';
		$category       = ! empty( $args['category'] ) ? sanitize_text_field( $args['category'] ) : '';
		$sub_category   = ! empty( $args['subcategory'] ) ? sanitize_text_field( $args['subcategory'] ) : '';
		$specific_types = ! empty( $args['specific_types'] ) ? array_map( 'sanitize_text_field', (array) $args['specific_types'] ) : array();
		$skills         = ! empty( $args['skills'] ) ? array_map( 'sanitize_text_field', (array) $args['skills'] ) : array();
		$min_price      = ! empty( $args['min_price'] ) && '' !== $args['min_price'] ? floatval( $args['min_price'] ) : '';
		$max_price      = ! empty( $args['max_price'] ) && '' !== $args['max_price'] ? floatval( $args['max_price'] ) : '';
		$types          = ! empty( $args['type'] ) ? array_map( 'sanitize_text_field', (array) $args['type'] ) : array();
		$delivery       = ! empty( $args['delivery'] ) ? array_map( 'sanitize_text_field', (array) $args['delivery'] ) : array();
		$sort           = ! empty( $args['sort'] ) ? sanitize_text_field( $args['sort'] ) : 'recommended';
		$rating         = ! empty( $args['rating'] ) && '' !== $args['rating'] ? absint( $args['rating'] ) : '';
		$step           = ! empty( $args['step'] ) ? max( 1, absint( $args['step'] ) ) : 1;
		$featured       = ! empty( $args['featured'] );
		$verified       = ! empty( $args['verified'] );

		$posts_per_page = gigneo_option( '_gigneo_ts_services_per_page', 9 );
		$posts_per_page = apply_filters( 'gigneo_build_service_query_posts_per_page', $posts_per_page );
		$posts_per_page = ! empty( $shortcode_options['per_page'] ) ? absint( $shortcode_options['per_page'] ) : $posts_per_page;

		// Query args.
		$service_args = array(
			'post_type'      => 'gigneo_service',
			'posts_per_page' => $posts_per_page,
			'paged'          => $step,
			's'              => $search,
			'post_status'    => 'publish',
		);

		// Tax query.
		$tax_query = array( 'relation' => 'AND' );

		if ( ! empty( $category ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_facet',
				'field'    => 'slug',
				'terms'    => $category,
			);
		}

		if ( ! empty( $sub_category ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_facet',
				'field'    => 'slug',
				'terms'    => $sub_category,
			);
		}

		if ( ! empty( $specific_types ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_facet',
				'field'    => 'slug',
				'terms'    => $specific_types,
				'operator' => 'IN',
			);
		}

		if ( ! empty( $skills ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_skill',
				'field'    => 'slug',
				'terms'    => $skills,
				'operator' => 'IN',
			);
		}

		if ( count( $tax_query ) > 1 ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
			$service_args['tax_query'] = $tax_query;
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
		}

		// Meta query.
		$meta_query = array( 'relation' => 'AND' );

		if ( ! empty( $location ) ) {
			$meta_query[] = array(
				'key'     => 'carbon_fields:_gigneo_pm_locations',
				'value'   => '"' . $location . '"',
				'compare' => 'LIKE',
			);
		}

		if ( '' !== $min_price && floatval( $min_price ) > 0 ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_price_plan_one_price',
				'value'   => $min_price,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		if ( '' !== $max_price && floatval( $max_price ) < 10000 ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_price_plan_one_price',
				'value'   => $max_price,
				'compare' => '<=',
				'type'    => 'NUMERIC',
			);
		}

		if ( ! empty( $types ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_type',
				'value'   => $types,
				'compare' => 'IN',
			);
		}

		if ( ! empty( $delivery ) ) {
			$meta_query[] = array(
				'relation' => 'OR',
				array(
					'key'     => '_gigneo_pm_delivery_type',
					'value'   => $delivery,
					'compare' => 'IN',
				),
				array(
					'key'     => '_gigneo_pm_delivery_type',
					'value'   => 'both',
					'compare' => '=',
				),
			);
		}

		if ( $featured ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_featured',
				'value'   => true,
				'compare' => '=',
			);
		}

		// Verified.
		if ( $verified ) {
			$verified_users             = gigneo_verified_users( 'freelancer' );
			$service_args['author__in'] = ! empty( $verified_users ) ? $verified_users : array();
		}

		if ( ! empty( $rating ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_average_rating',
				'value'   => $rating,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		if ( count( $meta_query ) > 1 ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
			$service_args['meta_query'] = $meta_query;
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
		}

		// Sorting.
		switch ( $sort ) {
			case 'recommended':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$service_args['meta_key'] = '_gigneo_pm_total_completed_order';
				$service_args['orderby']  = 'meta_value_num';
				$service_args['order']    = 'DESC';
				break;
			case 'top_rated':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$service_args['meta_key'] = '_gigneo_pm_average_rating';
				$service_args['orderby']  = 'meta_value_num';
				$service_args['order']    = 'DESC';
				break;
			case 'price_low_to_high':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$service_args['meta_key'] = '_gigneo_pm_price_plan_one_price';
				$service_args['orderby']  = 'meta_value_num';
				$service_args['order']    = 'ASC';
				break;
			case 'price_high_to_low':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$service_args['meta_key'] = '_gigneo_pm_price_plan_one_price';
				$service_args['orderby']  = 'meta_value_num';
				$service_args['order']    = 'DESC';
				break;
		}

		$service_args = apply_filters( 'gigneo_build_service_query_before', $service_args, $args, $shortcode_options );

		$service_query = new WP_Query( $service_args );

		$result = array(
			'query'            => $service_query,
			'step'             => $step ?? 1,
			'geo_filtered_ids' => array(),
			'geo_filtering'    => false,
			'search_lat'       => 0,
			'search_lng'       => 0,
			'distance_type'    => 'kilometers',
			'map_radius'       => '',
		);

		return apply_filters( 'gigneo_build_service_query_after', $result, $args, $shortcode_options );
	}

	/**
	 * Build freelancer query arguments.
	 *
	 * @since 0.0.1
	 */
	private function build_freelancer_query( $args, $shortcode_options = array() ) {

		$search           = ! empty( $args['search'] ) ? sanitize_text_field( $args['search'] ) : '';
		$location         = ! empty( $args['location'] ) ? sanitize_text_field( $args['location'] ) : '';
		$categories       = ! empty( $args['categories'] ) ? array_map( 'sanitize_text_field', (array) $args['categories'] ) : array();
		$skills           = ! empty( $args['skills'] ) ? array_map( 'sanitize_text_field', (array) $args['skills'] ) : array();
		$rating           = ! empty( $args['rating'] ) && '' !== $args['rating'] ? absint( $args['rating'] ) : '';
		$orders_completed = ! empty( $args['orders_completed'] ) && '' !== $args['orders_completed'] ? absint( $args['orders_completed'] ) : '';
		$sort             = ! empty( $args['sort'] ) ? sanitize_text_field( $args['sort'] ) : '';
		$online           = ! empty( $args['online'] ) ? sanitize_text_field( $args['online'] ) : '';
		$verified         = ! empty( $args['verified'] ) ? sanitize_text_field( $args['verified'] ) : '';
		$step             = ! empty( $args['step'] ) ? max( 1, absint( $args['step'] ) ) : 1;
		$posts_per_page   = gigneo_option( '_gigneo_ts_freelancers_per_page', 9 );
		$posts_per_page   = apply_filters( 'gigneo_build_freelancer_query_posts_per_page', $posts_per_page );
		$posts_per_page   = ! empty( $shortcode_options['per_page'] ) ? absint( $shortcode_options['per_page'] ) : $posts_per_page;

		$freelancer_args = array(
			'post_type'      => 'gigneo_freelancer',
			'posts_per_page' => $posts_per_page,
			'paged'          => $step,
			's'              => $search,
			'post_status'    => 'publish',
		);

		$meta_query = array( 'relation' => 'AND' );

		// Visibility Conditions
		$profile_conditions = gigneo_option( '_gigneo_ts_freelancer_visibility_conditions' );
		$profile_conditions = ! empty( $profile_conditions ) && is_array( $profile_conditions ) ? $profile_conditions : array();

		if ( in_array( 'profile_image', $profile_conditions, true ) ) {
			$meta_query[] = array(
				'key'     => '_thumbnail_id',
				'compare' => 'EXISTS',
			);
		}

		$author_in = array();

		if ( in_array( 'email_verified', $profile_conditions, true ) && in_array( 'email_verification', gigneo_active_modules(), true ) ) {
			$verified_users = gigneo_email_verified_users( 'freelancer' );
			$author_in      = ! empty( $verified_users ) ? $verified_users : array();
		}

		if ( ! empty( $author_in ) ) {
			$freelancer_args['author__in'] = $author_in;
		}

		if ( ! empty( $location ) ) {
			if ( str_contains( $location, ':' ) ) {
				$meta_query[] = array(
					'key'     => '_gigneo_pm_country_state',
					'value'   => $location,
					'compare' => '=',
				);
			} else {
				$meta_query[] = array(
					'relation' => 'OR',
					array(
						'key'     => '_gigneo_pm_country_state',
						'value'   => $location . ':',
						'compare' => 'LIKE',
					),
					array(
						'key'     => '_gigneo_pm_city',
						'value'   => $location,
						'compare' => '=',
					),
				);
			}
		}

		// Category
		if ( ! empty( $categories ) ) {
			$categories_meta = array( 'relation' => 'OR' );

			foreach ( $categories as $category_slug ) {
				$categories_meta[] = array(
					'key'     => 'carbon_fields:_gigneo_pm_categories',
					'value'   => '"' . $category_slug . '"',
					'compare' => 'LIKE',
				);
			}

			$meta_query[] = $categories_meta;
		}

		// Skills
		if ( ! empty( $skills ) ) {
			$skills_meta = array( 'relation' => 'OR' );

			foreach ( $skills as $skill_slug ) {
				$skills_meta[] = array(
					'key'     => 'carbon_fields:_gigneo_pm_skills',
					'value'   => '"' . $skill_slug . '"',
					'compare' => 'LIKE',
				);
			}

			$meta_query[] = $skills_meta;
		}

		// Rating
		if ( ! empty( $rating ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_average_rating',
				'value'   => $rating,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		// Orders completed
		if ( ! empty( $orders_completed ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_orders_completed',
				'value'   => $orders_completed,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		// Verified
		if ( ! empty( $verified ) ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_post__in
			$freelancer_args['post__in'] = gigneo_verified_profiles( 'freelancer' );
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_post__in
		}

		// Online
		if ( ! empty( $online ) ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_post__in
			$freelancer_args['post__in'] = gigneo_online_profiles( 'freelancer' );
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_post__in
		}

		// Attach meta_query only if filters exist
		if ( count( $meta_query ) > 1 ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
			$freelancer_args['meta_query'] = $meta_query;
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
		}

		// Sorting
		switch ( $sort ) {

			case 'recommended':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$freelancer_args['meta_key'] = '_gigneo_pm_orders_completed';
				$freelancer_args['orderby']  = 'meta_value_num';
				break;

			case 'top_rated':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$freelancer_args['meta_key'] = '_gigneo_pm_average_rating';
				$freelancer_args['orderby']  = 'meta_value_num';
				break;

			default:
				$freelancer_args['orderby'] = 'date';
				break;
		}

		$freelancer_args = apply_filters( 'gigneo_build_freelancer_query_before', $freelancer_args, $args, $shortcode_options );

		$freelancer_query = new WP_Query( $freelancer_args );

		$result = array(
			'query'            => $freelancer_query,
			'step'             => $step,
			'geo_filtered_ids' => array(),
			'geo_filtering'    => false,
			'search_lat'       => 0,
			'search_lng'       => 0,
			'distance_type'    => 'kilometers',
			'map_radius'       => '',
		);

		return apply_filters( 'gigneo_build_freelancer_query_after', $result, $args, $shortcode_options );
	}

	/**
	 * Build employer query arguments.
	 *
	 * @since 0.0.1
	 */
	private function build_employer_query( $args, $shortcode_options = array() ) {

		$search           = ! empty( $args['search'] ) ? sanitize_text_field( $args['search'] ) : '';
		$location         = ! empty( $args['location'] ) ? sanitize_text_field( $args['location'] ) : '';
		$categories       = ! empty( $args['categories'] ) ? array_map( 'sanitize_text_field', (array) $args['categories'] ) : array();
		$skills           = ! empty( $args['skills'] ) ? array_map( 'sanitize_text_field', (array) $args['skills'] ) : array();
		$rating           = ! empty( $args['rating'] ) && '' !== $args['rating'] ? absint( $args['rating'] ) : '';
		$orders_completed = ! empty( $args['orders_completed'] ) && '' !== $args['orders_completed'] ? absint( $args['orders_completed'] ) : '';
		$sort             = ! empty( $args['sort'] ) ? sanitize_text_field( $args['sort'] ) : '';
		$online           = ! empty( $args['online'] ) ? sanitize_text_field( $args['online'] ) : '';
		$verified         = ! empty( $args['verified'] ) ? sanitize_text_field( $args['verified'] ) : '';
		$step             = ! empty( $args['step'] ) ? max( 1, absint( $args['step'] ) ) : 1;

		$posts_per_page = gigneo_option( '_gigneo_ts_employers_per_page', 9 );
		$posts_per_page = apply_filters( 'gigneo_build_employer_query_posts_per_page', $posts_per_page );
		$posts_per_page = ! empty( $shortcode_options['per_page'] ) ? absint( $shortcode_options['per_page'] ) : $posts_per_page;

		$employer_args = array(
			'post_type'      => 'gigneo_employer',
			'posts_per_page' => $posts_per_page,
			'paged'          => $step,
			's'              => $search,
			'post_status'    => 'publish',
		);

		$meta_query = array( 'relation' => 'AND' );

		// Visibility Conditions
		$profile_conditions = gigneo_option( '_gigneo_ts_employer_visibility_conditions' );
		$profile_conditions = ! empty( $profile_conditions ) && is_array( $profile_conditions ) ? $profile_conditions : array();

		if ( in_array( 'profile_image', $profile_conditions, true ) ) {
			$meta_query[] = array(
				'key'     => '_thumbnail_id',
				'compare' => 'EXISTS',
			);
		}

		$author_in = array();

		if ( in_array( 'email_verified', $profile_conditions, true ) && in_array( 'email_verification', gigneo_active_modules(), true ) ) {
			$verified_users = gigneo_email_verified_users( 'employer' );
			$author_in      = ! empty( $verified_users ) ? $verified_users : array();
		}

		if ( ! empty( $author_in ) ) {
			$employer_args['author__in'] = $author_in;
		}

		if ( ! empty( $location ) ) {
			if ( str_contains( $location, ':' ) ) {
				$meta_query[] = array(
					'key'     => '_gigneo_pm_country_state',
					'value'   => $location,
					'compare' => '=',
				);
			} else {
				$meta_query[] = array(
					'relation' => 'OR',
					array(
						'key'     => '_gigneo_pm_country_state',
						'value'   => $location . ':',
						'compare' => 'LIKE',
					),
					array(
						'key'     => '_gigneo_pm_city',
						'value'   => $location,
						'compare' => '=',
					),
				);
			}
		}

		// Category
		if ( ! empty( $categories ) ) {
			$categories_meta = array( 'relation' => 'OR' );

			foreach ( $categories as $category_slug ) {
				$categories_meta[] = array(
					'key'     => 'carbon_fields:_gigneo_pm_categories',
					'value'   => '"' . $category_slug . '"',
					'compare' => 'LIKE',
				);
			}

			$meta_query[] = $categories_meta;
		}

		// Skills
		if ( ! empty( $skills ) ) {
			$skills_meta = array( 'relation' => 'OR' );

			foreach ( $skills as $skill_slug ) {
				$skills_meta[] = array(
					'key'     => 'carbon_fields:_gigneo_pm_skills',
					'value'   => '"' . $skill_slug . '"',
					'compare' => 'LIKE',
				);
			}

			$meta_query[] = $skills_meta;
		}

		// Rating
		if ( ! empty( $rating ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_average_rating',
				'value'   => $rating,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		// Orders completed
		if ( ! empty( $orders_completed ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_orders_completed',
				'value'   => $orders_completed,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		//Verified
		if ( ! empty( $verified ) ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_post__in
			$employer_args['post__in'] = gigneo_verified_profiles( 'employer' );
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_post__in
		}

		//Online
		if ( ! empty( $online ) ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_post__in
			$employer_args['post__in'] = gigneo_online_profiles( 'employer' );
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_post__in
		}

		// Attach meta_query only if filters exist
		if ( count( $meta_query ) > 1 ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
			$employer_args['meta_query'] = $meta_query;
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
		}
		// Sorting
		switch ( $sort ) {

			case 'recommended':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$employer_args['meta_key'] = '_gigneo_pm_orders_completed';
				$employer_args['orderby']  = 'meta_value_num';
				break;

			case 'top_rated':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$employer_args['meta_key'] = '_gigneo_pm_average_rating';
				$employer_args['orderby']  = 'meta_value_num';
				break;

			default:
				$employer_args['orderby'] = 'date';
				break;
		}

		$employer_args = apply_filters( 'gigneo_build_employer_query_before', $employer_args, $args, $shortcode_options );

		$employer_query = new WP_Query( $employer_args );

		$result = array(
			'query'            => $employer_query,
			'step'             => $step,
			'geo_filtered_ids' => array(),
			'geo_filtering'    => false,
			'search_lat'       => 0,
			'search_lng'       => 0,
			'distance_type'    => 'kilometers',
			'map_radius'       => '',
		);

		return apply_filters( 'gigneo_build_employer_query_after', $result, $args, $shortcode_options );
	}

	/**
	 * Handle service filtering requests.
	 *
	 * @since 0.0.1
	 */
	public function filter_services() {

		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$params = isset( $_POST['params'] ) ? map_deep( wp_unslash( (array) $_POST['params'] ), 'sanitize_text_field' ) : array();
		$params = $this->sanitize_filter_params( $params );
		// Recompute current_url correctly for the template from the base referrer + current params
		$base_url              = remove_query_arg( array_keys( $params ), wp_get_referer() );
		$params['current_url'] = add_query_arg( $params, $base_url );
		$shortcode_options     = isset( $_POST['shortcode_options'] ) ? map_deep( wp_unslash( (array) $_POST['shortcode_options'] ), 'sanitize_text_field' ) : array();
		$data                  = $this->build_service_query( $params, $shortcode_options );
		$query                 = $data['query'];

		// Check map status before the loop.

		// Single loop: render cards + collect map data.
		ob_start();
		if ( $query->have_posts() ) {
			$active_profile_id   = gigneo_active_profile_id();
			$active_profile_type = gigneo_profile_type( $active_profile_id );
			$country_state_list  = gigneo_countries_with_states( 'active' );
			$saved_items         = gigneo_post_meta( $active_profile_id, '_gigneo_pm_saved_service' );

			$item_args = array(
				'profile_id'         => $active_profile_id,
				'profile_type'       => $active_profile_type,
				'country_state_list' => $country_state_list,
				'saved'              => $saved_items,
			);

			while ( $query->have_posts() ) {
				$query->the_post();
				$service_id = get_the_ID();
				gigneo_load_template( 'archive/service/parts/card-layout-1', false, $item_args );

			}
			wp_reset_postdata();
		} else {
			gigneo_not_found( 'service_archive' );
		}
		$cards_html = ob_get_clean();

		// Render pagination.
		ob_start();
		gigneo_pagination( $query, $data['step'], 'gn-pagination-wrapper' );
		$pagination_html = ob_get_clean();

		// Render active pills.
		ob_start();
		gigneo_load_template( 'archive/service/parts/filter-pills', false, $params );
		$pills_html = ob_get_clean();

		// Result count.
		$result_count = $query->found_posts ?? 0;

		$response = array(
			'cards'        => $cards_html,
			'pagination'   => $pagination_html,
			'pills'        => $pills_html,
			'result_count' => $result_count,
		);

		$response = apply_filters( 'gigneo_filter_services_after', $response, $query, $data, $params );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle freelancer filtering requests.
	 *
	 * @since 0.0.1
	 */
	public function filter_freelancers() {

		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$params = isset( $_POST['params'] ) ? map_deep( wp_unslash( (array) $_POST['params'] ), 'sanitize_text_field' ) : array();
		$params = $this->sanitize_filter_params( $params );

		$base_url              = remove_query_arg( array_keys( $params ), wp_get_referer() );
		$params['current_url'] = add_query_arg( $params, $base_url );
		$shortcode_options     = isset( $_POST['shortcode_options'] ) ? map_deep( wp_unslash( (array) $_POST['shortcode_options'] ), 'sanitize_text_field' ) : array();
		$data                  = $this->build_freelancer_query( $params, $shortcode_options );
		$query                 = $data['query'];

		// Check map status before the loop.

		ob_start();
		if ( $query->have_posts() ) {

			$active_profile_id   = gigneo_active_profile_id();
			$active_profile_type = gigneo_profile_type( $active_profile_id );
			$country_state_list  = gigneo_countries_with_states( 'active' );
			$saved_items         = gigneo_post_meta( $active_profile_id, '_gigneo_pm_saved_freelancer' );

			$item_args = array(
				'profile_id'         => $active_profile_id,
				'profile_type'       => $active_profile_type,
				'country_state_list' => $country_state_list,
				'saved'              => $saved_items,
			);

			while ( $query->have_posts() ) {
				$query->the_post();
				gigneo_load_template( 'archive/freelancer/parts/card-layout-1', false, $item_args );

			}
			wp_reset_postdata();
		} else {
			gigneo_not_found( 'freelancer_archive' );
		}

		$cards_html = ob_get_clean();

		// Render pagination.
		ob_start();
		gigneo_pagination( $query, $data['step'] ?? 1, 'gn-pagination-wrapper' );
		$pagination_html = ob_get_clean();

		// Render active pills.
		ob_start();
		gigneo_load_template( 'archive/freelancer/parts/filter-pills', false, $params );
		$pills_html = ob_get_clean();

		// Result count.
		$result_count = $query->found_posts ?? 0;

		$response = array(
			'cards'        => $cards_html,
			'pagination'   => $pagination_html,
			'pills'        => $pills_html,
			'result_count' => $result_count,
		);

		$response = apply_filters( 'gigneo_filter_freelancers_after', $response, $query, $data, $params );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle employer filtering requests.
	 *
	 * @since 0.0.1
	 */
	public function filter_employers() {

		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$params = isset( $_POST['params'] ) ? map_deep( wp_unslash( (array) $_POST['params'] ), 'sanitize_text_field' ) : array();
		$params = $this->sanitize_filter_params( $params );

		$shortcode_options = isset( $_POST['shortcode_options'] ) ? map_deep( wp_unslash( (array) $_POST['shortcode_options'] ), 'sanitize_text_field' ) : array();

		$base_url              = remove_query_arg( array_keys( $params ), wp_get_referer() );
		$params['current_url'] = add_query_arg( $params, $base_url );
		$data                  = $this->build_employer_query( $params, $shortcode_options );
		$query                 = $data['query'];

		// Check map status before the loop.

		ob_start();
		if ( $query->have_posts() ) {

			$active_profile_id   = gigneo_active_profile_id();
			$active_profile_type = gigneo_profile_type( $active_profile_id );
			$country_state_list  = gigneo_countries_with_states( 'active' );
			$saved_items         = gigneo_post_meta( $active_profile_id, '_gigneo_pm_saved_employer' );

			$item_args = array(
				'profile_id'         => $active_profile_id,
				'profile_type'       => $active_profile_type,
				'country_state_list' => $country_state_list,
				'saved'              => $saved_items,
			);

			while ( $query->have_posts() ) {
				$query->the_post();
				gigneo_load_template( 'archive/employer/parts/card-layout-1', false, $item_args );

			}
			wp_reset_postdata();
		} else {
			gigneo_not_found( 'employer_archive' );
		}

		$cards_html = ob_get_clean();

		// Render pagination.
		ob_start();
		gigneo_pagination( $query, $data['step'] ?? 1, 'gn-pagination-wrapper' );
		$pagination_html = ob_get_clean();

		// Render active pills.
		ob_start();
		gigneo_load_template( 'archive/employer/parts/filter-pills', false, $params );
		$pills_html = ob_get_clean();

		// Result count.
		$result_count = $query->found_posts ?? 0;

		$response = array(
			'cards'        => $cards_html,
			'pagination'   => $pagination_html,
			'pills'        => $pills_html,
			'result_count' => $result_count,
		);

		$response = apply_filters( 'gigneo_filter_employers_after', $response, $query, $data, $params );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Build job query arguments.
	 *
	 * @since 0.0.1
	 */
	private function build_job_query( $args, $shortcode_options = array() ) {

		$search           = isset( $args['search'] ) ? sanitize_text_field( $args['search'] ) : '';
		$location         = isset( $args['location'] ) ? sanitize_text_field( $args['location'] ) : '';
		$category         = isset( $args['category'] ) ? sanitize_text_field( $args['category'] ) : '';
		$sub_category     = isset( $args['subcategory'] ) ? sanitize_text_field( $args['subcategory'] ) : '';
		$specific_types   = isset( $args['specific_types'] ) ? array_map( 'sanitize_text_field', (array) $args['specific_types'] ) : array();
		$skills           = isset( $args['skills'] ) ? array_map( 'sanitize_text_field', (array) $args['skills'] ) : array();
		$budget_min       = isset( $args['budget_min'] ) && '' !== $args['budget_min'] ? floatval( $args['budget_min'] ) : '';
		$budget_max       = isset( $args['budget_max'] ) && '' !== $args['budget_max'] ? floatval( $args['budget_max'] ) : '';
		$mode             = isset( $args['mode'] ) ? sanitize_text_field( $args['mode'] ) : '';
		$amount_spent     = isset( $args['amount_spent'] ) && '' !== $args['amount_spent'] ? absint( $args['amount_spent'] ) : '';
		$experience_level = isset( $args['experience_level'] ) ? sanitize_text_field( $args['experience_level'] ) : '';
		$sort             = isset( $args['sort'] ) ? sanitize_text_field( $args['sort'] ) : 'newest';
		$step             = isset( $args['step'] ) ? max( 1, absint( $args['step'] ) ) : 1;
		$featured         = isset( $args['featured'] );
		$verified         = isset( $args['verified'] );

		$posts_per_page = gigneo_option( '_gigneo_ts_jobs_per_page', 9 );
		$posts_per_page = apply_filters( 'gigneo_build_job_query_posts_per_page', $posts_per_page );
		$posts_per_page = ! empty( $shortcode_options['per_page'] ) ? absint( $shortcode_options['per_page'] ) : $posts_per_page;

		// Base query args.
		$job_args = array(
			'post_type'      => 'gigneo_job',
			'posts_per_page' => $posts_per_page,
			'paged'          => $step,
			's'              => $search,
			'post_status'    => 'publish',
		);

		// Tax query.
		$tax_query = array( 'relation' => 'AND' );

		if ( ! empty( $category ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_facet',
				'field'    => 'slug',
				'terms'    => $category,
			);
		}

		if ( ! empty( $sub_category ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_facet',
				'field'    => 'slug',
				'terms'    => $sub_category,
			);
		}

		if ( ! empty( $specific_types ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_facet',
				'field'    => 'slug',
				'terms'    => $specific_types,
				'operator' => 'IN',
			);
		}

		if ( ! empty( $skills ) ) {
			$tax_query[] = array(
				'taxonomy' => 'gigneo_skill',
				'field'    => 'slug',
				'terms'    => $skills,
				'operator' => 'IN',
			);
		}

		if ( count( $tax_query ) > 1 ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
			$job_args['tax_query'] = $tax_query;
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
		}

		// Meta query.
		$meta_query = array( 'relation' => 'AND' );

		if ( ! empty( $location ) ) {
			if ( str_contains( $location, ':' ) ) {
				$meta_query[] = array(
					'key'     => '_gigneo_pm_country_state',
					'value'   => $location,
					'compare' => '=',
				);
			} else {
				$meta_query[] = array(
					'relation' => 'OR',
					array(
						'key'     => '_gigneo_pm_country_state',
						'value'   => $location . ':',
						'compare' => 'LIKE',
					),
					array(
						'key'     => '_gigneo_pm_city',
						'value'   => $location,
						'compare' => '=',
					),
				);
			}
		}

		// Budget.
		if ( '' !== $budget_min || '' !== $budget_max ) {

			$rate_query = array(
				'key'  => '_gigneo_pm_price',
				'type' => 'NUMERIC',
			);

			if ( '' !== $budget_min && '' !== $budget_max ) {

				$rate_query['value']   = array( $budget_min, $budget_max );
				$rate_query['compare'] = 'BETWEEN';

			} elseif ( '' !== $budget_min ) {

				$rate_query['value']   = $budget_min;
				$rate_query['compare'] = '>=';

			} else {

				$rate_query['value']   = $budget_max;
				$rate_query['compare'] = '<=';
			}

			$meta_query[] = $rate_query;
		}

		// Mode.
		if ( ! empty( $mode ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_type',
				'value'   => $mode,
				'compare' => '=',
			);
		}

		// Amount Spent (employer who posted the job).
		if ( ! empty( $amount_spent ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_amount_spent',
				'value'   => $amount_spent,
				'compare' => '>=',
				'type'    => 'NUMERIC',
			);
		}

		// Experience Level.
		if ( ! empty( $experience_level ) ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_experience_level',
				'value'   => $experience_level,
				'compare' => '=',
			);
		}

		// Featured.
		if ( $featured ) {
			$meta_query[] = array(
				'key'     => '_gigneo_pm_featured',
				'value'   => true,
				'compare' => '=',
			);
		}

		if ( ! empty( $verified ) ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_post__in
			$job_args['post__in'] = gigneo_verified_users( 'employer' );
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_post__in
		}

		if ( count( $meta_query ) > 1 ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
			$job_args['meta_query'] = $meta_query;
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
		}

		// Sorting.
		switch ( $sort ) {
			case 'newest':
				$job_args['orderby'] = 'date';
				$job_args['order']   = 'DESC';
				break;
			case 'oldest':
				$job_args['orderby'] = 'date';
				$job_args['order']   = 'ASC';
				break;
			case 'rate_low_to_high':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$job_args['meta_key'] = '_gigneo_pm_price';
				$job_args['orderby']  = 'meta_value_num';
				$job_args['order']    = 'ASC';
				break;
			case 'rate_high_to_low':
				// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				$job_args['meta_key'] = '_gigneo_pm_price';
				$job_args['orderby']  = 'meta_value_num';
				$job_args['order']    = 'DESC';
				break;
			default:
				$job_args['orderby'] = 'date';
				$job_args['order']   = 'DESC';
				break;
		}

		$job_args = apply_filters( 'gigneo_build_job_query_before', $job_args, $args, $shortcode_options );

		$job_query = new WP_Query( $job_args );

		$result = array(
			'query'            => $job_query,
			'step'             => $step ?? 1,
			'geo_filtered_ids' => array(),
			'geo_filtering'    => false,
			'search_lat'       => 0,
			'search_lng'       => 0,
			'distance_type'    => 'kilometers',
			'map_radius'       => '',
		);

		return apply_filters( 'gigneo_build_job_query_after', $result, $args, $shortcode_options );
	}

	/**
	 * Handle job filtering requests.
	 *
	 * @since 0.0.1
	 */
	public function filter_jobs() {

		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$params = isset( $_POST['params'] ) ? map_deep( wp_unslash( (array) $_POST['params'] ), 'sanitize_text_field' ) : array();
		$params = $this->sanitize_filter_params( $params );

		$base_url              = remove_query_arg( array_keys( $params ), wp_get_referer() );
		$params['current_url'] = add_query_arg( $params, $base_url );
		$shortcode_options     = isset( $_POST['shortcode_options'] ) ? map_deep( wp_unslash( (array) $_POST['shortcode_options'] ), 'sanitize_text_field' ) : array();
		$data                  = $this->build_job_query( $params, $shortcode_options );
		$query                 = $data['query'];

		// Check map status before the loop.

		// Single loop: render cards + collect map data.
		ob_start();
		if ( $query->have_posts() ) {
			$active_profile_id  = gigneo_active_profile_id();
			$country_state_list = gigneo_countries_with_states( 'active' );
			$saved_items        = gigneo_post_meta( $active_profile_id, '_gigneo_pm_saved_job' );

			$item_args = array(
				'profile_id'         => $active_profile_id,
				'country_state_list' => $country_state_list,
				'saved'              => $saved_items,
			);

			while ( $query->have_posts() ) {
				$query->the_post();
				$job_id = get_the_ID();
				gigneo_load_template( 'archive/job/parts/card-layout-1', false, $item_args );

			}
			wp_reset_postdata();
		} else {
			gigneo_not_found( 'job_archive' );
		}

		$cards_html = ob_get_clean();

		// Render pagination.
		ob_start();
		gigneo_pagination( $query, $data['step'], 'gn-pagination-wrapper' );
		$pagination_html = ob_get_clean();

		// Render active pills.
		ob_start();
		gigneo_load_template( 'archive/job/parts/filter-pills', false, $params );
		$pills_html = ob_get_clean();

		// Result count.
		$result_count = $query->found_posts ?? 0;

		$response = array(
			'cards'        => $cards_html,
			'pagination'   => $pagination_html,
			'pills'        => $pills_html,
			'result_count' => $result_count,
		);

		$response = apply_filters( 'gigneo_filter_jobs_after', $response, $query, $data, $params );

		wp_send_json_success( $response, 200 );
	}

	/**
	 * Handle attachment removal requests.
	 *
	 * @since 0.0.1
	 */
	public function remove_attachment() {

		// Check if nonce is valid.
		$security = isset( $_POST['security'] ) ? sanitize_text_field( wp_unslash( $_POST['security'] ) ) : '';
		if ( empty( $security ) || ! wp_verify_nonce( $security, 'gigneo_security' ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Security verification failed. Please reload and try again.', 'gigneo' ) ), 403 );
		}

		$attachment_id = ! empty( $_POST['attachment_id'] ) ? absint( wp_unslash( $_POST['attachment_id'] ) ) : 0;
		$profile_id    = gigneo_active_profile_id();

		if ( empty( $attachment_id ) || empty( $profile_id ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid request.', 'gigneo' ) ), 400 );
		}

		global $wpdb;
		$table_attachments = $wpdb->prefix . 'gigneo_attachments';

		// Fetch attachment details
		global $wpdb;
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$attachment = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}gigneo_attachments WHERE id = %d", $attachment_id ) );
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		if ( ! $attachment ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Attachment not found.', 'gigneo' ) ), 404 );
		}

		// Security check: Ensure the attachment belongs to the user's profile OR post
		$is_allowed = false;
		if ( absint( $attachment->profile_id ) === absint( $profile_id ) ) {
			$is_allowed = true;
		} elseif ( ! empty( $attachment->post_id ) ) {
			$post_author = get_post_field( 'post_author', $attachment->post_id );
			if ( absint( $post_author ) === absint( get_current_user_id() ) ) {
				$is_allowed = true;
			}
		}

		if ( ! $is_allowed ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You do not have permission to delete this attachment.', 'gigneo' ) ), 403 );
		}

		// Delete record from DB
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->delete( $table_attachments, array( 'id' => $attachment_id ), array( '%d' ) );
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		// Delete physical file
		if ( ! empty( $attachment->path ) ) {
			$file_path = gigneo_upload_dir_path( $attachment->path );
			if ( file_exists( $file_path ) ) {
				wp_delete_file( $file_path );
			}
		}

		wp_send_json_success( array( 'message' => esc_html__( 'Attachment removed successfully.', 'gigneo' ) ) );
	}
}
