<?php

namespace Limb_Chatbot\Includes\AI_Providers\Claude\Handlers;

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

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

	const STATUS_CODE_QUOTA_EXCEED = 429;
	const STATUS_CODE_UNAUTHORIZED = 401;
	const STATUS_CODE_FORBIDDEN = 403;
	const STATUS_CODE_OVERLOADED = 529;

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

	/**
	 * Defines and decodes the response body.
	 *
	 * @return void
	 * @since 1.0.9
	 */
	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.9
	 */
	protected function check_for_errors(): void {
		$error   = null;
		$message = null;

		if ( isset( $this->get_body()->error ) ) {
			$error   = $this->get_body()->error;
			$message = $error->message ?? __( 'Unknown Claude API error', 'limb-chatbot' );
		} elseif ( $this->is_stream && ! empty( $this->stream_parser ) && $this->stream_parser->error ) {
			$error   = $this->stream_parser->error;
			$message = $error['message'] ?? __( 'Unknown Claude API error', 'limb-chatbot' );
		}

		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 );
			}

			// Attach utility with AI provider name prefix (same as Gemini)
			throw $exception->attach_utility( $this->get_endpoint()->get_utility(), true );
		}
	}

	/**
	 * Determines the appropriate error code based on the error data and message.
	 *
	 * Claude error types:
	 * - invalid_request_error: There was an issue with the format or content
	 * - authentication_error: There's an issue with your API key
	 * - permission_error: Your API key does not have permission
	 * - not_found_error: The requested resource was not found
	 * - rate_limit_error: Your account has hit a rate limit
	 * - api_error: An unexpected error has occurred
	 * - overloaded_error: Claude API is temporarily overloaded
	 *
	 * @param  mixed  $error  Error object or array.
	 * @param  string  $message  Error message.
	 *
	 * @return int Appropriate error code.
	 * @since 1.0.9
	 */
	protected 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:
			case self::STATUS_CODE_UNAUTHORIZED:
				return Error_Codes::AUTHENTICATION_UNAUTHORIZED;

			case self::STATUS_CODE_OVERLOADED:
				return Error_Codes::CLAUDE_ERROR;
		}

		// Check error object properties if available
		$error_type = null;
		if ( is_object( $error ) && isset( $error->type ) ) {
			$error_type = $error->type;
		} elseif ( is_array( $error ) && isset( $error['type'] ) ) {
			$error_type = $error['type'];
		}

		if ( $error_type ) {
			switch ( $error_type ) {
				case 'rate_limit_error':
					return Error_Codes::QUOTA_EXCEED;

				case 'permission_error':
				case 'authentication_error':
					return Error_Codes::AUTHENTICATION_UNAUTHORIZED;

				case 'invalid_request_error':
					return Error_Codes::VALIDATION_INVALID_VALUE;

				case 'not_found_error':
					if ( strpos( $message_lower, 'model' ) !== false ) {
						return Error_Codes::AI_MODEL_NOT_SET;
					}

					return Error_Codes::NOT_FOUND;

				case 'overloaded_error':
				case 'api_error':
					return Error_Codes::CLAUDE_ERROR;
			}
		}

		// Default to generic Claude error
		return Error_Codes::CLAUDE_ERROR;
	}
}

