<?php
/**
 * Shared HTTP client for OpenAI-compatible chat completion APIs.
 *
 * @package WP_PowerSuite\AI
 */

namespace WP_PowerSuite\AI;

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

final class OpenAiCompatibleClient {

	/**
	 * @param list<array{role: string, content: string}> $messages
	 * @param array<string, mixed>                       $options
	 */
	public static function chatCompletions(
		string $base_url,
		string $api_key,
		string $model,
		array $messages,
		array $options = []
	): string|\WP_Error {
		$headers = [
			'Authorization' => 'Bearer ' . $api_key,
			'Content-Type'  => 'application/json',
		];

		if ( ! empty( $options['extra_headers'] ) && is_array( $options['extra_headers'] ) ) {
			foreach ( $options['extra_headers'] as $name => $value ) {
				if ( is_string( $name ) && is_scalar( $value ) && (string) $value !== '' ) {
					$headers[ $name ] = (string) $value;
				}
			}
		}

		$body = [
			'model'    => $model,
			'messages' => $messages,
		];

		if ( self::supportsCustomTemperature( $model ) ) {
			$body['temperature'] = (float) ( $options['temperature'] ?? 0.2 );
		}

		$body = self::withTokenLimit( $body, (int) ( $options['max_tokens'] ?? 4096 ) );

		if ( ! empty( $options['json_mode'] ) ) {
			$body['response_format'] = [ 'type' => 'json_object' ];
		}

		$response = wp_remote_post(
			rtrim( $base_url, '/' ) . '/chat/completions',
			[
				'timeout' => (int) ( $options['timeout'] ?? 90 ),
				'headers' => $headers,
				'body'    => wp_json_encode( $body ),
			]
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$data = json_decode( (string) wp_remote_retrieve_body( $response ), true );
		if ( $code !== 200 || ! is_array( $data ) ) {
			$message = is_array( $data ) ? (string) ( $data['error']['message'] ?? '' ) : '';
			return new \WP_Error(
				'api_error',
				$message !== '' ? $message : __( 'AI request failed.', 'wp-powersuite' )
			);
		}

		$content = $data['choices'][0]['message']['content'] ?? '';

		return is_string( $content ) && $content !== ''
			? $content
			: new \WP_Error( 'empty_response', __( 'AI returned an empty response.', 'wp-powersuite' ) );
	}

	public static function testConnection( string $base_url, string $api_key, array $extra_headers = [] ): bool|\WP_Error {
		$headers = [
			'Authorization' => 'Bearer ' . $api_key,
		];

		foreach ( $extra_headers as $name => $value ) {
			if ( is_string( $name ) && is_scalar( $value ) && (string) $value !== '' ) {
				$headers[ $name ] = (string) $value;
			}
		}

		$response = wp_remote_get(
			rtrim( $base_url, '/' ) . '/models',
			[
				'timeout' => 20,
				'headers' => $headers,
			]
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
			return new \WP_Error( 'api_error', __( 'API connection failed.', 'wp-powersuite' ) );
		}

		return true;
	}

	/**
	 * Recommended headers for OpenRouter attribution.
	 *
	 * @return array<string, string>
	 */
	public static function openRouterHeaders(): array {
		return [
			'HTTP-Referer' => home_url( '/' ),
			'X-Title'      => 'WP PowerSuite',
		];
	}

	/**
	 * Whether the model expects max_completion_tokens instead of max_tokens.
	 */
	public static function usesMaxCompletionTokens( string $model ): bool {
		/**
		 * Filter whether an OpenAI-compatible model uses max_completion_tokens.
		 *
		 * @param bool   $uses     Default detection result.
		 * @param string $model_id Model ID or OpenRouter slug.
		 */
		return (bool) apply_filters(
			'wpps_openai_compatible_uses_max_completion_tokens',
			self::isRestrictedOpenAiModel( $model ),
			$model
		);
	}

	/**
	 * Whether the model accepts a custom temperature (GPT-5 / o-series only allow the default).
	 */
	public static function supportsCustomTemperature( string $model ): bool {
		/**
		 * Filter whether an OpenAI-compatible model accepts a custom temperature.
		 *
		 * @param bool   $supports Default detection result.
		 * @param string $model_id Model ID or OpenRouter slug.
		 */
		return (bool) apply_filters(
			'wpps_openai_compatible_supports_custom_temperature',
			! self::isRestrictedOpenAiModel( $model ),
			$model
		);
	}

	/**
	 * GPT-5 and o-series models use stricter Chat Completions parameters.
	 */
	private static function isRestrictedOpenAiModel( string $model ): bool {
		return (bool) preg_match( '/(?:^|\/)gpt-5|(?:^|\/)o\d/', $model );
	}

	/**
	 * Append the correct token limit key for the Chat Completions API.
	 *
	 * @param array<string, mixed> $body
	 * @return array<string, mixed>
	 */
	public static function withTokenLimit( array $body, int $max_tokens ): array {
		$model = isset( $body['model'] ) ? (string) $body['model'] : '';
		$key   = self::usesMaxCompletionTokens( $model ) ? 'max_completion_tokens' : 'max_tokens';
		$body[ $key ] = max( 1, $max_tokens );

		return $body;
	}
}
