<?php

namespace Limb_Chatbot\Includes\AI_Providers\Gemini\Handlers;

use Limb_Chatbot\Includes\AI_Providers\Gemini\Gemini;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use Limb_Chatbot\Includes\Services\Response_Handler as Base_Response_Handler;
use Limb_Chatbot\Includes\Interfaces\Response_Handler_Interface;

/**
 * Class Response_Handler
 *
 * Handles responses from the Gemini AI provider.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Gemini\Handlers
 * @since 1.0.0
 */
class Response_Handler extends Base_Response_Handler implements Response_Handler_Interface {

	const STATUS_CODE_QUOTA_EXCEED = 429;

	/**
	 * Parses the response and checks for errors.
	 *
	 * @return void
	 * @throws Exception When an error is detected in the response.
	 * @since 1.0.0
	 */
	public function parse() {
		parent::parse();
		static::check_for_errors();
	}

	/**
	 * Defines and decodes the response body.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function define_body(): void {
		$body       = wp_remote_retrieve_body( $this->response );
		$this->body = $this->is_application_json() ? json_decode( $body ) : $body;
	}

	/**
	 * Checks the response for any errors and throws an exception if found.
	 *
	 * @return void
	 * @throws Exception If an error exists in the response or stream parser.
	 * @since 1.0.0
	 */
	protected function check_for_errors(): void {
		if ( isset( $this->get_body()->error ) ) {
			$message     = $this->get_body()->error->message ?? __( 'error', 'limb-chatbot' );
			$error       = $this->get_body()->error;
		} elseif ( $this->is_stream && $this->stream_parser->error ) {
			$error       = $this->stream_parser->error;
			$message     = $error['message'] ?? Gemini::$name . ' error';
		}
		if ( isset( $message ) && isset( $error ) ) {
			$error_code = $this->determine_error_code( $error, $message );
			$exception = new Exception( $error_code, $message, $error, $this->get_status_code() );
			
			// Set quota flag for quota-related errors
			if ( $error_code === Error_Codes::QUOTA_EXCEED ) {
				$exception->set_related_to_quota( true );
			}
			
			throw $exception->attach_utility( $this->get_endpoint()->get_utility(), true );
		}
	}
	
	/**
	 * Determines the appropriate error code based on the error data and message.
	 *
	 * @param mixed $error Error object or array
	 * @param string $message Error message
	 * @return int Appropriate error code
	 * @since 1.0.0
	 */
	private function determine_error_code( $error, string $message ): int {
		$status_code = $this->get_status_code();
		$message_lower = strtolower( $message );
		
		// Check HTTP status codes first
		switch ( $status_code ) {
			case self::STATUS_CODE_QUOTA_EXCEED:
				return Error_Codes::QUOTA_EXCEED;
				
			case self::STATUS_CODE_FORBIDDEN:
				return Error_Codes::AUTHENTICATION_UNAUTHORIZED;
		}
		
		// Check error object properties if available
		if ( is_object( $error ) ) {
			if ( isset( $error->code ) ) {
				switch ( $error->code ) {
					case 'RESOURCE_EXHAUSTED':
					case 'RATE_LIMIT_EXCEEDED':
						return Error_Codes::QUOTA_EXCEED;

					case 'PERMISSION_DENIED':
						return Error_Codes::AUTHENTICATION_UNAUTHORIZED;
						
					case 'INVALID_ARGUMENT':
						return Error_Codes::VALIDATION_INVALID_VALUE;
						
					case 'NOT_FOUND':
						if ( strpos( $message_lower, 'model' ) !== false ) {
							return Error_Codes::AI_MODEL_NOT_SET;
						}
						return Error_Codes::NOT_FOUND;
				}
			}
		}
		
		// Default to generic Gemini error
		return Error_Codes::GEMINI_ERROR;
	}
}
