<?php
/**
 * GigaChat API Client
 *
 * Unified client for GigaChat text generation (chat/completions) and
 * image generation (chat + file download).
 * Uses WordPress HTTP API instead of Guzzle.
 *
 * @package SmartyPress_AI_Engine
 * @since 1.1.0
 */

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

/**
 * GigaChat Client class
 */
class SmartyPress_AI_GigaChat_Client {

	/**
	 * API base URI
	 */
	const BASE_URI          = 'https://gigachat.devices.sberbank.ru/api/v1';
	const BUSINESS_BASE_URI = 'https://api.giga.chat/v1';

	/**
	 * API endpoints
	 */
	const CHAT_ENDPOINT   = '/chat/completions';
	const MODELS_ENDPOINT = '/models';
	const FILES_ENDPOINT  = '/files';

	/**
	 * Auth manager instance
	 *
	 * @var SmartyPress_AI_GigaChat_Auth_Manager
	 */
	private $auth_manager;

	/**
	 * SSL verify setting
	 *
	 * @var bool
	 */
	private $verify_ssl;

	/**
	 * Selected GigaChat API base URL.
	 *
	 * @var string
	 */
	private $base_url;

	/**
	 * Constructor
	 *
	 * @param string $auth_key   Authorization key (base64 of client_id:client_secret).
	 * @param string $scope      API scope.
	 * @param bool   $verify_ssl Whether to verify SSL certificate.
	 * @param string $base_url   GigaChat API base URL.
	 */
	public function __construct( $auth_key, $scope = 'GIGACHAT_API_PERS', $verify_ssl = true, $base_url = self::BASE_URI ) {
		$this->auth_manager = new SmartyPress_AI_GigaChat_Auth_Manager( $auth_key, $scope, $verify_ssl );
		$this->verify_ssl   = $verify_ssl;
		$this->base_url     = $this->normalize_base_url( $base_url );
	}

	/**
	 * Send chat completion request
	 *
	 * @param array  $messages Array of messages [{role, content}, ...].
	 * @param string $model    Model name.
	 * @param array  $options  Options: temperature, max_tokens, top_p, repetition_penalty.
	 * @return array {success, data} or {success, error, code}.
	 */
	public function chat( $messages, $model = 'GigaChat-2', $options = array() ) {
		$token = $this->auth_manager->get_access_token();

		$body = array(
			'model'    => $model,
			'messages' => $messages,
			'stream'   => false,
		);

		// Optional parameters.
		if ( isset( $options['temperature'] ) ) {
			$body['temperature'] = floatval( $options['temperature'] );
		}
		if ( isset( $options['max_tokens'] ) && intval( $options['max_tokens'] ) > 0 ) {
			$body['max_tokens'] = intval( $options['max_tokens'] );
		}
		if ( isset( $options['top_p'] ) ) {
			$body['top_p'] = floatval( $options['top_p'] );
		}
		if ( isset( $options['repetition_penalty'] ) ) {
			$body['repetition_penalty'] = floatval( $options['repetition_penalty'] );
		}

		// For image generation, enable function calling.
		if ( ! empty( $options['function_call'] ) ) {
			$body['function_call'] = $options['function_call'];
		}

		$response = wp_remote_post(
			$this->get_endpoint_url( self::CHAT_ENDPOINT ),
			array(
				'headers'   => array(
					'Content-Type'  => 'application/json',
					'Accept'        => 'application/json',
					'Authorization' => 'Bearer ' . $token,
				),
				'body'      => wp_json_encode( $body ),
				'timeout'   => 120,
				'sslverify' => $this->verify_ssl,
			)
		);

		return $this->handle_response( $response );
	}

	/**
	 * Generate image via chat completions
	 *
	 * Sends a prompt that instructs the model to draw an image,
	 * extracts the file ID from the response, and downloads the image.
	 *
	 * @param string $prompt  Image generation prompt.
	 * @param array  $options Options: model, system_message.
	 * @return array {success, b64_json, file_id} or {success, error}.
	 */
	public function create_image( $prompt, $options = array() ) {
		$model = isset( $options['model'] ) ? $options['model'] : 'GigaChat-2';

		$messages = array();

		// Add system message if provided.
		if ( ! empty( $options['system_message'] ) ) {
			$messages[] = array(
				'role'    => 'system',
				'content' => $options['system_message'],
			);
		}

		$messages[] = array(
			'role'    => 'user',
			'content' => $prompt,
		);

		// Send chat request with function_call auto.
		$result = $this->chat(
			$messages,
			$model,
			array(
				'function_call' => 'auto',
				'temperature'   => isset( $options['temperature'] ) ? $options['temperature'] : 0.7,
			)
		);

		if ( ! $result['success'] ) {
			return $result;
		}

		// Extract content from response.
		$content = isset( $result['data']['choices'][0]['message']['content'] )
			? $result['data']['choices'][0]['message']['content']
			: '';

		if ( empty( $content ) ) {
			return array(
				'success' => false,
				'error'   => __( 'Empty response from GigaChat image generation.', 'smartypress-ai-engine' ),
			);
		}

		// Extract file ID from <img src="file_id"> tag.
		$file_id = $this->extract_file_id( $content );

		if ( ! $file_id ) {
			return array(
				'success' => false,
				'error'   => __( 'Could not find image file ID in GigaChat response.', 'smartypress-ai-engine' ),
			);
		}

		// Download the image.
		$image_data = $this->download_file( $file_id );

		if ( ! $image_data['success'] ) {
			return $image_data;
		}

		return array(
			'success'  => true,
			'b64_json' => $image_data['b64_json'],
			'file_id'  => $file_id,
		);
	}

	/**
	 * Download file content from GigaChat
	 *
	 * @param string $file_id File ID to download.
	 * @return array {success, b64_json} or {success, error}.
	 */
	public function download_file( $file_id ) {
		$token = $this->auth_manager->get_access_token();

		$response = wp_remote_get(
			$this->get_endpoint_url( self::FILES_ENDPOINT . '/' . rawurlencode( $file_id ) . '/content' ),
			array(
				'headers'   => array(
					'Accept'        => 'application/jpg',
					'Authorization' => 'Bearer ' . $token,
				),
				'timeout'   => 60,
				'sslverify' => $this->verify_ssl,
			)
		);

		if ( is_wp_error( $response ) ) {
			return array(
				'success' => false,
				'error'   => $response->get_error_message(),
			);
		}

		$code = wp_remote_retrieve_response_code( $response );

		if ( 200 !== $code ) {
			return array(
				'success' => false,
				'error'   => sprintf(
					/* translators: %d: HTTP status code */
					__( 'Failed to download GigaChat image (HTTP %d).', 'smartypress-ai-engine' ),
					$code
				),
				'code'    => $code,
			);
		}

		$body = wp_remote_retrieve_body( $response );

		if ( empty( $body ) ) {
			return array(
				'success' => false,
				'error'   => __( 'Empty image data from GigaChat.', 'smartypress-ai-engine' ),
			);
		}

		// Encode to base64.
		return array(
			'success'  => true,
			'b64_json' => base64_encode( $body ),
		);
	}

	/**
	 * Extract file ID from HTML img tag in GigaChat response
	 *
	 * GigaChat returns image references as: <img src="file_id" fuse="true"/>
	 *
	 * @param string $content Response content.
	 * @return string|null File ID or null if not found.
	 */
	private function extract_file_id( $content ) {
		if ( preg_match( '/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $content, $matches ) ) {
			return $matches[1];
		}
		return null;
	}

	/**
	 * Handle HTTP response
	 *
	 * @param array|WP_Error $response WordPress HTTP response.
	 * @return array {success, data} or {success, error, code}.
	 */
	private function handle_response( $response ) {
		if ( is_wp_error( $response ) ) {
			return array(
				'success' => false,
				'error'   => $response->get_error_message(),
			);
		}

		$code = wp_remote_retrieve_response_code( $response );
		$body = wp_remote_retrieve_body( $response );
		$data = json_decode( $body, true );

		if ( json_last_error() !== JSON_ERROR_NONE ) {
			return array(
				'success' => false,
				'error'   => __( 'Failed to decode GigaChat API response.', 'smartypress-ai-engine' ),
			);
		}

		if ( 200 !== $code ) {
			$error = isset( $data['message'] )
				? $data['message']
				: __( 'Unknown GigaChat API error', 'smartypress-ai-engine' );

			return array(
				'success' => false,
				'error'   => $error,
				'code'    => $code,
			);
		}

		return array(
			'success' => true,
			'data'    => $data,
		);
	}

	/**
	 * Get the auth manager instance
	 *
	 * @return SmartyPress_AI_GigaChat_Auth_Manager
	 */
	public function get_auth_manager() {
		return $this->auth_manager;
	}

	/**
	 * Get the selected base URL.
	 *
	 * @return string
	 */
	public function get_base_url() {
		return $this->base_url;
	}

	/**
	 * Get full URL for an API endpoint.
	 *
	 * @param string $endpoint Endpoint path.
	 * @return string
	 */
	public function get_endpoint_url( $endpoint ) {
		return $this->base_url . '/' . ltrim( $endpoint, '/' );
	}

	/**
	 * Normalize the base URL to one of the official GigaChat API endpoints.
	 *
	 * @param string $base_url Raw base URL.
	 * @return string
	 */
	private function normalize_base_url( $base_url ) {
		$base_url = untrailingslashit( (string) $base_url );
		$allowed  = array( self::BASE_URI, self::BUSINESS_BASE_URI );

		return in_array( $base_url, $allowed, true ) ? $base_url : self::BASE_URI;
	}
}
