<?php
/**
 * Ability: wp-agent/list-users
 *
 * Read-only. Listet WordPress-Nutzer mit optionalem Rollen-, Such- und
 * Paginierungs-Filter als schlanke Liste (id, username, display_name, email,
 * roles, registered) plus Gesamtzahl. Teil der stark gegateten
 * Nutzerverwaltungs-Gruppe: die Capability list_users besitzen in einer
 * Standardinstallation ausschließlich Administratoren, der Companion-Bot
 * (Editor) wird hier immer mit 403 abgewiesen.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_list_users(): array {
	return array(
		'label'               => __( 'Nutzer auflisten', 'wp-agent-companion' ),
		'description'         => __( 'Listet WordPress-Nutzer mit Rollen-, Such- und Paginierungs-Filter als schlanke Liste (id, username, display_name, email, roles, registered) plus Gesamtzahl.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'                 => 'object',
			'properties'           => array(
				'role'     => array(
					'type'        => 'string', 'maxLength' => 64, 'pattern' => '^[a-z0-9_-]{1,64}$',
					'description' => __( 'Muss eine registrierte Rolle sein (wp_roles()). Ohne Angabe werden alle Rollen geliefert.', 'wp-agent-companion' ),
				),
				'search'   => array( 'type' => 'string', 'minLength' => 1, 'maxLength' => 100 ),
				'per_page' => array(
					'type'    => 'integer', 'minimum' => 1, 'maximum' => 100,
					'default' => 20,
				),
				'page'     => array(
					'type'    => 'integer', 'minimum' => 1, 'maximum' => 10000,
					'default' => 1,
				),
			),
			'additionalProperties' => false,
		),
		'output_schema'       => array(
			'type'                 => 'object',
			'properties'           => array(
				'items' => array(
					'type'  => 'array', 'maxItems' => 100,
					'items' => array(
						'type'                 => 'object',
						'properties'           => array(
							'id'           => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 2147483647 ),
							'username'     => array( 'type' => 'string', 'maxLength' => 60 ),
							'display_name' => array( 'type' => 'string', 'maxLength' => 250 ),
							'email'        => array( 'type' => 'string', 'maxLength' => 320 ),
							'roles'        => array(
								'type'  => 'array', 'maxItems' => 20,
								'items' => array( 'type' => 'string', 'maxLength' => 64 ),
							),
							'registered'   => array( 'type' => 'string', 'maxLength' => 32 ),
						),
						'required'             => array( 'id', 'username', 'display_name', 'email', 'roles', 'registered' ),
						'additionalProperties' => false,
					),
				),
				'total' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 2147483647 ),
			),
			'required'             => array( 'items', 'total' ),
			'additionalProperties' => false,
		),
		'execute_callback'    => 'wpagent_exec_list_users',
		'permission_callback' => 'wpagent_perm_list_users',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => true,
				'destructive' => false,
				'idempotent'  => true,
			),
		),
	);
}

/**
 * Permission callback: der Aufrufer muss list_users besitzen. Diese
 * Capability ist in einer Standardinstallation Administratoren vorbehalten;
 * der als Editor eingerichtete Companion-Bot besitzt sie nie.
 *
 * @param mixed $input Unused ability input.
 * @return bool
 */
function wpagent_perm_list_users( $input = null ): bool {
	return current_user_can( 'list_users' );
}

/**
 * @param mixed $input
 * @return array|WP_Error
 */
function wpagent_exec_list_users( $input ) {
	$input = is_array( $input ) ? $input : array();

	if ( ! current_user_can( 'list_users' ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}

	$role = '';
	if ( array_key_exists( 'role', $input ) ) {
		$role = wpagent_core_mutator_bounded_text( $input['role'], 64 );
		if ( is_wp_error( $role ) || 1 !== preg_match( '/^[a-z0-9_-]{1,64}$/D', $role ) ) {
			return new WP_Error( 'wpagent_bad_role', __( 'Rolle ist ungültig.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
	}
	if ( '' !== $role && ! wp_roles()->is_role( $role ) ) {
		return new WP_Error(
			'wpagent_bad_role',
			/* translators: %s: submitted WordPress role. */
			sprintf( __( 'Unbekannte Rolle "%s".', 'wp-agent-companion' ), $role ),
			array( 'status' => 400 )
		);
	}

	$per_page = 20;
	if ( array_key_exists( 'per_page', $input ) ) {
		$per_page = wpagent_core_schema_input_integer( $input['per_page'], 1, 100, 'per_page' );
		if ( is_wp_error( $per_page ) ) {
			return $per_page;
		}
	}

	$page = 1;
	if ( array_key_exists( 'page', $input ) ) {
		$page = wpagent_core_schema_input_integer( $input['page'], 1, 10000, 'page' );
		if ( is_wp_error( $page ) ) {
			return $page;
		}
	}

	$query_args = array(
		'number'      => $per_page,
		'paged'       => $page,
		'orderby'     => 'registered',
		'order'       => 'DESC',
		'count_total' => true,
	);
	if ( '' !== $role ) {
		$query_args['role'] = $role;
	}
	if ( array_key_exists( 'search', $input ) ) {
		$search = wpagent_core_mutator_bounded_text( $input['search'], 100 );
		if ( is_wp_error( $search ) ) {
			return $search;
		}
		$query_args['search']         = '*' . $search . '*';
		$query_args['search_columns'] = array( 'user_login', 'user_email', 'user_nicename', 'display_name' );
	}

	$query = new WP_User_Query( $query_args );

	$items = array();
	foreach ( $query->get_results() as $user ) {
		if ( ! isset( $user->roles ) || ! is_array( $user->roles ) ) {
			return new WP_Error( 'wpagent_core_schema_output_overflow', __( 'Die Rollen eines Nutzers entsprechen nicht dem veröffentlichten Ergebnisvertrag.', 'wp-agent-companion' ), array( 'status' => 500 ) );
		}
		$roles = wpagent_core_schema_output_list( array_values( $user->roles ), 20, 'items.roles' );
		if ( is_wp_error( $roles ) ) {
			return $roles;
		}
		foreach ( $roles as $role_name ) {
			if ( is_wp_error( wpagent_core_schema_output_text( $role_name, 64, 'items.roles' ) ) ) {
				return new WP_Error( 'wpagent_core_schema_output_overflow', __( 'Eine Nutzerrolle überschreitet die veröffentlichte Sicherheitsgrenze.', 'wp-agent-companion' ), array( 'status' => 500 ) );
			}
		}
		$item = array(
			'id'           => (int) $user->ID,
			'username'     => wpagent_core_schema_output_text( $user->user_login, 60, 'items.username' ),
			'display_name' => wpagent_core_schema_output_text( $user->display_name, 250, 'items.display_name' ),
			'email'        => wpagent_core_schema_output_text( $user->user_email, 320, 'items.email' ),
			'roles'        => $roles,
			'registered'   => wpagent_core_schema_output_text( $user->user_registered, 32, 'items.registered' ),
		);
		foreach ( $item as $value ) {
			if ( is_wp_error( $value ) ) {
				return $value;
			}
		}
		$items[] = $item;
	}
	$items = wpagent_core_schema_output_list( $items, 100, 'items' );
	if ( is_wp_error( $items ) ) {
		return $items;
	}
	$total = (int) $query->get_total();
	if ( $total < 0 || $total > 2147483647 ) {
		return new WP_Error( 'wpagent_core_schema_output_overflow', __( 'Die Gesamtzahl der Nutzer überschreitet die veröffentlichte Sicherheitsgrenze.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}

	return array(
		'items' => $items,
		'total' => $total,
	);
}
