<?php
/**
 * @package Hafenstudios\Core
 */

namespace Hafenstudios\Core\Ai;

use Hafenstudios\Core\Events\EventBus;
use Hafenstudios\Core\Support\Secrets;

defined( 'ABSPATH' ) || exit;

/**
 * Zentrale KI-Fassade der Flotte (HANS-KI-KONZEPT Abschnitt 3, Muster Mailer).
 *
 * Der AiClient waehlt anhand der Core-Option `hs_core_ai` den passenden Treiber
 * und fuehrt einen Aufruf aus. Aufbau der Option:
 *
 *   array(
 *     'enabled' => bool,        // globaler Hauptschalter, Default false
 *     'driver'  => string,      // 'anthropic' | 'openai_compat' | 'proxy'
 *     'byo'     => array(
 *       'provider'      => string, // gespiegelte Treiberwahl (Informationszweck)
 *       'key_encrypted' => string, // via Core\Support\Secrets verschluesselt
 *       'model'         => string, // Pflicht, kein Default
 *       'endpoint'      => string, // optional (BYO Anthropic) / Pflicht (OpenAI-kompat)
 *     ),
 *     'proxy'   => array(
 *       'license_key_encrypted' => string, // verschluesselt
 *       'endpoint'              => string, // leer = Proxy noch nicht live
 *     ),
 *   )
 *
 * Leitplanken: (1) Hauptschalter aus -> AiResult::disabled() ohne HTTP.
 * (2) Jeder Fehler ist ein AiResult mit ok=false, NIE eine Ausnahme nach aussen
 * (stiller Rueckfall auf Nicht-KI-Verhalten beim Aufrufer).
 *
 * Nicht final, damit Tests bei Bedarf ableiten koennen.
 */
class AiClient {

	/**
	 * Name der Core-Option.
	 */
	public const OPTION = 'hs_core_ai';

	/**
	 * Ist die KI global eingeschaltet?
	 *
	 * @return bool
	 */
	public function is_enabled(): bool {
		return (bool) ( $this->config()['enabled'] ?? false );
	}

	/**
	 * Fuehrt einen LLM-Aufruf aus. Liefert immer ein AiResult.
	 *
	 * @param AiRequest $request Der Aufruf.
	 * @return AiResult
	 */
	public function complete( AiRequest $request ): AiResult {
		$config = $this->config();

		if ( empty( $config['enabled'] ) ) {
			return AiResult::disabled();
		}

		try {
			$driver = $this->driver( $config );
			if ( ! $driver instanceof AiDriver ) {
				return AiResult::permanent( 'Kein KI-Treiber eingerichtet.' );
			}
			return $driver->complete( $request );
		} catch ( \Throwable $e ) {
			// Stiller Rueckfall: interne Fehler nie nach aussen werfen.
			return AiResult::permanent( 'Interner Fehler beim KI-Aufruf.' );
		}
	}

	/**
	 * Baut den konfigurierten Treiber. Ueber den Filter `hafenstudios/ai_driver`
	 * ersetzbar (Muster mail_driver; z.B. fuer Tests oder kuenftige Anbieter).
	 *
	 * @param array<string, mixed> $config Konfiguration.
	 * @return AiDriver|null
	 */
	protected function driver( array $config ): ?AiDriver {
		$type = (string) ( $config['driver'] ?? '' );

		$driver = null;
		switch ( $type ) {
			case 'anthropic':
				$byo    = is_array( $config['byo'] ?? null ) ? $config['byo'] : array();
				$driver = new AnthropicDriver(
					Secrets::decrypt( (string) ( $byo['key_encrypted'] ?? '' ) ),
					(string) ( $byo['model'] ?? '' ),
					(string) ( $byo['endpoint'] ?? '' )
				);
				break;
			case 'openai_compat':
				$byo    = is_array( $config['byo'] ?? null ) ? $config['byo'] : array();
				$driver = new OpenAiCompatDriver(
					Secrets::decrypt( (string) ( $byo['key_encrypted'] ?? '' ) ),
					(string) ( $byo['model'] ?? '' ),
					(string) ( $byo['endpoint'] ?? '' )
				);
				break;
			case 'proxy':
				$proxy  = is_array( $config['proxy'] ?? null ) ? $config['proxy'] : array();
				$driver = new ProxyDriver(
					(string) ( $proxy['endpoint'] ?? '' ),
					Secrets::decrypt( (string) ( $proxy['license_key_encrypted'] ?? '' ) )
				);
				break;
		}

		/**
		 * Erlaubt das Ersetzen des KI-Treibers (Muster mail_driver).
		 *
		 * @param AiDriver|null        $driver Aktueller Treiber (null = unbekannter Typ).
		 * @param array<string, mixed> $config KI-Konfiguration.
		 */
		return EventBus::filter( 'ai_driver', $driver, $config );
	}

	/**
	 * Liest die Konfiguration aus der Option (immer ein Array).
	 *
	 * @return array<string, mixed>
	 */
	protected function config(): array {
		$config = get_option( self::OPTION, array() );
		return is_array( $config ) ? $config : array();
	}
}
