<?php

namespace Limb_Chatbot\Includes\Ai_Providers;

use Limb_Chatbot\Includes\AI_Providers\Claude\Claude;
use Limb_Chatbot\Includes\AI_Providers\Deep_Seek\Deep_Seek;
use Limb_Chatbot\Includes\AI_Providers\Gemini\Gemini;
use Limb_Chatbot\Includes\AI_Providers\Grok\Grok;
use Limb_Chatbot\Includes\AI_Providers\Open_Ai\Open_Ai;
use Limb_Chatbot\Includes\AI_Providers\Open_Router\Open_Router;
use Limb_Chatbot\Includes\Traits\SingletonTrait;

/**
 * Singleton class managing multiple AI provider instances.
 *
 * Handles loading, instantiation, and retrieval of AI providers.
 *
 * @package Limb_Chatbot\Includes\Ai_Providers
 * @since 1.0.0
 */
class AI_Providers {

	use SingletonTrait;

	/**
	 * Registered AI providers keyed by their unique ID.
	 *
	 * @since 1.0.0
	 * @var AI_Provider[]
	 */
	protected array $ai_providers = [];

	/**
	 * Initializes AI providers by applying the 'lbaic_ai_providers' filter.
	 *
	 * Instantiates providers from class names and ensures they extend AI_Provider.
	 * Sorts providers by their IDs.
	 *
	 * @return void
	 * @since 1.0.0
	 * @since 1.0.9 Added Claude
	 * @since 1.0.12 Added Grok
	 * @since 1.0.15 Added OpenRouter
	 *
	 */
	public function init() {
		$ai_providers = apply_filters( 'lbaic_ai_providers', [ Open_Ai::class, Gemini::class, Claude::class, Deep_Seek::class, Grok::class, Open_Router::class ] );
		foreach ( $ai_providers as $ai_provider ) {
			if ( is_string( $ai_provider ) && class_exists( $ai_provider ) ) {
				$ai_provider = new $ai_provider();
			}
			if ( ! is_a( $ai_provider, 'Limb_Chatbot\\Includes\\AI_Providers\\AI_Provider' ) ) {
				continue;
			}
			$this->ai_providers[ $ai_provider->get_id() ] = $ai_provider;
		}
		ksort( $this->ai_providers );
	}

	/**
	 * Retrieves all registered AI providers.
	 *
	 * @return AI_Provider[] Array of AI provider instances keyed by their ID.
	 * @since 1.0.0
	 *
	 */
	public function get_ai_providers(): array {
		return $this->ai_providers;
	}

	/**
	 * Retrieves a specific AI provider instance by its ID.
	 *
	 * Returns null if the provider is not registered.
	 *
	 * @param  string  $id  AI provider identifier.
	 *
	 * @return AI_Provider|null AI provider instance or null if not found.
	 * @since 1.0.0
	 *
	 */
	public function get_ai_provider( string $id ): ?AI_Provider {
		return $this->ai_providers[ $id ] ?? null;
	}
}
