<?php
/**
 * Credential-free setup preflight and connection instructions.
 *
 * @package WPAgentCompanion
 */

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

/**
 * Local, credential-free prerequisites shown before a first client connection.
 *
 * The environment check deliberately stays advisory: a production site can be
 * connected safely, but a staging site is the better first destination for a
 * new agent. PHP, WordPress and transport are hard prerequisites and therefore
 * have their own deterministic statuses instead of being hidden in a generic
 * diagnostics message.
 *
 * @return array{php:array{label:string,ok:bool,actual:string,detail:string,minimum:string},wordpress:array{label:string,ok:bool,actual:string,detail:string,minimum:string},https:array{label:string,ok:bool,actual:string,detail:string},staging:array{label:string,ok:bool,actual:string,detail:string}}
 */
function wpagent_companion_connection_setup_preflight(): array {
	$wordpress_version = (string) get_bloginfo( 'version' );
	$environment       = sanitize_key( (string) wp_get_environment_type() );
	$environment       = '' !== $environment ? $environment : 'production';
	$site_scheme       = strtolower( (string) wp_parse_url( home_url( '/' ), PHP_URL_SCHEME ) );
	$mcp_scheme        = strtolower( (string) wp_parse_url( wpagent_companion_mcp_endpoint(), PHP_URL_SCHEME ) );
	$local_http        = 'http' === $site_scheme && 'http' === $mcp_scheme && 'local' === $environment;
	$https_ok          = ( 'https' === $site_scheme && 'https' === $mcp_scheme ) || $local_http;
	$transport_actual  = $site_scheme === $mcp_scheme
		? ( 'https' === $site_scheme ? 'https' : ( $local_http ? 'http (local)' : ( '' !== $site_scheme ? $site_scheme : __( 'unbekannt', 'wp-agent-companion' ) ) ) )
		: sprintf(
			/* translators: 1: website scheme, 2: MCP endpoint scheme. */
			__( 'Website: %1$s, MCP: %2$s', 'wp-agent-companion' ),
			'' !== $site_scheme ? $site_scheme : __( 'unbekannt', 'wp-agent-companion' ),
			'' !== $mcp_scheme ? $mcp_scheme : __( 'unbekannt', 'wp-agent-companion' )
		);
	$staging           = 'staging' === $environment;

	return array(
		'php'       => array(
			'label'   => __( 'PHP 8.1+', 'wp-agent-companion' ),
			'ok'      => version_compare( PHP_VERSION, '8.1', '>=' ),
			'actual'  => PHP_VERSION,
			'minimum' => '8.1',
			'detail'  => version_compare( PHP_VERSION, '8.1', '>=' )
				? __( 'Die PHP-Voraussetzung ist erfüllt.', 'wp-agent-companion' )
				: __( 'WPAgently benötigt PHP 8.1 oder neuer.', 'wp-agent-companion' ),
		),
		'wordpress' => array(
			'label'   => __( 'WordPress 6.9+', 'wp-agent-companion' ),
			'ok'      => version_compare( $wordpress_version, '6.9', '>=' ),
			'actual'  => $wordpress_version,
			'minimum' => '6.9',
			'detail'  => version_compare( $wordpress_version, '6.9', '>=' )
				? __( 'Die WordPress-Voraussetzung ist erfüllt.', 'wp-agent-companion' )
				: __( 'WPAgently benötigt WordPress 6.9 oder neuer.', 'wp-agent-companion' ),
		),
		'https'     => array(
			'label'  => __( 'HTTPS', 'wp-agent-companion' ),
			'ok'     => $https_ok,
			'actual' => $transport_actual,
			'detail' => $https_ok
				? ( $local_http ? __( 'Lokales HTTP ist ausschließlich für lokale Tests erlaubt.', 'wp-agent-companion' ) : __( 'Die Website ist über HTTPS erreichbar.', 'wp-agent-companion' ) )
				: __( 'Browser-OAuth und externe Verbindungen benötigen HTTPS. Für lokale Tests setze WP_ENVIRONMENT_TYPE auf local.', 'wp-agent-companion' ),
		),
		'staging'   => array(
			'label'  => __( 'Staging', 'wp-agent-companion' ),
			'ok'     => $staging,
			'actual' => $environment,
			'detail' => $staging
				? __( 'Du richtest die Verbindung auf einer Staging-Umgebung ein.', 'wp-agent-companion' )
				: __( 'Die Verbindung ist auch hier möglich. Prüfe neue schreibende Abläufe zuerst auf Staging.', 'wp-agent-companion' ),
		),
	);
}

/**
 * Quotes a WordPress-controlled site URL for a Unix shell command without
 * turning a malformed site setting into executable shell syntax.
 */
function wpagent_companion_connection_shell_quote( string $value ): string {
	return "'" . str_replace( "'", "'\"'\"'", $value ) . "'";
}

/**
 * Rebuilds a display-only connection URL without user info, query or fragment.
 *
 * A normal WordPress URL never contains credentials, but this extra boundary
 * keeps a malformed URL filter from placing an accidental secret into a
 * copyable instruction. The actual connection code retains its own canonical
 * endpoint handling and never consumes this display value.
 */
function wpagent_companion_connection_setup_public_url( string $url ): string {
	$parts  = wp_parse_url( $url );
	$scheme = is_array( $parts ) && is_string( $parts['scheme'] ?? null ) ? strtolower( $parts['scheme'] ) : '';
	$host   = is_array( $parts ) && is_string( $parts['host'] ?? null ) ? $parts['host'] : '';
	$path   = is_array( $parts ) && is_string( $parts['path'] ?? null ) ? $parts['path'] : '';
	$port   = is_array( $parts ) ? absint( $parts['port'] ?? 0 ) : 0;
	if ( ! in_array( $scheme, array( 'http', 'https' ), true ) || '' === $host || $port > 65535 ) {
		return '';
	}

	if ( str_starts_with( $host, '[' ) && str_ends_with( $host, ']' ) ) {
		$host = substr( $host, 1, -1 );
	}
	$authority = str_contains( $host, ':' ) ? '[' . $host . ']' : $host;
	if ( $port > 0 ) {
		$authority .= ':' . $port;
	}
	return $scheme . '://' . $authority . $path;
}

/**
 * Returns a copyable, client-specific instruction without credential material.
 *
 * The Application Password fallback intentionally receives actions only. Its
 * generated local file is the sole place that may contain its one-time secret.
 */
function wpagent_companion_connection_setup_prompt( string $client ): string {
	$client = wpagent_companion_normalize_connection_client( $client );
	if ( ! in_array( $client, wpagent_companion_connection_clients(), true ) ) {
		return '';
	}

	$endpoint   = wpagent_companion_connection_setup_public_url( wpagent_companion_mcp_endpoint() );
	$site       = untrailingslashit( wpagent_companion_connection_setup_public_url( home_url( '/' ) ) );
	if ( '' === $site ) {
		return '';
	}
	$shell_site = wpagent_companion_connection_shell_quote( $site );
	$label      = wpagent_companion_connection_client_labels()[ $client ];
	if ( in_array( $client, array( 'chatgpt', 'cursor', 'vscode' ), true ) && '' === $endpoint ) {
		return '';
	}

	switch ( $client ) {
		case 'codex':
			return sprintf(
				/* translators: 1: shell-quoted site URL. */
				__( "Codex per Browser-OAuth verbinden:\nwp-agent init --agent codex --scope user --site %1\$s --i-approve\n\nFühre danach den von wp-agent ausgegebenen codex mcp login-Befehl aus und bestätige die Freigabe im Browser. Diese Anweisung enthält keine Zugangsdaten.", 'wp-agent-companion' ),
				$shell_site
			);
		case 'claude-code':
			return sprintf(
				/* translators: 1: shell-quoted site URL. */
				__( "Claude Code per Browser-OAuth verbinden:\nwp-agent init --agent claude --scope user --site %1\$s --i-approve\n\nÖffne anschließend /mcp in Claude Code und bestätige die Freigabe im Browser. Diese Anweisung enthält keine Zugangsdaten.", 'wp-agent-companion' ),
				$shell_site
			);
		case 'chatgpt':
			return sprintf(
				/* translators: 1: MCP endpoint. */
				__( "ChatGPT per OAuth verbinden:\nErstelle im Entwicklermodus eine benutzerdefinierte App mit diesem entfernten MCP-Endpunkt:\n%1\$s\n\nStarte die WordPress-Freigabe im Browser und wähle den dedizierten Agent-Nutzer. Diese Anweisung enthält keine Zugangsdaten.", 'wp-agent-companion' ),
				$endpoint
			);
		case 'cursor':
		case 'vscode':
			return sprintf(
				/* translators: 1: client name, 2: MCP endpoint. */
				__( "%1\$s per OAuth verbinden:\nLege einen entfernten Streamable-HTTP-MCP-Server mit dieser URL an:\n%2\$s\n\nWähle beim ersten Verbinden die Browser-Freigabe und bestätige den dedizierten Agent-Nutzer. Diese Anweisung enthält keine Zugangsdaten.", 'wp-agent-companion' ),
				$label,
				$endpoint
			);
		case 'claude-desktop':
			return __( "Claude Desktop verbinden:\nLade unten die sitespezifische .mcpb-Datei einmalig herunter, öffne sie lokal mit Claude Desktop und bestätige die Erweiterung. Diese Anweisung enthält keine Zugangsdaten.", 'wp-agent-companion' );
		default:
			return sprintf(
				/* translators: 1: client name. */
				__( "%1\$s verbinden:\nLade unten die sitespezifische Konfiguration einmalig herunter, führe sie mit der vorhandenen Client-Konfiguration zusammen und starte den Client neu. Diese Anweisung enthält keine Zugangsdaten.", 'wp-agent-companion' ),
				$label
			);
	}
}
