<?php
/**
 * Class Loco_Automatic_Translate_Addon_Pro\AI_Translate\OpenAI\OpenAI_AI_API_Client
 */

namespace Loco_Automatic_Translate_Addon_Pro\AI_Translate\OpenAI;

use Loco_Automatic_Translate_Addon_Pro\AI_Translate\Services\Contracts\Authentication;
use Loco_Automatic_Translate_Addon_Pro\AI_Translate\Services\Contracts\Generative_AI_API_Client;
use Loco_Automatic_Translate_Addon_Pro\AI_Translate\Services\Traits\Generative_AI_API_Client_Trait;
use Felix_Arntz\WP_OOP_Plugin_Lib\HTTP\Contracts\Request;
use Felix_Arntz\WP_OOP_Plugin_Lib\HTTP\Get_Request;
use Felix_Arntz\WP_OOP_Plugin_Lib\HTTP\HTTP;
use Felix_Arntz\WP_OOP_Plugin_Lib\HTTP\JSON_Post_Request;

/**
 * Class to interact directly with the OpenAI API.
 */
class OpenAI_AI_API_Client implements Generative_AI_API_Client {
	use Generative_AI_API_Client_Trait;

	const DEFAULT_BASE_URL    = 'https://api.openai.com';
	const DEFAULT_API_VERSION = 'v1';

	/**
	 * The OpenAI API key authentication.
	 *
	 * @var Authentication
	 */
	private $authentication;

	/**
	 * The HTTP instance to use for requests.
	 *
	 * @var HTTP
	 */
	private $http;

	/**
	 * Constructor.
	 *
	 * @param Authentication $authentication The authentication credentials.
	 * @param HTTP           $http           The HTTP instance to use for requests.
	 */
	public function __construct( Authentication $authentication, HTTP $http ) {
		$this->authentication = $authentication;
		$this->http           = $http;
	}

	/**
	 * Creates a request instance to list the available models with their information.
	 *
	 * @param array<string, mixed> $params          Optional. The request parameters. Default empty array.
	 * @param array<string, mixed> $request_options Optional. The request options. Default empty array.
	 * @return Request The request instance.
	 */
	public function create_list_models_request( array $params = array(), array $request_options = array() ): Request {
		return $this->create_get_request( 'models', $params, $request_options );
	}

	/**
	 * Creates a request instance to generate content using the specified model.
	 *
	 * @param string               $model           The model slug.
	 * @param array<string, mixed> $params          The request parameters.
	 * @param array<string, mixed> $request_options Optional. The request options. Default empty array.
	 * @return Request The request instance.
	 */
	public function create_generate_content_request( string $model, array $params, array $request_options = array() ): Request {
		$params['model'] = $model;
		return $this->create_post_request( 'chat/completions', $params, $request_options );
	}

	/**
	 * Returns the HTTP instance to use for requests.
	 *
	 * @return HTTP The HTTP instance.
	 */
	protected function get_http(): HTTP {
		return $this->http;
	}

	/**
	 * Returns the human readable API name (without the "API" suffix).
	 *
	 * @return string The API name.
	 */
	protected function get_api_name(): string {
		return 'OpenAI';
	}

	/**
	 * Creates a GET request instance for the given parameters.
	 *
	 * @param string               $path            The path to the API endpoint, relative to the base URL and version.
	 * @param array<string, mixed> $params          The request parameters.
	 * @param array<string, mixed> $request_options Optional. The request options. Default empty array.
	 * @return Request The request instance.
	 */
	private function create_get_request( string $path, array $params, array $request_options = array() ): Request {
		$request = new Get_Request(
			$this->get_request_url( $path, $request_options ),
			$params,
			$request_options
		);
		$this->add_default_options( $request );
		$this->authentication->authenticate( $request );
		return $request;
	}

	/**
	 * Creates a POST request instance for the given parameters.
	 *
	 * @param string               $path            The path to the API endpoint, relative to the base URL and version.
	 * @param array<string, mixed> $params          The request parameters.
	 * @param array<string, mixed> $request_options Optional. The request options. Default empty array.
	 * @return Request The request instance.
	 */
	private function create_post_request( string $path, array $params, array $request_options = array() ): Request {
		$request = new JSON_Post_Request(
			$this->get_request_url( $path, $request_options ),
			$params,
			$request_options
		);
		$this->add_default_options( $request );
		$this->authentication->authenticate( $request );
		return $request;
	}

	/**
	 * Gets the request URL for the specified model and task.
	 *
	 * @param string               $path            The path to the API endpoint, relative to the base URL and version.
	 * @param array<string, mixed> $request_options Optional. The request options. Default empty array.
	 * @return string The request URL.
	 */
	private function get_request_url( string $path, array $request_options = array() ): string {
		$base_url    = $request_options['base_url'] ?? self::DEFAULT_BASE_URL;
		$api_version = $request_options['api_version'] ?? self::DEFAULT_API_VERSION;
		$path        = ltrim( $path, '/' );

		return "{$base_url}/{$api_version}/{$path}";
	}
}
