<?php
/**
 * AI backend resolver.
 *
 * @package ThemeIsle\GutenbergBlocks\Server
 */

namespace ThemeIsle\GutenbergBlocks\Server;

/**
 * Class AI_Backend_Resolver
 */
class AI_Backend_Resolver {

	/**
	 * Cached backend registry for the current request.
	 *
	 * @var array<string, AI_Backend>|null
	 */
	private static $backends_cache = null;

	/**
	 * Resolve the effective backend instance.
	 *
	 * @return AI_Backend
	 */
	public static function resolve() {
		$backends = self::get_backends();
		$backend  = self::resolve_backend_id( $backends );

		if ( isset( $backends[ $backend ] ) ) {
			return $backends[ $backend ];
		}

		if ( isset( $backends[ AI_Client_Adaptor::BACKEND_OTTER_OPENAI ] ) ) {
			return $backends[ AI_Client_Adaptor::BACKEND_OTTER_OPENAI ];
		}

		if ( isset( $backends[ AI_Client_Adaptor::BACKEND_WP ] ) ) {
			return $backends[ AI_Client_Adaptor::BACKEND_WP ];
		}

		return reset( $backends );
	}

	/**
	 * Resolve the effective backend ID.
	 *
	 * Resolution is automatic: the WP AI Client when it is usable, otherwise the
	 * legacy Otter OpenAI key path.
	 *
	 * @param array<string, AI_Backend>|null $backends Optional backend registry.
	 * @return string
	 */
	public static function resolve_backend_id( $backends = null ) {
		$backends = null === $backends ? self::get_backends() : $backends;
		$resolved = self::is_backend_available( $backends, AI_Client_Adaptor::BACKEND_WP ) ? AI_Client_Adaptor::BACKEND_WP : AI_Client_Adaptor::BACKEND_OTTER_OPENAI;

		/**
		 * Filters the effective AI backend used by Otter AI features.
		 *
		 * @param string $resolved The effective backend: 'wp' or 'legacy' (the Otter OpenAI value).
		 */
		return (string) apply_filters( 'otter_ai_backend', $resolved );
	}

	/**
	 * Build the backend registry.
	 *
	 * @return array<string, AI_Backend>
	 */
	public static function get_backends() {
		if ( null !== self::$backends_cache ) {
			return self::$backends_cache;
		}

		$backends = array(
			AI_Client_Adaptor::BACKEND_WP           => new WP_AI_Client_Backend(),
			AI_Client_Adaptor::BACKEND_OTTER_OPENAI => new Otter_OpenAI_Backend(),
		);

		/**
		 * Filters the available Otter AI backend strategies.
		 *
		 * @param array<string, AI_Backend> $backends The backend registry.
		 */
		$filtered = apply_filters( 'otter_ai_backends', $backends );

		if ( ! is_array( $filtered ) ) {
			self::$backends_cache = $backends;
			return self::$backends_cache;
		}

		$valid_backends = array();
		foreach ( $filtered as $id => $backend ) {
			if ( $backend instanceof AI_Backend ) {
				$valid_backends[ (string) $id ] = $backend;
			}
		}

		self::$backends_cache = ! empty( $valid_backends ) ? $valid_backends : $backends;

		return self::$backends_cache;
	}

	/**
	 * Reset the request-level backend registry cache.
	 *
	 * @return void
	 */
	public static function reset_cache() {
		self::$backends_cache = null;
	}

	/**
	 * Check if a backend exists and is available.
	 *
	 * @param array<string, AI_Backend> $backends The backend registry.
	 * @param string                    $backend  The backend ID.
	 * @return bool
	 */
	private static function is_backend_available( $backends, $backend ) {
		return isset( $backends[ $backend ] )
			&& $backends[ $backend ]->is_available();
	}
}
