<?php

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

class Sabriel_Module_AI extends Sabriel_Module {

	const PROVIDERS = [
		'gemini' => [ 'Google Gemini', 'sabriel_gemini_api_key', 'https://aistudio.google.com/apikey' ],
		'openai' => [ 'OpenAI (ChatGPT)', 'sabriel_openai_api_key', 'https://platform.openai.com/api-keys' ],
		'claude' => [ 'Claude (Anthropic)', 'sabriel_claude_api_key', 'https://console.anthropic.com/settings/keys' ],
	];

	const MODELLI = [
		'gemini' => [
			[ 'gemini-3.1-pro-preview', 'Gemini 3.1 Pro', '$2 / $12', false ],

			[ 'gemini-3.6-flash', 'Gemini 3.6 Flash', '$1.50 / $7.50', false ],
			[ 'gemini-3.5-flash', 'Gemini 3.5 Flash', '$1.50 / $9', false ],
			[ 'gemini-3-flash-preview', 'Gemini 3 Flash', '$0.50 / $3', false ],
			[ 'gemini-3.5-flash-lite', 'Gemini 3.5 Flash-Lite', '$0.30 / $2.50', false ],
			[ 'gemini-3.1-flash-lite', 'Gemini 3.1 Flash-Lite', '$0.25 / $1.50', true ],
		],
		'openai' => [

			[ 'gpt-5.6-sol', 'GPT-5.6 Sol', '$5 / $30', false ],
			[ 'gpt-5.5', 'GPT-5.5', '$5 / $30', false ],
			[ 'gpt-5.4', 'GPT-5.4', '$2.50 / $15', false ],
			[ 'gpt-5.6-terra', 'GPT-5.6 Terra', '$2 / $12', false ],
			[ 'gpt-5.4-mini', 'GPT-5.4 mini', '$0.75 / $4.50', false ],
			[ 'gpt-5.6-luna', 'GPT-5.6 Luna', '$0.20 / $1.20', true ],
		],
		'claude' => [
			[ 'claude-fable-5', 'Fable 5', '$10 / $50', false ],

			[ 'claude-opus-5', 'Opus 5', '$5 / $25', false ],
			[ 'claude-opus-4-8', 'Opus 4.8', '$5 / $25', false ],
			[ 'claude-sonnet-5', 'Sonnet 5', '$3 / $15', false ],
			[ 'claude-haiku-4-5-20251001', 'Haiku 4.5', '$1 / $5', true ],
		],
	];

	const LISTINI = [
		'gemini' => 'https://ai.google.dev/gemini-api/docs/pricing',
		'openai' => 'https://openai.com/api/pricing/',
		'claude' => 'https://www.anthropic.com/pricing',
	];

	const MODELLI_VERIFICATI_IL = '2026-08-09';

	public static function icona_provider( $slug ) {
		$loghi = [
			'gemini' => '<svg width="30" height="30" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect x="7" y="7" width="18" height="18" rx="4" stroke="#1A73E8" stroke-width="2"/><rect x="12.5" y="12.5" width="7" height="7" rx="1.6" fill="#1A73E8"/><path d="M12 3v4M16 3v4M20 3v4M12 25v4M16 25v4M20 25v4M3 12h4M3 16h4M3 20h4M25 12h4M25 16h4M25 20h4" stroke="#1A73E8" stroke-width="2" stroke-linecap="round"/></svg>',
			'openai' => '<svg width="30" height="30" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect x="7" y="7" width="18" height="18" rx="4" stroke="#0F9D77" stroke-width="2"/><rect x="12.5" y="12.5" width="7" height="7" rx="1.6" fill="#0F9D77"/><path d="M12 3v4M16 3v4M20 3v4M12 25v4M16 25v4M20 25v4M3 12h4M3 16h4M3 20h4M25 12h4M25 16h4M25 20h4" stroke="#0F9D77" stroke-width="2" stroke-linecap="round"/></svg>',
			'claude' => '<svg width="30" height="30" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><rect x="7" y="7" width="18" height="18" rx="4" stroke="#D97757" stroke-width="2"/><rect x="12.5" y="12.5" width="7" height="7" rx="1.6" fill="#D97757"/><path d="M12 3v4M16 3v4M20 3v4M12 25v4M16 25v4M20 25v4M3 12h4M3 16h4M3 20h4M25 12h4M25 16h4M25 20h4" stroke="#D97757" stroke-width="2" stroke-linecap="round"/></svg>',
		];
		return $loghi[ $slug ] ?? '';
	}

	public static function modello_provider( $chiave ) {
		$map = [ 'gemini' => 'Sabriel_AI_Provider_Gemini', 'openai' => 'Sabriel_AI_Provider_OpenAI', 'claude' => 'Sabriel_AI_Provider_Claude' ];
		$cls = $map[ $chiave ] ?? '';
		return ( '' !== $cls && class_exists( $cls ) ) ? $cls::modello() : '';
	}

	public function get_id() {
		return 'ai';
	}

	public function register_hooks() {

		add_action( 'admin_menu', [ $this, 'add_submenu' ], 15 );
		add_action( 'rest_api_init', [ $this, 'register_routes' ] );
	}

	public function add_submenu() {
		add_submenu_page(
			'sabriel-ai',
			__( 'AI Engine', 'sabriel-ai' ),
			__( 'AI Engine', 'sabriel-ai' ),
			'manage_options',
			'sabriel-ai-motore',
			[ $this, 'render_page' ]
		);
	}

	/**
	 * Prefixes each service has used for its keys. Only a hint, never a rule:
	 * providers rebrand their key format whenever they like. Google moved from
	 * 'AIza' (standard keys) to 'AQ.' (auth keys) during 2026, and standard keys
	 * stop being accepted in September 2026. Anything not listed here is treated
	 * as valid, so a new format can never lock anyone out.
	 */
	const FIRME_CHIAVI = [
		'gemini' => [ 'AIza', 'AQ.', 'IQ.' ],
		'claude' => [ 'sk-ant-' ],
		'openai' => [ 'sk-' ],
	];

	/**
	 * Recognises which service a key belongs to from its prefix.
	 * Returns '' when the shape is unknown: an unrecognised key is
	 * accepted rather than blocked.
	 */
	public static function provider_dalla_chiave( $chiave ) {
		$chiave = trim( (string) $chiave );
		if ( '' === $chiave ) {
			return '';
		}

		$sab_trovato = '';
		$sab_lunghezza = 0;
		foreach ( self::FIRME_CHIAVI as $sab_prov => $sab_prefissi ) {
			foreach ( $sab_prefissi as $sab_pre ) {
				// Il prefisso piu' lungo vince: 'sk-ant-' batte 'sk-'.
				if ( 0 === strpos( $chiave, $sab_pre ) && strlen( $sab_pre ) > $sab_lunghezza ) {
					$sab_trovato   = $sab_prov;
					$sab_lunghezza = strlen( $sab_pre );
				}
			}
		}
		return $sab_trovato;
	}

	/**
	 * Says whether this key already belongs to a different engine.
	 * The comparison is on the key itself, not on its shape, so it keeps
	 * working whatever prefix a provider adopts next.
	 *
	 * @param string $chiave    the key being saved.
	 * @param string $provider  the engine whose field it arrived in.
	 * @param array  $inviate   every key submitted in this same save.
	 * @param string $scelto    the engine currently selected in the form.
	 * @return string the other engine's code, or '' when the key is fine.
	 * ⚠ Public because the setup wizard (class-module-settings.php) uses it too:
	 * it has the same three boxes in the same form, so the same problem. A
	 * second hand-written copy in there would drift from this one: do NOT
	 * duplicate it.
	 */
	public static function chiave_di_un_altro( $chiave, $provider, $inviate, $scelto ) {

		/*
		 * 1) La firma della chiave va per prima. Non cambia la decisione (la chiave
		 * viene comunque scartata da uno dei tre controlli), ma cambia il NOME che
		 * finisce nel messaggio, che e' tutto il valore dell'avviso.
		 */
		$sab_firma = self::provider_dalla_chiave( $chiave );
		if ( '' !== $sab_firma && $sab_firma !== $provider ) {
			return $sab_firma;
		}

		// 2) Identica a una chiave gia' salvata su un altro motore.
		foreach ( self::PROVIDERS as $sab_altro => $sab_info ) {
			if ( $sab_altro === $provider ) {
				continue;
			}
			$sab_salvata = (string) Sabriel_Crypto::decrypt( get_option( $sab_info[1], '' ) );
			if ( '' !== $sab_salvata && hash_equals( $sab_salvata, $chiave ) ) {
				return $sab_altro;
			}
		}

		/*
		 * 3) Identica a un'altra casella di questo stesso salvataggio: il motore
		 * SELEZIONATO ha la precedenza, e' quello su cui stava lavorando.
		 */
		if ( $provider !== $scelto && isset( $inviate[ $scelto ] ) && '' !== $inviate[ $scelto ]
			&& hash_equals( $inviate[ $scelto ], $chiave ) ) {
			return $scelto;
		}
		foreach ( self::PROVIDERS as $sab_altro => $sab_info ) {
			if ( $sab_altro === $provider ) {
				continue;
			}
			if ( isset( $inviate[ $sab_altro ] ) && '' !== $inviate[ $sab_altro ]
				&& hash_equals( $inviate[ $sab_altro ], $chiave ) && $provider !== $scelto ) {
				return $sab_altro;
			}
		}

		return '';
	}

	public static function provider_attivo() {
		$scelto = Sabriel_Base::get( 'ai_provider', 'gemini' );
		return array_key_exists( $scelto, self::PROVIDERS ) ? $scelto : 'gemini';
	}

	public static function motore_legge_pdf() {
		$classi = [
			'gemini' => 'Sabriel_AI_Provider_Gemini',
			'openai' => 'Sabriel_AI_Provider_OpenAI',
			'claude' => 'Sabriel_AI_Provider_Claude',
		];
		$classe = $classi[ self::provider_attivo() ] ?? '';

		if ( '' === $classe || ! class_exists( $classe ) ) {
			return true;
		}
		return (bool) call_user_func( [ $classe, 'legge_pdf' ] );
	}

	public function register_routes() {
		register_rest_route( 'sabriel/v1', '/ai/test-key/(?P<provider>gemini|openai|claude)', [
			'methods'             => 'POST',
			'callback'            => [ $this, 'rest_test_key' ],
			'permission_callback' => function () { return current_user_can( 'manage_options' ); },
		] );
		register_rest_route( 'sabriel/v1', '/ai/remove-key/(?P<provider>gemini|openai|claude)', [
			'methods'             => 'POST',
			'callback'            => [ $this, 'rest_remove_key' ],
			'permission_callback' => function () { return current_user_can( 'manage_options' ); },
		] );
	}

	public function rest_remove_key( WP_REST_Request $req ) {
		$provider = $req['provider'];
		delete_option( self::PROVIDERS[ $provider ][1] );
		if ( self::provider_attivo() === $provider && ! get_option( self::PROVIDERS[ $provider ][1] ) ) {

			$fallback = $provider;
			foreach ( self::PROVIDERS as $sab_codice => $sab_info ) {
				if ( $sab_codice !== $provider && get_option( $sab_info[1] ) ) {
					$fallback = $sab_codice;
					break;
				}
			}
			Sabriel_Base::update( 'ai_provider', $fallback );
		}
		return new WP_REST_Response( [ 'ok' => true ], 200 );
	}

	public function rest_test_key( WP_REST_Request $req ) {
		$provider = $req['provider'];
		$apikey   = Sabriel_Crypto::decrypt( get_option( self::PROVIDERS[ $provider ][1], '' ) );
		if ( ! $apikey ) {
			return new WP_REST_Response( [ 'ok' => false, 'error' => __( 'No key saved.', 'sabriel-ai' ) ], 200 );
		}

		if ( 'gemini' === $provider ) {

			$res = wp_remote_post( 'https://generativelanguage.googleapis.com/v1beta/models/' . rawurlencode( Sabriel_AI_Provider_Gemini::modello() ) . ':generateContent', [
				'headers' => [ 'Content-Type' => 'application/json', 'x-goog-api-key' => $apikey ],
				'body'    => wp_json_encode( [ 'contents' => [ [ 'role' => 'user', 'parts' => [ [ 'text' => 'rispondi solo con: ok' ] ] ] ], 'generationConfig' => [ 'maxOutputTokens' => 5 ] ] ),
				'timeout' => 15,
			] );
		} elseif ( 'openai' === $provider ) {

			$sab_prova = ( new Sabriel_AI_Provider_OpenAI() )->generate(
				'rispondi solo con: ok',
				[ [ 'role' => 'user', 'parts' => [ [ 'text' => 'ok' ] ] ] ],
				[ 'maxOutputTokens' => 16 ]
			);
			if ( ! empty( $sab_prova['ok'] ) ) {
				return new WP_REST_Response( [ 'ok' => true ], 200 );
			}
			return new WP_REST_Response( [
				'ok'    => false,
				'error' => ( isset( $sab_prova['error'] ) && is_scalar( $sab_prova['error'] ) )
					? (string) $sab_prova['error']
					: __( 'Doesn\'t work', 'sabriel-ai' ),
			], 200 );
		} else {
			$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( [ 'model' => Sabriel_AI_Provider_Claude::modello(), 'max_tokens' => 5, 'messages' => [ [ 'role' => 'user', 'content' => 'rispondi solo con: ok' ] ] ] ),
				'timeout' => 15,
			] );
		}

		if ( is_wp_error( $res ) ) {

			return new WP_REST_Response( [ 'ok' => false, 'error' => sprintf(
				/* translators: %s: error message returned by the service */
				__( 'Connection failed: %s', 'sabriel-ai' ),
				$res->get_error_message()
			) ], 200 );
		}
		$codice = wp_remote_retrieve_response_code( $res );
		if ( 200 === $codice ) {
			return new WP_REST_Response( [ 'ok' => true ], 200 );
		}
		$body        = json_decode( wp_remote_retrieve_body( $res ), true );
		$sab_classe  = [ 'gemini' => 'Sabriel_AI_Provider_Gemini', 'claude' => 'Sabriel_AI_Provider_Claude' ][ $provider ] ?? '';
		$sab_modello = ( '' !== $sab_classe && class_exists( $sab_classe ) ) ? (string) call_user_func( [ $sab_classe, 'modello' ] ) : '';
		$msg_errore  = Sabriel_AI_Provider::errore_leggibile( self::PROVIDERS[ $provider ][0], $codice, $body, $sab_modello );
		return new WP_REST_Response( [ 'ok' => false, 'error' => $msg_errore ], 200 );
	}

	public function render_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Access denied', 'sabriel-ai' ) );
		}
		$msg                 = '';
		$sab_chiavi_scartate = [];

		if ( Sabriel_Helpers::e_una_post() && isset( $_POST['sab_ai_nonce'] ) && check_admin_referer( 'sab_ai_action', 'sab_ai_nonce' ) ) {
			$provider = sanitize_text_field( wp_unslash( $_POST['ai_provider'] ?? 'gemini' ) );
			if ( array_key_exists( $provider, self::PROVIDERS ) ) {
				Sabriel_Base::update( 'ai_provider', $provider );
			}
			/*
			 * I tre campi chiave sono password dentro lo stesso form: il gestore
			 * password del browser puo' riempire quelli nascosti con una chiave
			 * gia' salvata, e cosi' un motore si ritrova la chiave di un altro.
			 * Raccogliamo tutto prima, poi scartiamo quello che non torna.
			 */
			$sab_inviate = [];
			foreach ( self::PROVIDERS as $sab_pk => $sab_pinfo ) {
				$sab_grezzo             = wp_unslash( $_POST[ $sab_pinfo[1] ] ?? '' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- ripulito nella riga successiva.
				$sab_inviate[ $sab_pk ] = is_scalar( $sab_grezzo ) ? trim( sanitize_text_field( (string) $sab_grezzo ) ) : '';
			}

			foreach ( self::PROVIDERS as $sab_prov_campo => $info ) {
				$valore_nuovo = $sab_inviate[ $sab_prov_campo ];
				if ( '' === $valore_nuovo ) {
					continue;
				}

				$sab_altro = self::chiave_di_un_altro( $valore_nuovo, $sab_prov_campo, $sab_inviate, $provider );
				if ( '' !== $sab_altro ) {
					$sab_chiavi_scartate[] = sprintf(
						/* translators: 1: name of the engine whose field was filled in; 2: name of the engine the key actually belongs to */
						__( 'The key in the %1$s field belongs to %2$s, so it was not saved. Each engine needs its own key: check you pasted it into the right box.', 'sabriel-ai' ),
						$info[0],
						self::PROVIDERS[ $sab_altro ][0]
					);
					continue;
				}

				update_option( $info[1], Sabriel_Crypto::encrypt( $valore_nuovo ), false );
			}

			foreach ( self::PROVIDERS as $chiave => $info_p ) {
				$scelta = sanitize_text_field( wp_unslash( $_POST[ 'ai_model_' . $chiave ] ?? '' ) );
				if ( '__custom__' === $scelta ) {
					$scelta = sanitize_text_field( wp_unslash( $_POST[ 'ai_model_' . $chiave . '_custom' ] ?? '' ) );
				}
				$scelta = trim( $scelta );
				if ( '' !== $scelta && preg_match( '/^[A-Za-z0-9._-]+$/', $scelta ) ) {
					Sabriel_Base::update( 'ai_model_' . $chiave, $scelta );
				}
			}
			$msg = __( 'AI Engine saved.', 'sabriel-ai' );
		}

		$provider_attivo = self::provider_attivo();
		?>
		<div class="wrap">
			<h1><?php esc_html_e( 'AI Engine', 'sabriel-ai' ); ?></h1>
			<p style="color:#666;max-width:640px"><?php esc_html_e( 'Choose which AI powers the bot\'s replies and enter its key. You can save several keys at once and switch engine whenever you like: the widget on your site keeps working exactly the same, whichever engine you pick.', 'sabriel-ai' ); ?></p>

			<?php if ( $msg ) : ?>
				<div style="background:#eff9f0;border:1.5px solid #86d29a;color:#1a7d3a;padding:12px 18px;border-radius:8px;margin:16px 0;max-width:640px"><?php echo esc_html( $msg ); ?></div>
			<?php endif; ?>
			<?php foreach ( $sab_chiavi_scartate as $sab_avviso ) : ?>
				<div style="background:#fef2f2;border:1.5px solid #f0a5a5;color:#b91c1c;padding:12px 18px;border-radius:8px;margin:16px 0;max-width:640px"><?php echo esc_html( $sab_avviso ); ?></div>
			<?php endforeach; ?>

			<form method="post" style="max-width:640px;background:#fff;border:1px solid #e5e5e5;border-radius:10px;padding:24px;margin-top:16px">
				<?php wp_nonce_field( 'sab_ai_action', 'sab_ai_nonce' ); ?>

				<h2 style="font-size:15px;margin:0 0 4px"><?php esc_html_e( 'Choose the engine', 'sabriel-ai' ); ?></h2>
				<p style="color:#888;font-size:12px;margin:0 0 14px"><?php esc_html_e( 'The engine that answers customers in chat. It uses YOUR API key for that service: you pay for and manage it.', 'sabriel-ai' ); ?></p>

				<?php

				$sab_stato = [];
				foreach ( self::PROVIDERS as $pk => $pinfo ) {
					$graw              = get_option( $pinfo[1], '' );
					$gdec              = class_exists( 'Sabriel_Crypto' ) ? Sabriel_Crypto::decrypt( $graw ) : $graw;
					$sab_stato[ $pk ]  = [ 'presente' => ( '' !== (string) $graw ), 'leggibile' => ( '' !== (string) $gdec ) ];
				}
				?>
				<div class="sab-ai-cards" style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:6px">
					<?php foreach ( self::PROVIDERS as $chiave => $info ) :
						$card_attiva = ( $provider_attivo === $chiave );
						$card_chiave = $sab_stato[ $chiave ]['leggibile'];
					?>
					<label class="sab-ai-card" data-card="<?php echo esc_attr( $chiave ); ?>" data-haskey="<?php echo $card_chiave ? '1' : '0'; ?>" style="position:relative;cursor:pointer;border:2px solid <?php echo $card_attiva ? '#1461CC' : '#e5e5e5'; ?>;border-radius:12px;padding:16px 10px 13px;text-align:center;background:#fff;transition:border-color .15s,box-shadow .15s">
						<input type="radio" name="ai_provider" value="<?php echo esc_attr( $chiave ); ?>" <?php checked( $card_attiva ); ?> class="sab-ai-radio" style="position:absolute;opacity:0;width:0;height:0;pointer-events:none">
						<span style="display:flex;width:38px;height:38px;margin:0 auto 9px;align-items:center;justify-content:center"><?php echo self::icona_provider( $chiave ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- SVG statico scritto nel plugin, nessun dato esterno. ?></span>
						<span style="display:block;font-size:13px;font-weight:600;color:#222;line-height:1.2"><?php echo esc_html( $info[0] ); ?></span>
						<span class="sab-ai-card-stato" data-card-stato="<?php echo esc_attr( $chiave ); ?>" style="display:block;font-size:10.5px;margin-top:5px;font-weight:600;color:<?php echo $card_attiva ? ( $card_chiave ? '#1461CC' : '#b45309' ) : ( $card_chiave ? '#1a7d3a' : '#9a9a9a' ); ?>">
							<?php
							if ( $card_attiva && $card_chiave ) {
								esc_html_e( '● active', 'sabriel-ai' );
							} elseif ( $card_attiva ) {
								esc_html_e( '● selected', 'sabriel-ai' );
							} elseif ( $card_chiave ) {
								esc_html_e( '✓ key saved', 'sabriel-ai' );
							} else {
								esc_html_e( 'tap to choose', 'sabriel-ai' );
							}
							?>
						</span>
					</label>
					<?php endforeach; ?>
				</div>
				<p style="color:#aaa;font-size:11px;margin:0 0 8px"><?php esc_html_e( 'The engine with the blue border is the active one. Tap another card to change it.', 'sabriel-ai' ); ?></p>

				<h2 style="font-size:14px;margin:22px 0 6px;border-top:1px solid #eee;padding-top:18px"><?php esc_html_e( 'Model and key', 'sabriel-ai' ); ?></h2>
				<p style="color:#888;font-size:12px;margin:0 0 14px"><?php esc_html_e( 'Settings for the engine selected above. The key is stored encrypted, never in plain text; leave the field empty to keep the one already saved.', 'sabriel-ai' ); ?></p>

				<?php foreach ( self::PROVIDERS as $chiave => $info ) :
					list( $nome, $campo, $url_chiave ) = $info;
					$presente        = $sab_stato[ $chiave ]['presente'];
					$leggibile       = $sab_stato[ $chiave ]['leggibile'];
					$pannello_attivo = ( $provider_attivo === $chiave );
				?>
				<div class="sab-ai-pannello" data-panel="<?php echo esc_attr( $chiave ); ?>" style="margin-bottom:8px;padding:16px;background:#fafafa;border-radius:10px;border:1px solid #eee;display:<?php echo $pannello_attivo ? 'block' : 'none'; ?>">
					<label style="font-weight:600;font-size:13px;display:flex;align-items:center;gap:8px;margin-bottom:8px">
						<?php echo esc_html( $nome ); ?>
						<?php

						if ( $leggibile ) {
							$sab_testo_badge = __( 'Key saved', 'sabriel-ai' );
						} elseif ( $presente ) {
							$sab_testo_badge = __( 'Key unreadable', 'sabriel-ai' );
						} else {
							$sab_testo_badge = __( 'No key', 'sabriel-ai' );
						}
						echo $this->badge( $leggibile, $sab_testo_badge ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- badge() fa esc_html() sul testo e costruisce il resto nel file stesso.
						?>
					</label>
					<?php if ( $presente && ! $leggibile ) : ?>
						<p style="color:#b45309;font-size:11.5px;margin:0 0 8px"><?php esc_html_e( 'The saved key can no longer be decrypted (usually after changing the security keys in wp-config.php or migrating the site). Re-enter it below to make it work again.', 'sabriel-ai' ); ?></p>
					<?php endif; ?>
					<?php

					$sab_classe_prov = [ 'gemini' => 'Sabriel_AI_Provider_Gemini', 'openai' => 'Sabriel_AI_Provider_OpenAI', 'claude' => 'Sabriel_AI_Provider_Claude' ][ $chiave ] ?? '';
					$sab_prov_pdf    = ( '' === $sab_classe_prov || ! class_exists( $sab_classe_prov ) ) ? true : (bool) call_user_func( [ $sab_classe_prov, 'legge_pdf' ] );
					?>
					<?php if ( ! $sab_prov_pdf ) : ?>
						<p style="background:#fffbeb;border:1px solid #f59e0b;color:#92400e;font-size:11.5px;padding:9px 12px;border-radius:6px;margin:0 0 10px;line-height:1.5">
							<strong><?php esc_html_e( 'Note:', 'sabriel-ai' ); ?></strong>
							<?php esc_html_e( 'this engine can\'t read the PDFs customers attach in chat, only images. If you choose it, the paperclip button stops offering PDFs on its own and the bot no longer promises to read them: if a customer has one, they\'re asked to paste the text instead. The other engines do read PDFs.', 'sabriel-ai' ); ?>
						</p>
					<?php endif; ?>
					<input type="password" class="sab-api-key" id="sab-key-<?php echo esc_attr( $chiave ); ?>" name="<?php echo esc_attr( $campo ); ?>" placeholder="<?php echo $presente ? esc_attr__( '•••••••••••••••••••• (leave empty to keep it unchanged)', 'sabriel-ai' ) : esc_attr__( 'Paste your API key here', 'sabriel-ai' ); ?>" style="width:100%;padding:8px 10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;font-family:monospace;font-size:12.5px" autocomplete="new-password" autocorrect="off" autocapitalize="off" spellcheck="false" data-lpignore="true" data-1p-ignore data-form-type="other">
					<div style="display:flex;align-items:center;gap:12px;margin-top:8px;flex-wrap:wrap">
						<a href="<?php echo esc_url( $url_chiave ); ?>" target="_blank" rel="noopener" style="font-size:11.5px;color:#1461CC"><?php esc_html_e( 'Where do I find the key →', 'sabriel-ai' ); ?></a>
						<?php if ( $presente ) : ?>
						<button type="button" class="button sab-test-key-btn" data-provider="<?php echo esc_attr( $chiave ); ?>" style="font-size:11.5px;padding:2px 10px;height:auto"><?php esc_html_e( 'Test this key', 'sabriel-ai' ); ?></button>
						<button type="button" class="button sab-remove-key-btn" data-provider="<?php echo esc_attr( $chiave ); ?>" style="font-size:11.5px;padding:2px 10px;height:auto;color:#b91c1c;border-color:#f0c4c4"><?php esc_html_e( 'Remove key', 'sabriel-ai' ); ?></button>
						<span class="sab-test-key-result" data-provider-result="<?php echo esc_attr( $chiave ); ?>" style="font-size:11.5px;font-weight:600"></span>
						<?php endif; ?>
					</div>
					<?php
					$modello_corr = self::modello_provider( $chiave );
					$lista_mod    = self::MODELLI[ $chiave ];
					$ids_mod      = array_column( $lista_mod, 0 );
					$is_custom    = ! in_array( $modello_corr, $ids_mod, true );
					?>
					<div style="margin-top:14px;border-top:1px dashed #e3e3e3;padding-top:12px">
						<label style="font-weight:600;font-size:12.5px;display:block;margin-bottom:6px"><?php esc_html_e( 'Model', 'sabriel-ai' ); ?></label>
						<select name="ai_model_<?php echo esc_attr( $chiave ); ?>" class="sab-model-select" data-provider="<?php echo esc_attr( $chiave ); ?>" style="width:100%;padding:8px 10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;font-size:12.5px;background:#fff">
							<?php foreach ( $lista_mod as $m ) :
								list( $mid, $mlabel, $mprice, $mreco ) = $m;
								$suffisso = $mreco ? ' · ' . __( 'recommended', 'sabriel-ai' ) : '';
							?>
							<option value="<?php echo esc_attr( $mid ); ?>" <?php selected( ! $is_custom && $modello_corr === $mid ); ?>><?php echo esc_html( $mlabel . ': ' . $mprice . ' ' . __( 'per 1M tokens', 'sabriel-ai' ) . $suffisso ); ?></option>
							<?php endforeach; ?>
							<option value="__custom__" <?php selected( $is_custom ); ?>><?php esc_html_e( 'Custom model…', 'sabriel-ai' ); ?></option>
						</select>
						<input type="text" name="ai_model_<?php echo esc_attr( $chiave ); ?>_custom" class="sab-model-custom" data-provider="<?php echo esc_attr( $chiave ); ?>" value="<?php echo $is_custom ? esc_attr( $modello_corr ) : ''; ?>" placeholder="<?php echo esc_attr( sprintf( /* translators: %s: example of a model identifier */ __( 'Exact model ID (e.g. %s)', 'sabriel-ai' ), $ids_mod[0] ) ); ?>" style="width:100%;margin-top:8px;padding:8px 10px;border:1px solid #ccc;border-radius:6px;box-sizing:border-box;font-family:monospace;font-size:12.5px;display:<?php echo $is_custom ? 'block' : 'none'; ?>" autocomplete="off">
						<p style="color:#888;font-size:11px;margin:8px 0 0;line-height:1.5">
							<?php echo esc_html( sprintf( /* translators: %s: date the prices were checked */ __( 'Prices in USD per 1M tokens (input / output), billed to your API key. Verified on %s. Some engines charge more above a certain request length (usually 200,000 tokens): the figure here is the standard rate, and with a very long prompt the bill on those models can be higher.', 'sabriel-ai' ), date_i18n( get_option( 'date_format' ), strtotime( self::MODELLI_VERIFICATI_IL ) ) ) ); ?>
							<a href="<?php echo esc_url( self::LISTINI[ $chiave ] ); ?>" target="_blank" rel="noopener" style="color:#1461CC"><?php esc_html_e( 'Official pricing', 'sabriel-ai' ); ?></a>
						</p>
					</div>
				</div>
				<?php endforeach; ?>

				<?php

			do_action( 'sabriel_ai_motore_extra' );
			?>

			<button type="submit" style="background:#1461CC;color:#fff;border:none;padding:11px 26px;border-radius:8px;font-weight:700;cursor:pointer"><?php esc_html_e( 'Save AI engine', 'sabriel-ai' ); ?></button>
			</form>
		</div>
		<script>
		(function(){
			/* Il server disegna sempre i campi chiave vuoti: se al caricamento c'e'
			   dentro qualcosa, l'ha messo il gestore password del browser, non
			   l'utente. Va tolto, altrimenti al salvataggio finisce nel provider
			   sbagliato. Chrome riempie in ritardo, quindi ripassiamo piu' volte. */
			function svuota(){
				document.querySelectorAll('.sab-api-key').forEach(function(c){
					if (c.value && !c.dataset.scritto) c.value = '';
				});
			}
			document.querySelectorAll('.sab-api-key').forEach(function(c){
				c.addEventListener('input', function(){ c.dataset.scritto = '1'; });
			});
			svuota();
			[80, 300, 900].forEach(function(ms){ setTimeout(svuota, ms); });
		})();
		document.querySelectorAll('.sab-test-key-btn').forEach(function(btn){
			btn.addEventListener('click', function(){
				var provider = this.dataset.provider;
				var out = document.querySelector('[data-provider-result="'+provider+'"]');
				var b = this;
				b.disabled = true; out.textContent = '<?php echo esc_js( __( 'Checking...', 'sabriel-ai' ) ); ?>'; out.style.color = '#888';
				fetch('<?php echo esc_js( esc_url_raw( rest_url( 'sabriel/v1/ai/test-key/' ) ) ); ?>' + provider, {
					method: 'POST',
					headers: { 'X-WP-Nonce': '<?php echo esc_js( wp_create_nonce( 'wp_rest' ) ); ?>' }
				}).then(function(r){ return r.json(); }).then(function(data){
					b.disabled = false;
					if (data.ok) { out.textContent = '<?php echo esc_js( __( '✓ Works', 'sabriel-ai' ) ); ?>'; out.style.color = '#1a7d3a'; }
					else { out.textContent = '✗ ' + (data.error || '<?php echo esc_js( __( 'Doesn\'t work', 'sabriel-ai' ) ); ?>'); out.style.color = '#b91c1c'; }
				}).catch(function(){ b.disabled = false; out.textContent = '<?php echo esc_js( __( '✗ Connection error', 'sabriel-ai' ) ); ?>'; out.style.color = '#b91c1c'; });
			});
		});
		document.querySelectorAll('.sab-remove-key-btn').forEach(function(btn){
			btn.addEventListener('click', function(){
				var provider = this.dataset.provider;
				if (!confirm(<?php echo wp_json_encode( __( 'Remove this key? If this is the active engine, the bot may stop replying until you choose another one.', 'sabriel-ai' ) ); ?>)) return;
				var b = this;
				b.disabled = true;
				fetch('<?php echo esc_js( esc_url_raw( rest_url( 'sabriel/v1/ai/remove-key/' ) ) ); ?>' + provider, {
					method: 'POST',
					headers: { 'X-WP-Nonce': '<?php echo esc_js( wp_create_nonce( 'wp_rest' ) ); ?>' }
				}).then(function(r){ return r.json(); }).then(function(data){
					if (data.ok) { location.reload(); }
					else { b.disabled = false; alert('<?php echo esc_js( __( 'I couldn\'t remove it, please try again.', 'sabriel-ai' ) ); ?>'); }
				}).catch(function(){ b.disabled = false; alert('<?php echo esc_js( __( 'Connection error, please try again.', 'sabriel-ai' ) ); ?>'); });
			});
		});
		document.querySelectorAll('.sab-model-select').forEach(function(sel){
			sel.addEventListener('change', function(){
				var box = document.querySelector('.sab-model-custom[data-provider="'+this.dataset.provider+'"]');
				if (box) { box.style.display = (this.value === '__custom__') ? 'block' : 'none'; if (this.value === '__custom__') box.focus(); }
			});
		});
		(function(){
			var SAB_AI_LBL = {
					attivo: '<?php echo esc_js( __( '● active', 'sabriel-ai' ) ); ?>',
					selezionato: '<?php echo esc_js( __( '● selected', 'sabriel-ai' ) ); ?>',
					chiave: '<?php echo esc_js( __( '✓ key saved', 'sabriel-ai' ) ); ?>',
					tocca: '<?php echo esc_js( __( 'tap to choose', 'sabriel-ai' ) ); ?>'
				};
				var cards = document.querySelectorAll('.sab-ai-card');
			function attiva(prov){
				cards.forEach(function(c){
					var suo = (c.dataset.card === prov);
						var haskey = (c.dataset.haskey === '1');
					c.style.borderColor = suo ? '#1461CC' : '#e5e5e5';
					var r = c.querySelector('.sab-ai-radio');
					if (r) r.checked = suo;
					var st = c.querySelector('.sab-ai-card-stato');
					if (st) {
							if (suo && haskey) { st.textContent = SAB_AI_LBL.attivo; st.style.color = '#1461CC'; }
							else if (suo) { st.textContent = SAB_AI_LBL.selezionato; st.style.color = '#b45309'; }
							else if (haskey) { st.textContent = SAB_AI_LBL.chiave; st.style.color = '#1a7d3a'; }
							else { st.textContent = SAB_AI_LBL.tocca; st.style.color = '#9a9a9a'; }
						}
				});
				document.querySelectorAll('.sab-ai-pannello').forEach(function(p){
					p.style.display = (p.dataset.panel === prov) ? 'block' : 'none';
				});
			}
			cards.forEach(function(c){
				c.addEventListener('click', function(){ attiva(this.dataset.card); });
			});
		})();
		</script>
		<?php
	}

	private function badge( $ok, $testo ) {
		$colore = $ok ? '#1a7d3a' : '#999';
		$sfondo = $ok ? '#eff9f0' : '#f2f2f2';
		return '<span style="display:inline-block;padding:2px 9px;border-radius:10px;font-weight:600;font-size:10.5px;color:' . $colore . ';background:' . $sfondo . '">' . esc_html( $testo ) . '</span>';
	}
}
