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

namespace Hafenstudios\Core\Ai;

defined( 'ABSPATH' ) || exit;

/**
 * BYO-Treiber fuer OpenAI-kompatible Anbieter (HANS-KI-KONZEPT Abschnitt 3).
 *
 * Nutzt das verbreitete chat/completions-Format: POST auf den konfigurierbaren
 * Endpunkt (kompatible Anbieter unterscheiden sich in der Basis-URL, daher gibt
 * es hier bewusst KEINEN Default-Endpunkt und der Endpunkt ist Pflicht),
 * Authentifizierung ueber den Header Authorization: Bearer. Der Body traegt
 * model, max_tokens und die messages-Liste (system + user); die Antwort liefert
 * den Text unter choices[0].message.content.
 *
 * WICHTIG: Die Modell-ID ist IMMER ein Setting ({@see DEFAULT_MODEL} ist
 * absichtlich leer und ein Pflichtfeld in der UI). Keine hartkodierten
 * Produktions-Modellnamen.
 */
final class OpenAiCompatDriver extends AbstractHttpAiDriver {

	/**
	 * Kein Default-Endpunkt: kompatible Anbieter haben je eigene Basis-URLs,
	 * der Endpunkt ist ein Pflicht-Setting.
	 */
	public const DEFAULT_ENDPOINT = '';

	/**
	 * Absichtlich leerer Modell-Platzhalter (Pflicht-Setting, kein Default).
	 */
	public const DEFAULT_MODEL = '';

	private string $api_key;

	private string $model;

	private string $endpoint;

	/**
	 * @param string $api_key  API-Schluessel (Klartext).
	 * @param string $model    Modell-ID (Pflicht-Setting).
	 * @param string $endpoint Endpunkt (Pflicht, z.B. .../v1/chat/completions).
	 */
	public function __construct( string $api_key, string $model, string $endpoint ) {
		$this->api_key  = $api_key;
		$this->model    = $model;
		$this->endpoint = $endpoint;
	}

	/**
	 * @return string
	 */
	public function key(): string {
		return 'openai_compat';
	}

	/**
	 * @return string
	 */
	protected function endpoint(): string {
		return $this->endpoint;
	}

	/**
	 * @return bool
	 */
	protected function is_configured(): bool {
		return '' !== $this->api_key && '' !== $this->model && '' !== $this->endpoint;
	}

	/**
	 * @return string
	 */
	protected function config_error(): string {
		if ( '' === $this->endpoint ) {
			return 'Kein API-Endpunkt hinterlegt.';
		}
		if ( '' === $this->model ) {
			return 'Kein Modell hinterlegt.';
		}
		return 'Kein API-Schluessel hinterlegt.';
	}

	/**
	 * @return array<string, string>
	 */
	protected function headers(): array {
		return array(
			'Authorization' => 'Bearer ' . $this->api_key,
			'Content-Type'  => 'application/json',
		);
	}

	/**
	 * @param AiRequest $request Der Aufruf.
	 * @return array<string, mixed>
	 */
	protected function build_body( AiRequest $request ): array {
		$messages = array();
		if ( '' !== $request->system ) {
			$messages[] = array(
				'role'    => 'system',
				'content' => $request->system,
			);
		}
		$messages[] = array(
			'role'    => 'user',
			'content' => $request->prompt,
		);

		return array(
			'model'      => $this->model,
			'max_tokens' => $request->max_tokens,
			'messages'   => $messages,
		);
	}

	/**
	 * Antwort-Text: choices[0].message.content.
	 *
	 * @param array<string, mixed> $json Dekodierte Antwort.
	 * @return string
	 */
	protected function parse_text( array $json ): string {
		$choices = $json['choices'] ?? null;
		if ( ! is_array( $choices ) || ! isset( $choices[0] ) || ! is_array( $choices[0] ) ) {
			return '';
		}
		$message = $choices[0]['message'] ?? null;
		if ( is_array( $message ) && isset( $message['content'] ) ) {
			return (string) $message['content'];
		}
		return '';
	}

	/**
	 * usage.prompt_tokens / usage.completion_tokens.
	 *
	 * @param array<string, mixed> $json Dekodierte Antwort.
	 * @return array{input:int,output:int}
	 */
	protected function parse_usage( array $json ): array {
		$usage = is_array( $json['usage'] ?? null ) ? $json['usage'] : array();
		return array(
			'input'  => isset( $usage['prompt_tokens'] ) ? (int) $usage['prompt_tokens'] : -1,
			'output' => isset( $usage['completion_tokens'] ) ? (int) $usage['completion_tokens'] : -1,
		);
	}
}
