<?php

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

class Sabriel_AI_Provider_OpenAI extends Sabriel_AI_Provider {

	const DEFAULT_MODEL = 'gpt-5.6-luna';

	const RISERVA_RAGIONAMENTO = 8000;

	public static function legge_pdf() {
		return false;
	}

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

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

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

		$messages = [ [ 'role' => 'system', 'content' => $system_text ] ];
		foreach ( ( is_array( $contents ) ? $contents : [] ) as $turno ) {
			if ( ! is_array( $turno ) ) {
				continue;
			}
			$sab_contenuto = self::converti_parti( $turno['parts'] ?? [] );
			if ( is_array( $sab_contenuto ) ) {
				$sab_contenuto = self::togli_blocchi_vuoti( $sab_contenuto );
			}

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

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

		$code = 0;
		$data = null;

		$sab_scadenza = time() + 45;

			for ( $tentativo = 1; $tentativo <= 4; $tentativo++ ) {
			$res = wp_remote_post( 'https://api.openai.com/v1/chat/completions', [
				'headers'   => [ 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $apikey ],
				'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 ( 4 === $tentativo ) {
				break;
			}

			if ( 400 === $code ) {
				$corretto = self::correggi_parametro_rifiutato( $payload, $data );
				if ( null === $corretto ) {
					break;
				}
				$payload = $corretto;
				continue;
			}

			if ( $code >= 200 && $code < 300 && self::risposta_svuotata_dal_ragionamento( $data ) ) {
				$corretto = self::lascia_spazio_al_ragionamento( $payload );
				if ( null === $corretto ) {
					break;
				}
				$payload = $corretto;
				continue;
			}

			break;
		}

		if ( 429 === $code || 503 === $code ) {

			/*
			 * OpenAI risponde 429 sia quando e' davvero sovraccarico sia quando
			 * il credito e' finito. Il secondo caso non passa aspettando: va detto
			 * al cliente, altrimenti legge "molto richiesto" per sempre.
			 */
			$sab_tipo = '';
			foreach ( [ 'code', 'type' ] as $sab_campo ) {
				if ( isset( $data['error'][ $sab_campo ] ) && is_scalar( $data['error'][ $sab_campo ] ) ) {
					$sab_tipo .= ' ' . strtolower( (string) $data['error'][ $sab_campo ] );
				}
			}
			if ( false !== strpos( $sab_tipo, 'insufficient_quota' ) || false !== strpos( $sab_tipo, 'billing' ) ) {
				return [
					'ok'          => false,
					'error'       => __( 'The OpenAI account has run out of credit. Top up the balance or add a payment method on platform.openai.com, then try the key again.', 'sabriel-ai' ),
					'http_status' => 402,
				];
			}
			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( 'OpenAI (ChatGPT)', $code, $data, self::modello() );
			return [ 'ok' => false, 'error' => $msg, 'http_status' => $code ];
		}

		$testo = $data['choices'][0]['message']['content'] ?? '';
		return [ 'ok' => true, 'data' => [ 'candidates' => [ [ 'content' => [ 'parts' => [ [ 'text' => $testo ] ] ] ] ] ], 'http_status' => $code ];
	}

	private static function chiave_profilo() {
		return 'sabriel_ai_oai_par_' . md5( self::modello() );
	}

	private static function applica_profilo( $payload ) {
		$profilo = get_transient( self::chiave_profilo() );
		if ( ! is_array( $profilo ) ) {
			return $payload;
		}
		if ( ! empty( $profilo['max_completion_tokens'] ) && isset( $payload['max_tokens'] ) ) {
			$payload['max_completion_tokens'] = $payload['max_tokens'];
			unset( $payload['max_tokens'] );
		}
		if ( ! empty( $profilo['senza_temperature'] ) ) {
			unset( $payload['temperature'] );
		}
		if ( ! empty( $profilo['riserva_ragionamento'] ) ) {
			$chiave = isset( $payload['max_completion_tokens'] ) ? 'max_completion_tokens' : 'max_tokens';
			if ( (int) ( $payload[ $chiave ] ?? 0 ) <= self::RISERVA_RAGIONAMENTO ) {
				$payload[ $chiave ] = (int) ( $payload[ $chiave ] ?? 0 ) + self::RISERVA_RAGIONAMENTO;
			}
		}
		return $payload;
	}

	private static function ricorda_profilo( $voce ) {
		$profilo = get_transient( self::chiave_profilo() );
		if ( ! is_array( $profilo ) ) {
			$profilo = [];
		}
		$profilo[ $voce ] = true;
		set_transient( self::chiave_profilo(), $profilo, WEEK_IN_SECONDS );
	}

	private static function correggi_parametro_rifiutato( $payload, $data ) {
		$param  = is_array( $data ) ? ( $data['error']['param'] ?? '' ) : '';
		$codice = is_array( $data ) ? ( $data['error']['code'] ?? '' ) : '';

		if ( ! in_array( $codice, [ 'unsupported_parameter', 'unsupported_value' ], true ) ) {
			return null;
		}

		if ( 'max_tokens' === $param && isset( $payload['max_tokens'] ) ) {
			$payload['max_completion_tokens'] = $payload['max_tokens'];
			unset( $payload['max_tokens'] );
			self::ricorda_profilo( 'max_completion_tokens' );
			return $payload;
		}

		if ( 'temperature' === $param && isset( $payload['temperature'] ) ) {
			unset( $payload['temperature'] );
			self::ricorda_profilo( 'senza_temperature' );
			return $payload;
		}

		return null;
	}

	private static function risposta_svuotata_dal_ragionamento( $data ) {
		if ( ! is_array( $data ) ) {
			return false;
		}
		$scelta = $data['choices'][0] ?? [];
		if ( ! is_array( $scelta ) || 'length' !== ( $scelta['finish_reason'] ?? '' ) ) {
			return false;
		}
		$testo = $scelta['message']['content'] ?? '';
		return '' === trim( is_scalar( $testo ) ? (string) $testo : '' );
	}

	private static function lascia_spazio_al_ragionamento( $payload ) {
		$chiave  = isset( $payload['max_completion_tokens'] ) ? 'max_completion_tokens' : 'max_tokens';
		$attuale = (int) ( $payload[ $chiave ] ?? 0 );
		if ( $attuale > self::RISERVA_RAGIONAMENTO ) {
			return null;
		}
		$payload[ $chiave ] = $attuale + self::RISERVA_RAGIONAMENTO;
		self::ricorda_profilo( 'riserva_ragionamento' );
		return $payload;
	}

	private static function converti_parti( $parti ) {
		if ( ! is_array( $parti ) ) {
			return '';
		}
		if ( 1 === count( $parti ) && isset( $parti[0]['text'] ) && is_scalar( $parti[0]['text'] ) && ! isset( $parti[0]['inlineData'] ) ) {
			return (string) $parti[0]['text'];
		}
		$out = [];
		foreach ( $parti as $p ) {
			if ( isset( $p['text'] ) ) {
				$out[] = [ 'type' => 'text', 'text' => $p['text'] ];
			} elseif ( isset( $p['inlineData']['mimeType'], $p['inlineData']['data'] ) && 0 === strpos( $p['inlineData']['mimeType'], 'image/' ) ) {
				$out[] = [ 'type' => 'image_url', 'image_url' => [ 'url' => 'data:' . $p['inlineData']['mimeType'] . ';base64,' . $p['inlineData']['data'] ] ];
			} 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;
	}
}
