<?php

namespace Limb_Chatbot\Includes\AI_Providers\Open_Router\Utilities;

use Limb_Chatbot\Includes\AI_Providers\Open_Router\Endpoints\Chat_Completion_Endpoint;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
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;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\AI_Providers\Open_Router\Open_Router;

/**
 * Utility class for managing copilot operations using the OpenRouter provider.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Open_Router\Utilities
 * @since 1.0.14
 */
class Copilot_Utility {

	/**
	 * Configuration object associated with this utility.
	 *
	 * @since 1.0.14
	 * @var Config|null
	 */
	public ?Config $config;

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

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

	/**
	 * AI model for copilot operations.
	 *
	 * @var AI_Model|null
	 * @since 1.0.14
	 */
	public $ai_model = null;

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

	/**
	 * Constructor.
	 *
	 * Initializes the utility with a global utility instance, sets the default config if missing,
	 * and initializes the chat completion endpoint.
	 *
	 * @param  Global_Utility  $global_utility  Global copilot utility instance.
	 *
	 * @since 1.0.14
	 */
	public function __construct( Global_Utility $global_utility ) {
		$this->global_utility = $global_utility;
		if ( is_null( $this->global_utility->config ) ) {
			$this->config = Config::where( [ 'default' => true, 'related_to' => Open_Router::class ] )->first();
		}
		$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.14
	 */
	public function get_config(): ?Config {
		return $this->config;
	}

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

	/**
	 * Proxy method to retrieve a search query from the endpoint.
	 *
	 * @param  mixed  $messages  Messages or collection of messages to process.
	 *
	 * @return Message The search query returned by the endpoint.
	 *
	 * @throws Exception
	 * @since 1.0.14
	 */
	public function is_vector_search_applicable( $messages ) {
		return $this->endpoint->is_vector_search_applicable( $messages );
	}

	/**
	 * Analyze a single conversation turn using the configured endpoint.
	 *
	 * @param  array  $messages  Array of Message objects representing the current conversation turn.
	 *
	 * @return array The result of the analysis from the endpoint.
	 * @throws Exception
	 * @since 1.0.14
	 */
	public function analyze_turn( $messages ) {
		$this->ai_model = AI_Model::find_by_name( 'z-ai/glm-4.5-air:free' ) ?? null;

		return $this->endpoint->analyze_turn( $messages );
	}

	/**
	 * Generate simple text response from AI using the configured endpoint.
	 *
	 * @param  Collection|array  $messages  Messages to process.
	 * @param  bool  $stream  Whether to use streaming.
	 * @param  array  $params  Optional generation parameters.
	 *
	 * @return Message|null The generated response message.
	 * @throws Exception
	 * @since 1.0.14
	 */
	public function generate_text( $messages, $stream = false, array $params = [] ): ?Message {
		$this->ai_model = AI_Model::find_by_name( 'z-ai/glm-4.5-air:free' ) ?? null;

		return $this->endpoint->make_request( $messages, $stream, $params )->get_response_message();
	}

	/**
	 * 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.
	 *
	 * @return Message The generated text response.
	 * @throws Exception
	 * @since 1.0.14
	 */
	public function generate_data_collect_question( $messages, $stream = false ) {
		return $this->endpoint->generate_data_collect_question( $messages, $stream );
	}

	/**
	 * 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
	 *
	 * @return Message The generated success message
	 * @throws Exception If message generation fails
	 * @since 1.0.14
	 */
	public function generate_action_success_message( $messages, $stream = false ) {
		$this->ai_model = AI_Model::find_by_name( 'z-ai/glm-4.5-air:free' ) ?? null;

		return $this->endpoint->generate_action_success_message( $messages, $stream );
	}

	/**
	 * 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
	 *
	 * @return Message The generated success message with extracted variables
	 * @throws Exception If message generation fails
	 * @since 1.0.14
	 */
	public function generate_action_success_message_with_context( $messages, $stream = false ) {
		return $this->endpoint->generate_action_success_message( $messages, $stream );
	}

	/**
	 * 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
	 * @since 1.0.9
	 */
	public function rerank( $messages ) {
		$this->ai_model = AI_Model::find_by_name( 'openai/gpt-4.1-nano' ) ?? null;

		return $this->endpoint->rerank( $messages );
	}

	public function generate_json_message_for_rerank( $messages ) {
		$this->ai_model = AI_Model::find_by_name( 'openai/gpt-4.1-nano' ) ?? null;

		return $this->endpoint->generate_rerank_json_message( $messages );
	}

	public function generate_json_message( $messages ) {
		$this->ai_model = AI_Model::find_by_name( 'openai/gpt-4.1-nano' ) ?? null;

		return $this->endpoint->generate_json_message($messages);
	}
}
