<?php

namespace Limb_Chatbot\Includes\AI_Providers\Grok\Endpoints;

use Limb_Chatbot\Includes\AI_Providers\Grok\Grok;
use Limb_Chatbot\Includes\Data_Objects\Config;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Services\Endpoint;

/**
 * Class Grok_Endpoint
 *
 * Base endpoint class for xAI API interactions.
 * Provides common functionality such as header generation including authentication.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Grok\Endpoints
 * @since 1.0.12
 */
class Grok_Endpoint extends Endpoint {

	/**
	 * xAI API base URL.
	 *
	 * @var string
	 * @since 1.0.12
	 */
	const API_BASE_URL = 'https://api.x.ai/v1';

	/**
	 * Generate HTTP headers for API requests.
	 *
	 * Throws exception if API key is missing or empty.
	 *
	 * @param  Config|null  $config  Optional Config object. If null, uses internal config.
	 * @param  string  $content_type  Content-Type header value. Defaults to 'application/json'.
	 *
	 * @return array<string, string> HTTP headers including Authorization Bearer token.
	 *
	 * @throws Exception Throws if API key is missing or empty in the config.
	 *
	 * @since 1.0.12
	 */
	protected function get_header(
		?Config $config = null,
		string $content_type = 'application/json'
	): array {
		$config = $config ?? $this->get_config();
		if ( ! ( $config instanceof Config ) ) {
			$global_utility = property_exists( $this->utility,
				'global_utility' ) ? $this->utility->global_utility : $this->utility;
			throw ( new Exception( Error_Codes::AUTHENTICATION_API_KEY_MISSING,
				__( 'Api key is missing.', 'limb-chatbot' ) ) )->with_link( $global_utility, null, null, null,
				'ai-settings', 'config_id' );
		}
		if ( empty( $config->get_params()['api_key'] ) ) {
			$global_utility = property_exists( $this->utility,
				'global_utility' ) ? $this->utility->global_utility : $this->utility;
			throw ( ( new Exception( Error_Codes::AUTHENTICATION_API_KEY_MISSING,
				__( 'Api key is empty.', 'limb-chatbot' ) ) )->with_link( $global_utility, null, null, Grok::$id,
				'api-keys' ) );
		}

		return array(
			'Authorization' => 'Bearer ' . $config->get_params()['api_key'],
			'Content-Type'  => $content_type,
		);
	}

	/**
	 * Get the API key from config object.
	 *
	 * @param  Config|null  $config  Optional config object.
	 *
	 * @return string The API key string.
	 * @throws Exception If API key is missing or config is invalid.
	 * @since 1.0.12
	 */
	public function get_auth_key( ?Config $config = null ): string {
		$config = $config ?? $this->get_config();
		if ( empty( $config ) || ! ( $config instanceof Config ) || empty( $config->get_params()['api_key'] ) ) {
			$global_utility = property_exists( $this->utility,
				'global_utility' ) ? $this->utility->global_utility : $this->utility;
			throw ( new Exception( Error_Codes::AUTHENTICATION_API_KEY_MISSING,
				__( 'Api key is missing', 'limb-chatbot' ) ) )->attach_utility( $global_utility );
		}

		return $config->get_params()['api_key'];
	}

	/**
	 * Handle xAI API error responses.
	 *
	 * Maps xAI error types to plugin error codes.
	 *
	 * @param  object  $response_body  The decoded response body containing error info.
	 *
	 * @throws Exception With appropriate error code and message.
	 * @since 1.0.12
	 */
	protected function handle_error( $response_body ): void {
		if ( empty( $response_body->error ) ) {
			return;
		}

		$error_type    = $response_body->error->type ?? 'unknown';
		$error_message = $response_body->error->message ?? __( 'Unknown xAI API error', 'limb-chatbot' );

		$error_map = array(
			'authentication_error'  => Error_Codes::AUTHENTICATION_UNAUTHORIZED,
			'permission_error'      => Error_Codes::AUTHENTICATION_UNAUTHORIZED,
			'rate_limit_error'      => Error_Codes::QUOTA_EXCEED,
			'invalid_request_error' => Error_Codes::VALIDATION_INVALID_VALUE,
			'not_found_error'       => Error_Codes::NOT_FOUND,
			'api_error'             => Error_Codes::TECHNICAL_ERROR,
		);

		$error_code = $error_map[ $error_type ] ?? Error_Codes::TECHNICAL_ERROR;

		throw new Exception( $error_code, $error_message );
	}
}
