<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Sabriel_AI_Provider_Claude extends Sabriel_AI_Provider {

	const DEFAULT_MODEL = 'claude-haiku-4-5-20251001';

	public static function modello() {
		return self::modello_sicuro( Sabriel_Base::get( 'ai_model_claude', '' ), self::DEFAULT_MODEL );
	}

	public function generate( $system_text, $contents, $generation_config ) {

		$sab_chiave = self::chiave_o_errore( 'sabriel_claude_api_key', 'Claude' );
		if ( isset( $sab_chiave['errore'] ) ) {
			return $sab_chiave['errore'];
		}
		$apikey = $sab_chiave['chiave'];

		$sab_turni = [];
		foreach ( ( is_array( $contents ) ? $contents : [] ) as $turno ) {
			if ( ! is_array( $turno ) ) {
				continue;
			}
			$sab_contenuto = self::togli_blocchi_vuoti( self::converti_parti( $turno['parts'] ?? [] ) );

			if ( empty( $sab_contenuto ) ) {
				continue;
			}
			$sab_turni[] = [
				'role'    => ( 'model' === ( $turno['role'] ?? '' ) ) ? 'assistant' : 'user',
				'content' => $sab_contenuto,
			];
		}

		while ( ! empty( $sab_turni ) && 'assistant' === $sab_turni[0]['role'] ) {
			array_shift( $sab_turni );
		}

		$messages = [];
		foreach ( $sab_turni as $t ) {
			$ultimo = count( $messages ) - 1;
			if ( $ultimo >= 0 && $messages[ $ultimo ]['role'] === $t['role'] ) {
				$messages[ $ultimo ]['content'] = array_merge( $messages[ $ultimo ]['content'], $t['content'] );
				continue;
			}
			$messages[] = $t;
		}

		if ( empty( $messages ) ) {
			return [
				'ok'          => false,
				'error'       => __( 'No customer message to send to the AI engine.', 'sabriel-ai' ),
				'http_status' => 400,
			];
		}

		$payload = [
			'model'       => self::modello(),
			'system'      => $system_text,
			'messages'    => $messages,
			'temperature' => $generation_config['temperature'] ?? 0.72,
			'max_tokens'  => $generation_config['maxOutputTokens'] ?? 700,
		];

		$res = wp_remote_post( 'https://api.anthropic.com/v1/messages', [
			'headers'   => [
				'Content-Type'      => 'application/json',
				'x-api-key'         => $apikey,
				'anthropic-version' => '2023-06-01',
			],
			'body'      => wp_json_encode( $payload ),
			'timeout'   => 22,
			'sslverify' => true,
		] );

		if ( is_wp_error( $res ) ) {
			return [ 'ok' => false, 'error' => $res->get_error_message(), 'http_status' => 502 ];
		}

		$code = wp_remote_retrieve_response_code( $res );
		$data = json_decode( wp_remote_retrieve_body( $res ), true );

		if ( 429 === $code || 529 === $code ) {
			return [ 'ok' => false, 'ai_overload' => true, 'error' => __( 'The AI service is very busy right now.', 'sabriel-ai' ), 'http_status' => 429 ];
		}
		if ( $code < 200 || $code >= 300 ) {
			$msg = self::errore_leggibile( 'Claude (Anthropic)', $code, $data, self::modello() );
			return [ 'ok' => false, 'error' => $msg, 'http_status' => $code ];
		}

		$testo = '';
		/* ⚠ `is_array()` e non solo `?? []`: il ripiego copre il campo ASSENTE, non il
		   campo di TIPO SBAGLIATO. Se `content` arriva come testo o numero — un proxy
		   dell'hosting che risponde 200 con un JSON suo, o un cambio di forma della
		   risposta — il ciclo solleva un avviso PHP. Sui server con la stampa degli
		   errori accesa quell'avviso finisce DENTRO la risposta JSON della chat e il
		   widget non riesce piu' a leggerla: il visitatore vede la chat rotta.
		   Gemini e OpenAI questo controllo ce l'hanno gia': qui mancava. */
		$sab_blocchi = ( isset( $data['content'] ) && is_array( $data['content'] ) ) ? $data['content'] : [];
		foreach ( $sab_blocchi as $blocco ) {
			if ( 'text' === ( $blocco['type'] ?? '' ) && isset( $blocco['text'] ) && is_scalar( $blocco['text'] ) ) {
				$testo .= (string) $blocco['text'];
			}
		}
		return [ 'ok' => true, 'data' => [ 'candidates' => [ [ 'content' => [ 'parts' => [ [ 'text' => $testo ] ] ] ] ] ], 'http_status' => $code ];
	}

	private static function converti_parti( $parti ) {
		$out = [];
		foreach ( ( is_array( $parti ) ? $parti : [] ) as $p ) {
			if ( isset( $p['text'] ) ) {
				$out[] = [ 'type' => 'text', 'text' => $p['text'] ];
			} elseif ( isset( $p['inlineData']['mimeType'], $p['inlineData']['data'] ) ) {
				$mime = $p['inlineData']['mimeType'];
				if ( 0 === strpos( $mime, 'image/' ) ) {
					$out[] = [ 'type' => 'image', 'source' => [ 'type' => 'base64', 'media_type' => $mime, 'data' => $p['inlineData']['data'] ] ];
				} elseif ( 'application/pdf' === $mime ) {
					$out[] = [ 'type' => 'document', 'source' => [ 'type' => 'base64', 'media_type' => $mime, 'data' => $p['inlineData']['data'] ] ];
				} else {
					$out[] = [ 'type' => 'text', 'text' => __( '[The customer attached a file that this AI engine cannot read directly: kindly ask them to describe its contents]', 'sabriel-ai' ) ];
				}
			} elseif ( isset( $p['inlineData'] ) ) {
				$out[] = [ 'type' => 'text', 'text' => __( '[The customer attached a file that this AI engine cannot read directly: kindly ask them to describe its contents]', 'sabriel-ai' ) ];
			}
		}

		return $out;
	}
}
