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

namespace Hafenstudios\Core\Ai;

defined( 'ABSPATH' ) || exit;

/**
 * BYO-Treiber fuer die Anthropic Messages-API (HANS-KI-KONZEPT Abschnitt 3).
 *
 * POST auf den konfigurierbaren Endpunkt (Default {@see DEFAULT_ENDPOINT}),
 * Authentifizierung ueber den Header x-api-key und die API-Versionskennung
 * anthropic-version. Der Body traegt model, max_tokens, optional system und die
 * messages-Liste; die Antwort liefert den Text unter content[0].text.
 *
 * WICHTIG: Die Modell-ID ist IMMER ein Setting ({@see DEFAULT_MODEL} ist
 * absichtlich leer und ein Pflichtfeld in der UI). Es werden hier KEINE
 * Produktions-Modellnamen fest verdrahtet; der Betreiber traegt das aktuelle
 * Modell in den Einstellungen ein.
 */
final class AnthropicDriver extends AbstractHttpAiDriver {

	/**
	 * Default-Endpunkt der Messages-API (ueberschreibbar per Setting).
	 */
	public const DEFAULT_ENDPOINT = 'https://api.anthropic.com/v1/messages';

	/**
	 * Absichtlich leerer Modell-Platzhalter: das Modell ist ein Pflicht-Setting,
	 * es gibt keinen hartkodierten Produktions-Default.
	 */
	public const DEFAULT_MODEL = '';

	/**
	 * Versionskennung des Messages-API-Vertrags (Header anthropic-version).
	 * Dies ist eine API-Version, KEIN Modellname.
	 */
	public const API_VERSION = '2023-06-01';

	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 (leer = DEFAULT_ENDPOINT).
	 */
	public function __construct( string $api_key, string $model, string $endpoint = '' ) {
		$this->api_key  = $api_key;
		$this->model    = $model;
		$this->endpoint = '' !== $endpoint ? $endpoint : self::DEFAULT_ENDPOINT;
	}

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

	/**
	 * @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->model ) {
			return 'Kein Modell hinterlegt.';
		}
		return 'Kein Anthropic-API-Schluessel hinterlegt.';
	}

	/**
	 * @return array<string, string>
	 */
	protected function headers(): array {
		return array(
			'x-api-key'         => $this->api_key,
			'anthropic-version' => self::API_VERSION,
			'content-type'      => 'application/json',
		);
	}

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

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

	/**
	 * usage.input_tokens / usage.output_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['input_tokens'] ) ? (int) $usage['input_tokens'] : -1,
			'output' => isset( $usage['output_tokens'] ) ? (int) $usage['output_tokens'] : -1,
		);
	}
}
