<?php
/**
 * Sifency AI — API Handler
 *
 * Provider-agnostic wrapper. Supports OpenAI and Anthropic (Claude).
 * The active provider + key are pulled from WP options so the user
 * only has to configure them once in the AI Studio settings page.
 *
 * @package Sifency_Addons
 * @since   1.0.5
 */

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

class Sifency_Addons_AI_API {

	/*
	 ------------------------------------------------------------------ */
	/*
	  Config                                                              */
	/* ------------------------------------------------------------------ */

	private string $provider;
	private string $api_key;
	private string $model;

	/** Supported providers and their default models. Updated to latest 2026/2025 releases. */
	private const PROVIDERS = array(
		'openai'    => array(
			'endpoint'      => 'https://api.openai.com/v1/chat/completions',
			'default_model' => 'gpt-4.5', // OpenAI's premier 2025/2026 flagship model
		),
		'anthropic' => array(
			'endpoint'      => 'https://api.anthropic.com/v1/messages',
			'default_model' => 'claude-3-7-sonnet-20260219', // Anthropic's flagship 3.7 Sonnet (2026 release)
		),
		'gemini'    => array(
			'endpoint'      => 'https://generativelanguage.googleapis.com/v1beta/models/',
			'default_model' => 'gemini-2.0-flash', // Google's ultra-fast, high-quality 2.0 Flash model
		),
		'groq'      => array(
			'endpoint'      => 'https://api.groq.com/openai/v1/chat/completions',
			'default_model' => 'llama-3.3-70b-versatile', // Groq's most stable and capable open-source model
		),
	);

	public function __construct() {
		$this->provider = get_option( 'sifency_ai_provider', 'openai' );
		$this->api_key  = get_option( 'sifency_ai_api_key', '' );
		$this->model    = get_option( 'sifency_ai_model', '' );

		// Fall back to default model if none stored.
		if ( empty( $this->model ) ) {
			$this->model = self::PROVIDERS[ $this->provider ]['default_model'] ?? '';
		}
	}

	/*
	 ------------------------------------------------------------------ */
	/*
	  Public Interface                                                    */
	/* ------------------------------------------------------------------ */

	/**
	 * Send a system + user message to the configured AI provider.
	 *
	 * @param  string $system_prompt  Instructions / persona for the AI.
	 * @param  string $user_prompt    The user's actual request.
	 * @param  int    $max_tokens     Token ceiling for the response.
	 * @return string|\WP_Error       Raw text content or a WP_Error.
	 */
	public function chat( string $system_prompt, string $user_prompt, int $max_tokens = 4000 ): string|\WP_Error {
		if ( empty( $this->api_key ) ) {
			return new \WP_Error(
				'sifency_ai_no_key',
				__( 'API key is not set. Please configure it in Sifency AI → Settings.', 'sifency-addons' )
			);
		}

		return match ( $this->provider ) {
			'anthropic' => $this->call_anthropic( $system_prompt, $user_prompt, $max_tokens ),
			'gemini'    => $this->call_gemini( $system_prompt, $user_prompt, $max_tokens ),
			'groq'      => $this->call_openai( $system_prompt, $user_prompt, $max_tokens, self::PROVIDERS['groq']['endpoint'] ),
			default     => $this->call_openai( $system_prompt, $user_prompt, $max_tokens, self::PROVIDERS['openai']['endpoint'] ),
		};
	}

	/*
	 ------------------------------------------------------------------ */
	/*
	  OpenAI / Groq                                                       */
	/* ------------------------------------------------------------------ */

	private function call_openai( string $system, string $user, int $max_tokens, string $endpoint ): string|\WP_Error {
		$body = wp_json_encode(
			array(
				'model'      => $this->model,
				'max_tokens' => $max_tokens,
				'messages'   => array(
					array(
						'role'    => 'system',
						'content' => $system,
					),
					array(
						'role'    => 'user',
						'content' => $user,
					),
				),
			)
		);

		$response = wp_remote_post(
			$endpoint,
			array(
				'timeout' => 90,
				'headers' => array(
					'Content-Type'  => 'application/json',
					'Authorization' => 'Bearer ' . $this->api_key,
				),
				'body'    => $body,
			)
		);

		return $this->parse_openai_response( $response );
	}

	private function parse_openai_response( $response ): string|\WP_Error {
		if ( is_wp_error( $response ) ) {
			return $response;
		}

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

		if ( $code !== 200 ) {
			$msg = $data['error']['message'] ?? __( 'OpenAI/Groq API error.', 'sifency-addons' );
			return new \WP_Error( 'sifency_ai_openai_error', $msg );
		}

		return $data['choices'][0]['message']['content'] ?? '';
	}

	/*
	 ------------------------------------------------------------------ */
	/*
	  Anthropic (Claude)                                                  */
	/* ------------------------------------------------------------------ */

	private function call_anthropic( string $system, string $user, int $max_tokens ): string|\WP_Error {
		$body = wp_json_encode(
			array(
				'model'      => $this->model,
				'max_tokens' => $max_tokens,
				'system'     => $system,
				'messages'   => array(
					array(
						'role'    => 'user',
						'content' => $user,
					),
				),
			)
		);

		$response = wp_remote_post(
			self::PROVIDERS['anthropic']['endpoint'],
			array(
				'timeout' => 90,
				'headers' => array(
					'Content-Type'      => 'application/json',
					'x-api-key'         => $this->api_key,
					'anthropic-version' => '2023-06-01',
				),
				'body'    => $body,
			)
		);

		return $this->parse_anthropic_response( $response );
	}

	private function parse_anthropic_response( $response ): string|\WP_Error {
		if ( is_wp_error( $response ) ) {
			return $response;
		}

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

		if ( $code !== 200 ) {
			$msg = $data['error']['message'] ?? __( 'Anthropic API error.', 'sifency-addons' );
			return new \WP_Error( 'sifency_ai_anthropic_error', $msg );
		}

		// Anthropic returns content as an array of blocks.
		foreach ( $data['content'] ?? array() as $block ) {
			if ( ( $block['type'] ?? '' ) === 'text' ) {
				return $block['text'];
			}
		}

		return new \WP_Error( 'sifency_ai_empty', __( 'AI returned an empty response.', 'sifency-addons' ) );
	}

	/*
	 ------------------------------------------------------------------ */
	/*
	  Google Gemini                                                       */
	/* ------------------------------------------------------------------ */

	private function call_gemini( string $system, string $user, int $max_tokens ): string|\WP_Error {
		$body = wp_json_encode(
			array(
				'systemInstruction' => array(
					'parts' => array(
						array( 'text' => $system ),
					),
				),
				'contents'          => array(
					array(
						'role'  => 'user',
						'parts' => array(
							array( 'text' => $user ),
						),
					),
				),
				'generationConfig'  => array(
					'maxOutputTokens' => $max_tokens,
				),
			)
		);

		$endpoint = self::PROVIDERS['gemini']['endpoint'] . $this->model . ':generateContent?key=' . $this->api_key;

		$response = wp_remote_post(
			$endpoint,
			array(
				'timeout' => 90,
				'headers' => array(
					'Content-Type' => 'application/json',
				),
				'body'    => $body,
			)
		);

		return $this->parse_gemini_response( $response );
	}

	private function parse_gemini_response( $response ): string|\WP_Error {
		if ( is_wp_error( $response ) ) {
			return $response;
		}

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

		if ( $code !== 200 ) {
			$msg = $data['error']['message'] ?? __( 'Google Gemini API error.', 'sifency-addons' );
			return new \WP_Error( 'sifency_ai_gemini_error', $msg );
		}

		if ( isset( $data['candidates'][0]['content']['parts'][0]['text'] ) ) {
			return $data['candidates'][0]['content']['parts'][0]['text'];
		}

		return new \WP_Error( 'sifency_ai_empty', __( 'AI returned an empty response.', 'sifency-addons' ) );
	}

	/*
	 ------------------------------------------------------------------ */
	/*
	  Helpers                                                             */
	/* ------------------------------------------------------------------ */

	/** Return the list of supported providers for the settings UI. */
	public static function get_providers(): array {
		return array_keys( self::PROVIDERS );
	}

	/** Return the default model for a given provider. */
	public static function get_default_model( string $provider ): string {
		return self::PROVIDERS[ $provider ]['default_model'] ?? '';
	}

	/*
	 ------------------------------------------------------------------ */
	/*
	  Verification                                                        */
	/* ------------------------------------------------------------------ */

	public static function verify_credentials( string $provider, string $api_key, string $model = '' ): bool|\WP_Error {
		if ( empty( $api_key ) ) {
			return new \WP_Error( 'sifency_ai_empty_key', __( 'API key cannot be empty.', 'sifency-addons' ) );
		}

		if ( empty( $model ) ) {
			$model = self::PROVIDERS[ $provider ]['default_model'] ?? '';
		}

		if ( 'gemini' === $provider ) {
			// For Gemini, we ping the models endpoint to verify the key and get available models.
			$url      = 'https://generativelanguage.googleapis.com/v1beta/models?key=' . $api_key;
			$response = wp_remote_get( $url, array( 'timeout' => 15 ) );

			if ( is_wp_error( $response ) ) {
				return $response;
			}

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

			if ( $code !== 200 ) {
				$msg = $data['error']['message'] ?? __( 'Invalid Gemini API key.', 'sifency-addons' );
				return new \WP_Error( 'sifency_ai_gemini_verify', $msg );
			}

			// Valid key! Let's check if the model is supported.
			$available_models = array();
			$model_found      = false;
			foreach ( $data['models'] ?? array() as $m ) {
				$m_name = str_replace( 'models/', '', $m['name'] );
				if ( in_array( 'generateContent', $m['supportedGenerationMethods'] ?? array(), true ) ) {
					$available_models[] = $m_name;
					if ( $m_name === $model ) {
						$model_found = true;
					}
				}
			}

			if ( ! $model_found ) {
				return new \WP_Error(
					'sifency_ai_invalid_model',
					sprintf(
					/* translators: %1$s: model name, %2$s: comma-separated list of supported models */
						__( 'Your API key is valid, but the model "%1$s" is not supported or not available for your account. Supported models are: %2$s', 'sifency-addons' ),
						$model,
						implode( ', ', array_slice( $available_models, 0, 5 ) )
					)
				);
			}

			return true;
		}

		if ( 'openai' === $provider || 'groq' === $provider ) {
			$url      = 'openai' === $provider ? 'https://api.openai.com/v1/models' : 'https://api.groq.com/openai/v1/models';
			$response = wp_remote_get(
				$url,
				array(
					'timeout' => 15,
					'headers' => array( 'Authorization' => 'Bearer ' . $api_key ),
				)
			);

			if ( is_wp_error( $response ) ) {
				return $response;
			}
			if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
				$err_msg = 'openai' === $provider ? __( 'Invalid OpenAI API key.', 'sifency-addons' ) : __( 'Invalid Groq API key.', 'sifency-addons' );
				return new \WP_Error( 'sifency_ai_openai_verify', $err_msg );
			}
			return true;
		}

		if ( 'anthropic' === $provider ) {
			// Anthropic doesn't have a simple models endpoint that validates keys via GET without params,
			// so we just do a tiny ping to the messages endpoint.
			$body = wp_json_encode(
				array(
					'model'      => $model,
					'max_tokens' => 1,
					'messages'   => array(
						array(
							'role'    => 'user',
							'content' => 'hi',
						),
					),
				)
			);

			$response = wp_remote_post(
				self::PROVIDERS['anthropic']['endpoint'],
				array(
					'timeout' => 15,
					'headers' => array(
						'Content-Type'      => 'application/json',
						'x-api-key'         => $api_key,
						'anthropic-version' => '2023-06-01',
					),
					'body'    => $body,
				)
			);

			if ( is_wp_error( $response ) ) {
				return $response;
			}

			$code = wp_remote_retrieve_response_code( $response );
			if ( $code !== 200 ) {
				$raw  = wp_remote_retrieve_body( $response );
				$data = json_decode( $raw, true );
				$msg  = $data['error']['message'] ?? __( 'Invalid Anthropic API key.', 'sifency-addons' );
				return new \WP_Error( 'sifency_ai_anthropic_verify', $msg );
			}
			return true;
		}

		return true;
	}
}
