<?php
/**
 * Resolves the configured provider key into an instance.
 *
 * Premium engines (OpenAI, Hugging Face) live behind capability checks
 * in FindAstra_License. If a buyer somehow lands on a paid engine
 * without the license (e.g. they activated Pro, picked OpenAI, then
 * the license expired), `make()` silently falls back to Local so
 * search never breaks — the admin UI shows the upgrade prompt.
 *
 * @package FindAstra
 */

defined( 'ABSPATH' ) || exit;

final class FindAstra_Provider_Factory {

	public static function current(): FindAstra_Provider_Base {
		$settings = get_option(
			FindAstra_Admin::SETTINGS_OPTION,
			array( 'provider' => FindAstra_Provider_Local::KEY )
		);

		$key = isset( $settings['provider'] ) ? (string) $settings['provider'] : FindAstra_Provider_Local::KEY;

		return self::make( $key );
	}

	public static function make( string $key ): FindAstra_Provider_Base {
		// Use literal provider keys ('openai'/'huggingface') as case labels rather
		// than FindAstra_Provider_OpenAI::KEY etc.: those classes are absent from
		// the free build, so referencing their constants here would fatal. The key
		// strings are stable and match each provider's KEY constant in the paid build.
		switch ( $key ) {
			case 'openai':
				if ( FindAstra_License::can( 'engine.openai' ) && class_exists( 'FindAstra_Provider_OpenAI' ) ) {
					return new FindAstra_Provider_OpenAI();
				}
				// Absent (free build) or license expired — fall through to Local.
				return new FindAstra_Provider_Local();
			case 'huggingface':
				if ( FindAstra_License::can( 'engine.huggingface' ) && class_exists( 'FindAstra_Provider_HuggingFace' ) ) {
					return new FindAstra_Provider_HuggingFace();
				}
				return new FindAstra_Provider_Local();
			case FindAstra_Provider_Mock::KEY:
				if ( FindAstra_Provider_Mock::is_enabled() ) {
					return new FindAstra_Provider_Mock();
				}
				// fall through to default
			case FindAstra_Provider_Local::KEY:
			default:
				return new FindAstra_Provider_Local();
		}
	}

	/**
	 * Every provider known to the build, regardless of license. The admin
	 * UI uses this to render the tier picker — premium engines are still
	 * rendered to free-tier buyers, with an upsell overlay. To know whether
	 * a given provider is *usable*, call `is_unlocked()`.
	 *
	 * @return FindAstra_Provider_Base[]
	 */
	public static function all(): array {
		$providers = array( new FindAstra_Provider_Local() );
		if ( class_exists( 'FindAstra_Provider_OpenAI' ) ) {
			$providers[] = new FindAstra_Provider_OpenAI();
		}
		if ( class_exists( 'FindAstra_Provider_HuggingFace' ) ) {
			$providers[] = new FindAstra_Provider_HuggingFace();
		}
		if ( FindAstra_Provider_Mock::is_enabled() ) {
			$providers[] = new FindAstra_Provider_Mock();
		}
		return $providers;
	}

	/**
	 * Is the named provider unlocked for the current buyer? Used by the
	 * admin tier picker and by REST permission callbacks. Free engines
	 * return true unconditionally; paid engines defer to FindAstra_License.
	 */
	public static function is_unlocked( string $key ): bool {
		// Literal keys: the premium provider classes are absent from the free
		// build, so their KEY constants are unavailable here (see make()).
		switch ( $key ) {
			case 'openai':
				return FindAstra_License::can( 'engine.openai' );
			case 'huggingface':
				return FindAstra_License::can( 'engine.huggingface' );
			default:
				return true;
		}
	}
}
