<?php
/** OAuth-Freigabe und Verwaltung im WordPress-Backend. */

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

function wpagent_companion_oauth_authorize_menu(): void {
	add_submenu_page(
		null,
		__( 'Agent autorisieren', 'wp-agent-companion' ),
		__( 'Agent autorisieren', 'wp-agent-companion' ),
		'manage_options',
		'wpagently-oauth-authorize',
		'wpagent_companion_oauth_authorize_page'
	);
}
add_action( 'admin_menu', 'wpagent_companion_oauth_authorize_menu', 30 );

/** @return array<string,mixed> */
function wpagent_companion_oauth_request_from_input( array $input ): array {
	$keys   = array( 'response_type', 'client_id', 'redirect_uri', 'code_challenge', 'code_challenge_method', 'resource', 'scope', 'state' );
	$result = array();
	foreach ( $keys as $key ) {
		if ( ! isset( $input[ $key ] ) ) {
			$result[ $key ] = '';
			continue;
		}
		$result[ $key ] = is_scalar( $input[ $key ] )
			? (string) wp_unslash( $input[ $key ] )
			: wp_unslash( $input[ $key ] );
	}
	return $result;
}

/** Nur nach vollständiger Client- und Redirect-Prüfung verwenden. */
function wpagent_companion_oauth_redirect( array $validated, array $params ): void {
	$params['iss'] = wpagent_companion_oauth_issuer();
	$location = add_query_arg( $params, $validated['redirect_uri'] );
	nocache_headers();
	wp_redirect( $location, 302, 'wpagently OAuth' ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Exakter, registrierter OAuth-Redirect.
	exit;
}

function wpagent_companion_oauth_decision(): void {
	if ( ! current_user_can( 'manage_options' ) ) {
		wp_die( esc_html__( 'Keine Berechtigung.', 'wp-agent-companion' ), '', array( 'response' => 403 ) );
	}
	check_admin_referer( 'wpagent_companion_oauth_authorize' );
	$request   = wpagent_companion_oauth_request_from_input( $_POST );
	$validated = wpagent_companion_oauth_validate_authorization_request( $request );
	if ( is_wp_error( $validated ) ) {
		wp_die( esc_html( $validated->get_error_message() ), esc_html__( 'OAuth-Anfrage ungültig', 'wp-agent-companion' ), array( 'response' => 400 ) );
	}
	$decision = isset( $_POST['decision'] ) ? sanitize_key( wp_unslash( $_POST['decision'] ) ) : '';
	if ( 'approve' !== $decision ) {
		wpagent_companion_oauth_redirect(
			$validated,
			array( 'error' => 'access_denied', 'error_description' => __( 'Die Verbindung wurde nicht freigegeben.', 'wp-agent-companion' ), 'state' => $validated['state'] )
		);
	}
	$user_id = isset( $_POST['connection_user'] ) ? absint( $_POST['connection_user'] ) : 0;
	$issued  = wpagent_companion_oauth_issue_code( $validated, $user_id );
	if ( is_wp_error( $issued ) ) {
		wpagent_companion_oauth_redirect(
			$validated,
			array( 'error' => $issued->get_error_code(), 'error_description' => $issued->get_error_message(), 'state' => $validated['state'] )
		);
	}
	wpagent_companion_oauth_redirect( $validated, array( 'code' => $issued['code'], 'state' => $issued['state'] ) );
}
add_action( 'admin_post_wpagently_oauth_decision', 'wpagent_companion_oauth_decision' );

function wpagent_companion_oauth_authorize_page(): void {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}
	$request   = wpagent_companion_oauth_request_from_input( $_GET ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Externe OAuth-Anfrage, Freigabe folgt mit Nonce.
	$validated = wpagent_companion_oauth_validate_authorization_request( $request );
	if ( is_wp_error( $validated ) ) {
		?>
		<div class="wrap wpagently-admin"><h1><?php esc_html_e( 'Agent konnte nicht verbunden werden', 'wp-agent-companion' ); ?></h1><div class="notice notice-error"><p><?php echo esc_html( $validated->get_error_message() ); ?></p></div></div>
		<?php
		return;
	}
	$users            = wpagent_companion_connection_users( false );
	$is_rest_resource = hash_equals( wpagent_companion_oauth_rest_resource(), (string) $validated['resource'] );
	?>
	<div class="wrap wpagently-admin wpagently-oauth-consent">
		<div class="wpagently-admin__head">
			<p class="wpagently-admin__eyebrow"><?php esc_html_e( 'Direkte Verbindung', 'wp-agent-companion' ); ?></p>
			<h1><?php esc_html_e( 'Darf dieser Agent auf WordPress zugreifen?', 'wp-agent-companion' ); ?></h1>
		</div>
		<div class="wpagently-card">
			<p><?php esc_html_e( 'Der Client', 'wp-agent-companion' ); ?> <span class="wpagently-oauth-client"><?php echo esc_html( $validated['client_name'] ); ?></span> <?php echo esc_html( $is_rest_resource ? __( 'möchte die wp-agent-CLI über die WordPress-REST-Schnittstelle verwenden.', 'wp-agent-companion' ) : __( 'möchte den wpagently-MCP-Endpunkt dieser Website verwenden.', 'wp-agent-companion' ) ); ?></p>
			<p class="wpagently-oauth-detail"><?php esc_html_e( 'Nach der Freigabe wird der Browser zu dieser registrierten Adresse zurückgeleitet:', 'wp-agent-companion' ); ?> <code><?php echo esc_html( $validated['redirect_uri'] ); ?></code></p>
			<div class="wpagently-oauth-scope wpagently-rail--safe">
				<strong><?php esc_html_e( 'Was freigegeben wird', 'wp-agent-companion' ); ?></strong>
				<?php if ( $is_rest_resource ) : ?>
					<p><?php esc_html_e( 'Die CLI darf die WordPress-REST-Schnittstelle mit den Rechten des gewählten Redakteurs verwenden. Dazu gehören wpagently-Abilities sowie normale Inhalts- und Medienzugriffe. Administratorfunktionen bleiben gesperrt. Die CLI wendet zusätzlich ihre eigenen Sicherheits- und Verifikationsprüfungen an.', 'wp-agent-companion' ); ?></p>
				<?php else : ?>
					<p><?php esc_html_e( 'Der Agent sieht ausschließlich die Abilities, die im aktiven wpagently-Profil erlaubt sind. Jede Ability prüft weiterhin die WordPress-Rechte des gewählten Nutzers.', 'wp-agent-companion' ); ?></p>
				<?php endif; ?>
				<?php if ( wpagent_companion_oauth_scope_contains( (string) $validated['scope'], 'offline_access' ) ) : ?>
					<p><?php esc_html_e( 'Diese Verbindung darf ihren kurzlebigen Zugang im Hintergrund erneuern und bleibt aktiv, bis du sie unter wpagently > Agent verbinden widerrufst.', 'wp-agent-companion' ); ?></p>
				<?php endif; ?>
			</div>
			<?php if ( empty( $users ) ) : ?>
				<div class="notice notice-error inline"><p><?php esc_html_e( 'Es gibt keinen geeigneten Redakteur. Lege zuerst unter wpagently > Agent verbinden einen dedizierten Agent-Nutzer an.', 'wp-agent-companion' ); ?></p></div>
			<?php else : ?>
			<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
				<input type="hidden" name="action" value="wpagently_oauth_decision">
				<?php wp_nonce_field( 'wpagent_companion_oauth_authorize' ); ?>
				<?php foreach ( $request as $key => $value ) : ?>
					<input type="hidden" name="<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $value ); ?>">
				<?php endforeach; ?>
				<label for="connection_user"><strong><?php esc_html_e( 'Agent-Nutzer', 'wp-agent-companion' ); ?></strong></label>
				<select id="connection_user" name="connection_user" required>
					<?php foreach ( $users as $user ) : ?>
						<option value="<?php echo esc_attr( (string) $user['id'] ); ?>"><?php echo esc_html( $user['name'] . ' (' . $user['login'] . ')' ); ?></option>
					<?php endforeach; ?>
				</select>
				<p class="wpagently-oauth-detail"><?php esc_html_e( 'Administratoren und Super-Administratoren stehen hier bewusst nicht zur Auswahl.', 'wp-agent-companion' ); ?></p>
				<div class="wpagently-oauth-actions">
					<button class="button button-primary" type="submit" name="decision" value="approve"><?php esc_html_e( 'Verbindung freigeben', 'wp-agent-companion' ); ?></button>
					<button class="button" type="submit" name="decision" value="deny"><?php esc_html_e( 'Ablehnen', 'wp-agent-companion' ); ?></button>
				</div>
			</form>
			<?php endif; ?>
		</div>
	</div>
	<?php
}
