<?php

namespace Limb_Chatbot\Includes\AI_Providers\Gemini\Utilities;

use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\AI_Providers\Gemini\Endpoints\Token\Token_Endpoint;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;

/**
 * Class Token_Utility
 *
 * Utility class for token counting related operations.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Gemini\Utilities
 * @since 1.0.0
 */
class Token_Utility {

	/**
	 * The message object.
	 *
	 * @var Message
	 * @since 1.0.0
	 */
	public Message $message;

	/**
	 * AI model name used for token counting.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	public string $model_name;

	/**
	 * Optional config instance.
	 *
	 * @var Config|null
	 * @since 1.0.0
	 */
	public ?Config $config = null;

	/**
	 * Token_Utility constructor.
	 *
	 * @param  Message  $message  The message object to count tokens for.
	 * @param  Chatbot|null  $chatbot  Optional chatbot instance; if null, resolved via message's chat UUID.
	 *
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function __construct( Message $message, ?Chatbot $chatbot = null ) {
		$this->message = $message;
		if ( is_null( $chatbot ) ) {
			$chatbot = Chat::find_by_uuid( $this->message->get_chat_uuid() )->get_chatbot();
		}
		if ( is_null( $chatbot->get_ai_model() ) ) {
			throw ( new Exception( Error_Codes::AI_MODEL_NOT_SET, __( 'Ai model isn\'t setup.', 'limb-chatbot' ) ) )->with_link( null, $chatbot, null, 'chatbot', 'ai-settings', 'ai_model_id' );
		}
		$this->model_name = $chatbot->get_ai_model()->get_name();
		$this->config     = $chatbot->get_config();
	}

	/**
	 * Get the config instance.
	 *
	 * @return Config|null
	 * @since 1.0.0
	 */
	public function get_config(): ?Config {
		return $this->config;
	}

	/**
	 * Get the AI model name.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function get_model_name(): string {
		return $this->model_name;
	}

	/**
	 * Count tokens for the message.
	 *
	 * @return mixed Response from the Token_Endpoint count method.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function count() {
		return $this->get_endpoint_instance()->count();
	}

	/**
	 * Get the Token_Endpoint instance.
	 *
	 * @return Token_Endpoint
	 * @since 1.0.0
	 */
	public function get_endpoint_instance(): Token_Endpoint {
		return new Token_Endpoint( $this );
	}

	/**
	 * Get the API version used.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function get_version(): string {
		return 'v1beta';
	}

	/**
	 * Get the Message object.
	 *
	 * @return Message
	 * @since 1.0.0
	 */
	public function get_message(): Message {
		return $this->message;
	}
}