<?php

namespace Limb_Chatbot\Includes\AI_Providers\Grok\Utilities;

use Limb_Chatbot\Includes\AI_Providers\Grok\Grok;
use Limb_Chatbot\Includes\AI_Providers\Grok\Endpoints\Chat_Completion\Chat_Completion_Endpoint;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Utilities\Copilot_Utility as Global_Utility;

/**
 * Utility class for managing copilot operations using the xAI provider.
 *
 * Provides methods for generating AI-powered questions and messages
 * in the context of chatbot actions and data collection.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Grok\Utilities
 * @since 1.0.12
 */
class Copilot_Utility {

	/**
	 * Configuration object associated with this utility.
	 *
	 * May be null if no configuration is found or set.
	 *
	 * @var Config|null
	 * @since 1.0.12
	 */
	public ?Config $config;

	/**
	 * Global copilot utility instance for shared operations.
	 *
	 * @var Global_Utility
	 * @since 1.0.12
	 */
	public Global_Utility $global_utility;

	/**
	 * Timeout duration in seconds for the request.
	 *
	 * @var int|null
	 * @since 1.0.12
	 */
	public ?int $timeout = 60;

	/**
	 * AI model to use for copilot operations.
	 *
	 * @var AI_Model|null
	 * @since 1.0.12
	 */
	public ?AI_Model $ai_model = null;

	/**
	 * Endpoint instance handling API calls.
	 *
	 * @var Chat_Completion_Endpoint
	 * @since 1.0.12
	 */
	public Chat_Completion_Endpoint $endpoint;

	/**
	 * Constructor.
	 *
	 * Initializes the utility with a global utility instance, sets the default config if missing,
	 * and initializes the chat completions endpoint.
	 *
	 * @param  Global_Utility  $global_utility  Global copilot utility instance.
	 *
	 * @since 1.0.12
	 */
	public function __construct( Global_Utility $global_utility ) {
		$this->global_utility = $global_utility;
		if ( is_null( $this->global_utility->config ) ) {
			$this->config = Config::where( array( 'default' => true, 'related_to' => Grok::$id ) )->first();
		} else {
			$this->config = $this->global_utility->config;
		}
		$this->ai_model = $this->global_utility->ai_model;
		$this->endpoint = new Chat_Completion_Endpoint( $this );
	}

	/**
	 * Returns the configuration object used by this utility.
	 *
	 * @return Config|null Configuration object or null if not set.
	 * @since 1.0.12
	 */
	public function get_config(): ?Config {
		return $this->config;
	}

	/**
	 * Timeout duration in seconds for the copilot operation.
	 *
	 * @return int|null
	 * @since 1.0.12
	 */
	public function get_timeout(): ?int {
		return $this->timeout;
	}

	/**
	 * Get the AI model.
	 *
	 * @return AI_Model|null
	 * @since 1.0.12
	 */
	public function get_ai_model(): ?AI_Model {
		return $this->ai_model ?? $this->global_utility->ai_model;
	}

	/**
	 * Generate simple text response from AI using the configured endpoint.
	 *
	 * This method is used to generate straightforward text responses based on
	 * the provided messages. It extracts just the text content from the AI's response.
	 *
	 * @param  mixed  $messages  Collection or array of Message objects for the AI.
	 * @param  bool  $stream  Whether to stream the response.
	 * @param  array  $params  Optional additional parameters for the request.
	 *
	 * @return string The generated text content.
	 * @throws Exception If the request fails.
	 * @since 1.0.12
	 */
	public function generate_text( $messages, bool $stream = false, array $params = array() ): string {
		$response = $this->endpoint->make_request( $messages, $stream, $params );
		$message  = $response->get_message();

		if ( $message instanceof Message ) {
			$content = $message->get_content();
			if ( is_array( $content ) && isset( $content[0]['text']['value'] ) ) {
				return $content[0]['text']['value'];
			}
			if ( is_string( $content ) ) {
				return $content;
			}
		}

		return '';
	}

	/**
	 * Make a request to the AI endpoint.
	 *
	 * @param  Collection|array  $messages  Messages to send.
	 * @param  bool  $stream  Whether to stream the response.
	 * @param  array  $params  Optional generation parameters.
	 *
	 * @return mixed Response handler from HTTP client.
	 * @throws Exception If request fails.
	 * @since 1.0.12
	 */
	public function make_request( $messages, bool $stream = false, array $params = array() ) {
		return $this->endpoint->make_request( $messages, $stream, $params );
	}

	/**
	 * Generate simple text response from AI for data collection questions.
	 *
	 * This method is used to generate straightforward text responses based on
	 * the provided messages. It extracts just the text content from the AI's response.
	 *
	 * @param  mixed  $messages  Collection or array of Message objects for the AI.
	 * @param  bool  $stream  Whether to stream the response.
	 *
	 * @return Message The generated text response.
	 * @throws Exception If the request fails.
	 * @since 1.0.12
	 */
	public function generate_data_collect_question( $messages, $stream = false ): Message {
		$response = $this->endpoint->make_request( $messages, $stream );
		return $response->get_message();
	}

	/**
	 * Generate a beautiful success message for action completion.
	 *
	 * Generates a warm, celebratory message based on the action context.
	 * Delegates to the endpoint to call the AI provider.
	 *
	 * @param  Collection  $messages  Collection of Message objects with system and user prompts.
	 * @param  bool  $stream  Whether to stream the response.
	 *
	 * @return Message The generated success message.
	 * @throws Exception If message generation fails.
	 * @since 1.0.12
	 */
	public function generate_action_success_message( $messages, $stream = false ): Message {
		$response = $this->endpoint->make_request( $messages, $stream );
		return $response->get_message();
	}

	/**
	 * Generate action success message with extracted variables context.
	 *
	 * Creates a beautiful success message that includes information from extracted variables.
	 *
	 * @param  Collection  $messages  Collection of Message objects with context and variables.
	 * @param  bool  $stream  Whether to stream the response.
	 *
	 * @return Message The generated success message with extracted variables.
	 * @throws Exception If message generation fails.
	 * @since 1.0.12
	 */
	public function generate_action_success_message_with_context( $messages, $stream = false ): Message {
		$response = $this->endpoint->make_request( $messages, $stream );
		return $response->get_message();
	}

	/**
	 * Rerank a list of messages using the configured endpoint.
	 *
	 * This method sends the messages to the endpoint for reranking based on relevance or other criteria.
	 *
	 * @param  array  $messages  Array of Message objects to be reranked.
	 *
	 * @return null|Message The reranked list of messages from the endpoint.
	 * @throws Exception If the request fails.
	 * @since 1.0.9
	 */
	public function rerank( $messages ) {
		$this->ai_model = AI_Model::find_by_name( 'grok-4-1-fast-non-reasoning' );
		$response       = $this->endpoint->make_request( $messages, false, array( 'temperature' => 0 ) );

		return $response->get_message();
	}
}

