<?php
/**
 * Ability: wp-agent/create-user
 *
 * Legt einen neuen Nutzer über die offizielle wp_insert_user()-API an
 * (Username-, E-Mail- und Rollen-Validierung inklusive Eindeutigkeitsprüfung
 * übernimmt der WordPress-Kern selbst; ein WP_Error von wp_insert_user()
 * wird unverändert durchgereicht, analog zum wp_update_post()-Muster in
 * update-post.php). Ist das Passwort-Feld leer, wird serverseitig ein
 * starkes Passwort erzeugt und EINMALIG im Ergebnis zurückgegeben
 * (generated_password); bei nachfolgenden Leseoperationen (wp-agent/get-user)
 * taucht es nie wieder auf.
 *
 * Dasselbe administrator-Gate wie bei wp-agent/set-user-role: Rollen mit der
 * Capability manage_options dürfen nur mit dem expliziten Input-Flag
 * i_grant_admin=true angelegt werden, sonst 403. Die Erkennungslogik ist
 * bewusst hier lokal dupliziert statt wpagent_role_grants_admin_capability()
 * aus set-user-role.php wiederzuverwenden: beide Dateien sollen unabhängig
 * voneinander ladbar bleiben und keine Reihenfolge-Abhängigkeit zwischen
 * neuen Ability-Dateien einführen. Die Integrationsphase sollte diese
 * kleine Dopplung nach helpers.php heben, sobald die Datei dort angefasst
 * werden darf.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_create_user(): array {
	return array(
		'label'               => __( 'Nutzer anlegen', 'wp-agent-companion' ),
		'description'         => __( 'Legt einen neuen WordPress-Nutzer an (Username, E-Mail, Rolle, optionales Passwort). Ohne Passwort wird eines serverseitig generiert und einmalig im Ergebnis zurückgegeben. Administrator-äquivalente Rollen (Capability manage_options) erfordern das explizite Flag i_grant_admin=true, sonst 403. Re-Read-verifiziert.', 'wp-agent-companion' ),
		'category'            => 'wp-agent',
		'input_schema'        => array(
			'type'       => 'object',
			'properties' => array(
				'username'      => array( 'type' => 'string' ),
				'email'         => array( 'type' => 'string' ),
				'role'          => array(
					'type'        => 'string',
					'description' => __( 'Muss eine registrierte Rolle sein (wp_roles()).', 'wp-agent-companion' ),
				),
				'password'      => array(
					'type'        => 'string',
					'description' => __( 'Optional. Fehlt es, wird serverseitig ein starkes Passwort generiert und einmalig zurückgegeben.', 'wp-agent-companion' ),
				),
				'i_grant_admin' => array(
					'type'        => 'boolean',
					'default'     => false,
					'description' => __( 'Pflicht (true), wenn die Zielrolle die Capability manage_options besitzt (z. B. administrator).', 'wp-agent-companion' ),
				),
			),
			'required'   => array( 'username', 'email', 'role' ),
		),
		'output_schema'       => array(
			'type'       => 'object',
			'properties' => array(
				'user_id'             => array( 'type' => 'integer' ),
				'username'            => array( 'type' => 'string' ),
				'email'               => array( 'type' => 'string' ),
				'role'                => array( 'type' => 'string' ),
				'password_generated'  => array( 'type' => 'boolean' ),
				'generated_password'  => array(
					'type'        => 'string',
					'description' => __( 'Nur vorhanden, wenn password_generated true ist. Wird nie erneut ausgeliefert.', 'wp-agent-companion' ),
				),
				'verified'            => array( 'type' => 'boolean' ),
			),
		),
		'execute_callback'    => 'wpagent_exec_create_user',
		'permission_callback' => 'wpagent_perm_create_users',
		'meta'                => array(
			'show_in_rest' => true,
			'annotations'  => array(
				'readonly'    => false,
				'destructive' => false,
				// Ein zweiter Aufruf mit demselben username schlägt am
				// WordPress-Kern (existing_user_login) fehl statt denselben
				// Endzustand ruhig erneut zu melden; daher bewusst false statt
				// des sonst in diesem Kern-Plugin üblichen true.
				'idempotent'  => false,
			),
		),
	);
}

/**
 * Permission callback: der Aufrufer muss create_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_create_users( $input = null ): bool {
	return current_user_can( 'create_users' );
}

/**
 * Prüft, ob eine Rolle Administrator-äquivalente Rechte trägt. Siehe
 * Datei-Kommentar oben zur bewussten lokalen Dopplung gegenüber
 * set-user-role.php.
 *
 * @param string $role
 * @return bool
 */
function wpagent_new_user_role_grants_admin_capability( string $role ): bool {
	if ( 'administrator' === $role ) {
		return true;
	}
	$role_object = get_role( $role );
	if ( ! $role_object instanceof WP_Role ) {
		return false;
	}
	return ! empty( $role_object->capabilities['manage_options'] );
}

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

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

	$username = trim( (string) ( $input['username'] ?? '' ) );
	$email    = trim( (string) ( $input['email'] ?? '' ) );
	$role     = (string) ( $input['role'] ?? '' );

	if ( '' === $username ) {
		return new WP_Error( 'wpagent_bad_username', __( 'username fehlt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	if ( '' === $email ) {
		return new WP_Error( 'wpagent_bad_email', __( 'email fehlt.', '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( __( 'Ungültige Rolle "%s".', 'wp-agent-companion' ), $role ),
			array( 'status' => 400 )
		);
	}

	$i_grant_admin = ! empty( $input['i_grant_admin'] );
	if ( wpagent_new_user_role_grants_admin_capability( $role ) && ! $i_grant_admin ) {
		return new WP_Error(
			'wpagent_admin_grant_required',
			__( 'Diese Rolle besitzt Administrator-Rechte (manage_options). Setze i_grant_admin=true, um das explizit zu bestätigen.', 'wp-agent-companion' ),
			array( 'status' => 403 )
		);
	}

	$password_generated = false;
	$password            = isset( $input['password'] ) ? (string) $input['password'] : '';
	if ( '' === $password ) {
		$password            = wp_generate_password( 24, true, true );
		$password_generated = true;
	}

	$user_id = wp_insert_user(
		array(
			'user_login' => $username,
			'user_email' => $email,
			'user_pass'  => $password,
			'role'       => $role,
		)
	);
	if ( is_wp_error( $user_id ) ) {
		return $user_id;
	}
	$user_id = (int) $user_id;

	$fresh    = get_userdata( $user_id );
	$verified = ( $fresh instanceof WP_User )
		&& ( $fresh->user_login === $username )
		&& ( $fresh->user_email === $email )
		&& in_array( $role, $fresh->roles, true );

	$result = array(
		'user_id'            => $user_id,
		'username'           => $fresh ? $fresh->user_login : $username,
		'email'              => $fresh ? $fresh->user_email : $email,
		'role'               => $role,
		'password_generated' => $password_generated,
		'verified'           => $verified,
	);
	if ( $password_generated ) {
		$result['generated_password'] = $password;
	}

	return $result;
}
