<?php
/**
 * Author_Kit User Management Functions
 *
 * This file contains various functions and AJAX handlers for managing users within the Author_Kit plugin.
 * It includes actions for:
 * - Loading a user table
 * - Retrieving the total number of users by role
 * - Deleting, blocking, and unblocking users
 * - Sending password reset emails
 * - Retrieving a list of users
 *
 * The file uses AJAX requests with nonce verification and permission checks to ensure that only authorized
 * users can execute certain actions.
 *
 * @package Author_Kit
 * @since 1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * User Management Class for handling AJAX requests related to users.
 *
 * This class provides functionality for managing users in the system. It includes actions for:
 * - Loading a user table
 * - Getting the total number of users by role
 * - Deleting, blocking, and unblocking users
 * - Sending password reset emails
 * - Retrieving a list of users
 *
 * The class handles AJAX requests with proper security checks, such as nonce validation,
 * and ensures that the current user has the necessary permissions to perform actions.
 *
 * @package Author_Kit
 * @since 1.0.0
 */
class Author_Kit_User_Table {


	/**
	 * Initializes AJAX actions for managing users.
	 *
	 * Registers AJAX handlers for loading user tables, getting total users by role,
	 * deleting users, blocking/unblocking users, sending password reset emails, and retrieving user lists.
	 *
	 * @return void
	 */
	public function __construct() {
		add_action( 'wp_ajax_author_kit_load_users', array( $this, 'load_users_table' ) );
		add_action( 'wp_ajax_author_kit_load_total_no_of_users', array( $this, 'get_total_users_by_role' ) );
		add_action( 'wp_ajax_author_kit_delete_user', array( $this, 'delete_user' ) );
		add_action( 'wp_ajax_author_kit_block_user', array( $this, 'block_user' ) );
		add_action( 'wp_ajax_author_kit_unblock_user', array( $this, 'unblock_user' ) );
		add_action( 'wp_ajax_author_kit_send_password_reset', array( $this, 'send_password_reset' ) );
		add_action( 'wp_ajax_author_kit_get_users_list', array( $this, 'get_users_list' ) );
	}

	/**
	 * Handles AJAX request to return paginated user data.
	 *
	 * Applies filters like search, role, and blocked status.
	 * Returns user details and pagination info as a JSON success response.
	 *
	 * @return void Outputs JSON response with users and pagination data.
	 */
	public function load_users_table() {
		check_ajax_referer( 'user-table-loader-nonce', 'nonce' );

		$user_limit      = isset( $_POST['limit'] ) ? intval( wp_unslash( $_POST['limit'] ) ) : 10;
		$current_page    = isset( $_POST['pageId'] ) || -1 !== $user_limit ? intval( wp_unslash( $_POST['pageId'] ) ) : 1;
		$search_value    = isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '';
		$order_by        = isset( $_POST['order_by'] ) ? sanitize_text_field( wp_unslash( $_POST['order_by'] ) ) : 'user_login';
		$order_direction = isset( $_POST['order_direction'] ) ? sanitize_text_field( wp_unslash( $_POST['order_direction'] ) ) : 'ASC';
		$user_role       = isset( $_POST['userRole'] ) ? sanitize_text_field( wp_unslash( $_POST['userRole'] ) ) : '';

		global $author_kit_blocker, $author_kit_online_user;

		$include      = '';
		$meta_query   = '';
		$role__not_in = array();

		$include_subscribers = get_option( 'author_kit_include_subscribers', true ); // default true if not set.

		// Handle special role logic.
		if ( 'all' === $user_role || '' === $user_role ) {
			$user_role  = '';
			$meta_query = $author_kit_blocker->get_meta_query_exclude_blocked();

			// Exclude subscribers if option is false.
			if ( ! $include_subscribers ) {
				$role__not_in[] = 'subscriber';
			}
		} elseif ( 'blocked' === $user_role || 'Blocked' === $user_role ) {
			$user_role  = '';
			$meta_query = $author_kit_blocker->get_meta_query_only_blocked();
		} else {
			$all_roles = wp_roles()->roles;
			if ( array_key_exists( $user_role, $all_roles ) ) {
				$user_role = sanitize_text_field( $user_role );

				// If the selected role is subscriber and the option is false, prevent loading.
				if ( 'subscriber' === $user_role && ! $include_subscribers ) {
					$user_role = '';
					$include   = array( 0 ); // No users.
				} else {
					$meta_query = $author_kit_blocker->get_meta_query_exclude_blocked();
				}
			} else {
				$user_role = '';
				$include   = array( 0 ); // Invalid role.
			}
		}

		// Prepare the WP_User_Query args.
		$args = array(
			'number'         => $user_limit,
			'paged'          => $current_page,
			'orderby'        => $order_by,
			'order'          => $order_direction,
			'role'           => $user_role,
			'include'        => $include,
			'search'         => '*' . esc_attr( $search_value ) . '*',
			'search_columns' => array(
				'user_login',
				'user_nicename',
				'display_name',
				'user_email',
			),
            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
			'meta_query'     => $meta_query,
		);

		if ( ! empty( $role__not_in ) ) {
			$args['role__not_in'] = $role__not_in;
		}

		// Fetch the users.
		$user_query  = new WP_User_Query( $args );
		$users       = $user_query->get_results();
		$total_users = $user_query->get_total();

		$current_user_id = get_current_user_id();

		$total_pages  = -1 !== $user_limit ? ceil( $total_users / $user_limit ) : min( 1, 1 * $total_users );
		$start_index  = -1 !== $user_limit ? min( ( $current_page - 1 ) * $user_limit + 1, $total_users ) : min( 1, 1 * $total_users );
		$ending_index = -1 !== $user_limit ? min( $current_page * $user_limit, $total_users ) : $total_users;

		// Build the user data for DataTables.
		$user_data = array();
		foreach ( $users as $user ) {
			$user_id        = intval( $user->ID );
			$post_as_author = count_user_posts( $user_id );
			$avatar         = get_avatar_url( $user_id );

			$display_name = $user->display_name;
			if ( $user_id === $current_user_id ) {
				$display_name .= ' (You)';
			}

			$user_status     = $author_kit_online_user->is_user_online( $user_id ) ? 'Online' : 'Offline';
			$user_role_value = $author_kit_blocker->is_user_blocked( $user_id ) ? 'Blocked' : ucfirst( implode( ', ', $user->roles ) );

			$user_profile_url = get_author_posts_url( $user_id );

			$user_data[] = array(
				'ID'           => $user_id,
				'username'     => $user->user_login,
				'avatar'       => $avatar,
				'display_name' => $display_name,
				'role'         => $user_role_value,
				'status'       => $user_status,
				'contribution' => $post_as_author,
				'email'        => $user->user_email,
				'joinDate'     => $user->user_registered,
				'userProfile'  => $user_profile_url,
			);
		}

		$pagination_data = array(
			'total_users'  => $total_users,
			'total_pages'  => $total_pages,
			'current_page' => $current_page,
			'start_index'  => $start_index,
			'ending_index' => $ending_index,
		);

		wp_send_json(
			array(
				'pagination_data' => $pagination_data,
				'user_data'       => $user_data,
			)
		);
	}

	/**
	 * Handles AJAX request to return user counts by role.
	 *
	 * Excludes blocked users and optionally subscribers based on settings.
	 * Adds total and blocked user counts, and returns the result as a JSON success response.
	 *
	 * @return void Outputs JSON response with user counts per role.
	 */
	public function get_total_users_by_role() {
		// Check nonce for security.
		check_ajax_referer( 'user-table-loader-nonce', 'nonce' );

		// Get include_subscribers flag from options.
		$include_subscribers = get_option( 'author_kit_include_subscribers', true ); // default true if not set.

		// Initialize an array to store the user counts.
		$user_counts = array();
		global $author_kit_blocker;

		// Get all roles dynamically.
		$all_roles  = wp_roles()->roles;
		$role_slugs = array_keys( $all_roles );

		// Get total users count.
		$total_users_data = count_users();
		$blocked_count    = intval( $author_kit_blocker->get_total_blocked_users() );
		$total_users      = intval( $total_users_data['total_users'] ) - $blocked_count;

		$filtered_total_users = 0;

		foreach ( $role_slugs as $role ) {
			// Skip subscriber role if the option is disabled.
			if ( ! $include_subscribers && 'subscriber' === $role ) {
				continue;
			}

			$role_count = $total_users_data['avail_roles'][ $role ] ?? 0;

			// Get blocked users for this role.
			$blocked_role_users_query = new WP_User_Query(
				array(
					'role'       => $role,
                	// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
					'meta_query' => $author_kit_blocker->get_meta_query_only_blocked(),
					'fields'     => 'ID',
				)
			);
			$blocked_role_count       = $blocked_role_users_query->get_total();

			$adjusted_role_count = max( 0, $role_count - $blocked_role_count );

			if ( $adjusted_role_count > 0 ) {
				$user_counts[ $role ]  = $adjusted_role_count;
				$filtered_total_users += $adjusted_role_count;
			}
		}

		// Add filtered total users.
		if ( $filtered_total_users > 0 ) {
			$user_counts['all'] = $filtered_total_users;
		}

		// Add blocked users count.
		if ( $blocked_count > 0 ) {
			$user_counts['blocked'] = $blocked_count;
		}

		// Ensure 'all' key is the first element.
		if ( isset( $user_counts['all'] ) ) {
			$user_counts = array_merge( array( 'all' => $user_counts['all'] ), $user_counts );
		}

		// Send the filtered data as JSON response.
		wp_send_json_success( $user_counts );
	}

	/**
	 * Handles AJAX request to block selected users.
	 *
	 * Validates admin permissions and blocks users via Author Kit blocker.
	 * Returns a JSON success or error response based on the result.
	 *
	 * @return void Outputs JSON response indicating block status.
	 */
	public function block_user() {
		// Verify nonce for security.
		check_ajax_referer( 'user-table-loader-nonce', 'nonce' );

		// Get the array of user IDs from the POST request.
		$user_ids = isset( $_POST['block_user_ids'] )
			? json_decode( sanitize_text_field( wp_unslash( $_POST['block_user_ids'] ) ), true )
			: array();

		$user_ids = ( is_array( $user_ids ) && ! empty( $user_ids ) ) ? array_map( 'intval', $user_ids ) : array();

		// Check if the user has permission to block other users.
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission Not Allowed', 'author-kit' ) ) );
		}

		global $author_kit_blocker;
		$result = $author_kit_blocker->block_multiple_users( $user_ids );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * Handles AJAX request to unblock selected users.
	 *
	 * Validates admin permissions and unblocks users via Author Kit blocker.
	 * Returns a JSON success or error response based on the result.
	 *
	 * @return void Outputs JSON response indicating unblock status.
	 */
	public function unblock_user() {
		// Verify nonce for security.
		check_ajax_referer( 'user-table-loader-nonce', 'nonce' );

		// Decode the array of user IDs from the request.
		$user_ids = isset( $_POST['unblock_user_ids'] )
			? json_decode( sanitize_text_field( wp_unslash( $_POST['unblock_user_ids'] ) ), true )
			: array();

		$user_ids = ( is_array( $user_ids ) && ! empty( $user_ids ) ) ? array_map( 'intval', $user_ids ) : array();

		if ( empty( $user_ids ) || ! is_array( $user_ids ) ) {
			wp_send_json_error( array( 'message' => __( 'No Valid User IDs Provided', 'author-kit' ) ) );
		}

		// Security: Ensure the user is allowed to unblock other users.
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission Not Allowed', 'author-kit' ) ) );
		}

		global $author_kit_blocker;
		$result = $author_kit_blocker->unblock_multiple_users( $user_ids );

		if ( $result['success'] ) {
			wp_send_json_success( $result );
		} else {
			wp_send_json_error( $result );
		}
	}

	/**
	 * Handles AJAX request to delete selected users.
	 *
	 * Validates permissions, deletes users (excluding self and admins), and reassigns posts if needed.
	 * Returns a JSON success or error response with a status message.
	 *
	 * @return void Outputs JSON response indicating delete result.
	 */
	public function delete_user() {
		// Verify nonce for security.
		check_ajax_referer( 'user-table-loader-nonce', 'nonce' );

		// Decode the JSON array of user IDs.
		$user_ids = isset( $_POST['delete_user_ids'] )
			? json_decode( sanitize_text_field( wp_unslash( $_POST['delete_user_ids'] ) ), true )
			: array();

		$user_ids = ( is_array( $user_ids ) && ! empty( $user_ids ) ) ? array_map( 'intval', $user_ids ) : array();

		// Check if user IDs are provided.
		if ( empty( $user_ids ) ) {
			wp_send_json_error( array( 'message' => __( 'No User IDs Provided', 'author-kit' ) ) );
			return;
		}

		$current_user_id = get_current_user_id();

		// Get the user to reassign posts to (or default to the current user).
		$reassigned_user = isset( $_POST['attribute_user'] )
			? sanitize_text_field( wp_unslash( $_POST['attribute_user'] ) )
			: $current_user_id;

		// Handle null reassignment properly.
		$reassigned_user = ( 'null' === $reassigned_user ) ? null : intval( $reassigned_user );

		// Validate input and check user permissions.
		if ( ! is_array( $user_ids ) || ! current_user_can( 'delete_users' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission Not Allowed', 'author-kit' ) ) );
		}

		$deleted_users = array();
		$failed_users  = array();
		$success       = false;

		// Remove the current user from the array and add to failed list.
		if ( in_array( $current_user_id, $user_ids, true ) ) {
			$failed_users[] = $current_user_id;
			$user_ids       = array_diff( $user_ids, array( $current_user_id ) );
		}

		foreach ( $user_ids as $user_id ) {
			$user_id = intval( $user_id );

			// Prevent administrators from being deleted.
			$user = get_userdata( $user_id );
			if ( $user ) {
				// Attempt to delete user.
				if ( wp_delete_user( $user_id, $reassigned_user ) ) {
					$deleted_users[] = $user_id;
				} else {
					$failed_users[] = $user_id;
				}
			} else {
				$failed_users[] = $user_id;
			}
		}

		// Determine the response message based on success/failure.
		if ( empty( $deleted_users ) ) {
			$message = __( 'No Users Deleted', 'author-kit' );
			$success = false;
		} elseif ( empty( $failed_users ) ) {
			$message = ( count( $deleted_users ) === 1 )
				? __( 'User Deleted Successfully.', 'author-kit' )
				: __( 'Users Deleted Successfully', 'author-kit' );
			$success = true;
		} else {
			$message = __( 'Some Users Deleted, Others Failed', 'author-kit' );
			$success = false;
		}

		if ( $success ) {
			wp_send_json_success( array( 'message' => $message ) );
		} else {
			wp_send_json_error( array( 'message' => $message ) );
		}
	}

	/**
	 * Sends password reset emails to selected users via AJAX.
	 *
	 * Validates permissions and user IDs, then sends reset emails (excluding current user).
	 * Returns JSON success or error with a status message.
	 *
	 * @return void Outputs JSON response indicating email result.
	 */
	public function send_password_reset() {

		// Verify nonce for security.
		check_ajax_referer( 'user-table-loader-nonce', 'nonce' );

		// Check if user IDs are provided.
		if ( empty( $_POST['reset_user_ids'] ) ) {
			wp_send_json_error( array( 'message' => __( 'No User IDs Provided', 'author-kit' ) ) );
			return;
		}

		// Decode user IDs from JSON.
		$user_ids = isset( $_POST['reset_user_ids'] )
			? json_decode( sanitize_text_field( wp_unslash( $_POST['reset_user_ids'] ) ), true )
			: array();

		$user_ids = ( is_array( $user_ids ) && ! empty( $user_ids ) ) ? array_map( 'intval', $user_ids ) : array();

		if ( ! is_array( $user_ids ) || empty( $user_ids ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid User IDs Format', 'author-kit' ) ) );
			return;
		}

		if ( ! current_user_can( 'edit_users' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission Not Allowed', 'author-kit' ) ) );
		}

		// Initialize an array to store success/failure results.
		$success_results = array();
		$failed_results  = array();
		$success         = false;
		$current_user_id = get_current_user_id();

		// Loop through each user ID and attempt to send a password reset email.
		foreach ( $user_ids as $user_id ) {
			$user_id = intval( $user_id );
			// Get user data.
			$user = get_user_by( 'ID', $user_id );

			if ( $user ) {
				// Use WordPress function to send password reset email.
				$reset_email_sent = $user_id !== $current_user_id ? retrieve_password( $user->user_login ) : false;

				if ( $reset_email_sent ) {
					$success_results[] = $user_id;
				} else {
					$failed_results[] = $user_id;
				}
			} else {
				$failed_results[] = $user_id;
			}
		}

		// Determine message based on results.
		if ( empty( $success_results ) ) {
			$message = __( 'No Password Reset Emails Sent', 'author-kit' );
			$success = false;
		} elseif ( empty( $failed_results ) ) {
			$message = ( count( $success_results ) === 1 )
				? __( 'Password Reset Email Sent Successfully', 'author-kit' )
				: __( 'Password Reset Emails Sent Successfully', 'author-kit' );
			$success = true;
		} else {
			$message = __( 'Some Password Reset Emails Sent, Others Failed', 'author-kit' );
			$success = false;
		}

		if ( $success ) {
			wp_send_json_success( array( 'message' => $message ) );
		} else {
			wp_send_json_error( array( 'message' => $message ) );
		}
	}

	/**
	 * Returns a sorted list of users via AJAX.
	 *
	 * Checks permissions and nonce, fetches user IDs, usernames, and display names,
	 * sorts them alphabetically, and returns as a JSON response.
	 *
	 * @return void Outputs JSON response with user list.
	 */
	public function get_users_list() {

		if ( ! check_ajax_referer( 'user-table-loader-nonce', 'nonce' ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid Request.', 'author-kit' ) ) );
		}

		if ( ! current_user_can( 'delete_users' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission Not Allowed', 'author-kit' ) ) );
		}

		$users     = get_users( array( 'fields' => array( 'ID', 'user_login', 'display_name' ) ) );
		$user_list = array();

		foreach ( $users as $user ) {
			$user_list[] = array(
				'id'           => $user->ID,
				'username'     => $user->user_login,
				'display_name' => $user->display_name,
			);
		}

		// Sort user list alphabetically by display_name.
		usort(
			$user_list,
			function ( $a, $b ) {
				return strcasecmp( $a['display_name'], $b['display_name'] );
			}
		);

		wp_send_json_success( array( 'users' => $user_list ) );
	}
}


// Initialize the class.
new Author_Kit_User_Table();
