<?php

namespace Limb_Chatbot\Includes\Factories;

use Limb_Chatbot\Includes\AI_Providers\AI_Provider;
use Limb_Chatbot\Includes\Data_Objects\Limit;
use Limb_Chatbot\Includes\Data_Objects\Message;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Interfaces\Token_Calculator_Interface;

/**
 * Factory class to create Token Calculator instances based on AI provider.
 *
 * @since 1.0.0
 */
class Token_Calculator_Factory {

	/**
	 * Creates a Token_Calculator_Interface implementation instance.
	 *
	 * @param  Message  $message  The message object for token calculation context.
	 * @param  Limit  $limit  The limit object, usually linked to a chatbot.
	 * @param  AI_Provider|null  $ai_provider  Optional AI provider; if not passed, fetched from limit's chatbot.
	 *
	 * @return Token_Calculator_Interface
	 *
	 * @throws Exception Throws on missing Token_Calculator implementation or class.
	 *
	 * @since 1.0.0
	 */
	public function make( Message $message, Limit $limit, ?AI_Provider $ai_provider = null ): Token_Calculator_Interface {
		$ai_provider = $ai_provider ?: $limit->get_chatbot()->get_ai_provider();
		if ( is_null( $ai_provider ) ) {
			throw ( new Exception( Error_Codes::AI_PROVIDER_NOT_SET, __( 'Ai Provider isn\'t setup.', 'limb-chatbot' ) ) )->with_link( null, $limit->get_chatbot(), null, 'chatbot', 'ai-settings', 'config_id' );
		}
		$class = 'Limb_Chatbot\\Includes\\AI_Providers\\' . $ai_provider::$name . '\\Services\\Token_Calculator';
		if ( class_exists( $class ) ) {
			return new $class( $message, $limit->get_chatbot() );
		}
		throw new Exception( Error_Codes::TECHNICAL_ERROR, __( 'Technical error.', 'limb-chatbot' ) );
	}
}