<?php

namespace Limb_Chatbot\Includes\AI_Providers\Claude\Endpoints\Model\Handlers;

use Limb_Chatbot\Includes\AI_Providers\Claude\Handlers\Response_Handler;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;
use WP_Http;

/**
 * Class Response_Handler
 *
 * Handles API responses from Claude Models endpoint.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Claude\Endpoints\Model
 * @since 1.0.9
 */
class Model_Response_Handler extends Response_Handler {

	/**
	 * When true, response bodies will be decoded as associative arrays.
	 *
	 * @var bool|null
	 * @since 1.0.9
	 */
	protected ?bool $body_cast_array = true;

	/**
	 * Defines and decodes the response body.
	 *
	 * @return void
	 * @since 1.0.9
	 */
	public function define_body(): void {
		if ( get_class( $this->http_client ) === WP_Http::class ) {
			$body       = wp_remote_retrieve_body( $this->response );
			$this->body = $this->is_application_json() ? json_decode( $body, $this->body_cast_array ) : $body;
		} else {
			$this->body = null;
		}
	}

	/**
	 * Checks the response for any errors and throws an exception if found.
	 *
	 * Overrides parent to handle array response body (body_cast_array = true).
	 *
	 * @return void
	 * @throws Exception If an error exists in the response.
	 * @since 1.0.9
	 */
	protected function check_for_errors(): void {
		$body    = $this->get_body();
		$error   = null;
		$message = null;

		if ( is_array( $body ) ) {
			// Check for type=error format: {"type": "error", "error": {...}}
			if ( isset( $body['type'] ) && $body['type'] === 'error' && isset( $body['error'] ) ) {
				$error   = $body['error'];
				$message = $error['message'] ?? __( 'Claude API error', 'limb-chatbot' );
			} // Check for direct error key
			elseif ( isset( $body['error'] ) ) {
				$error = $body['error'];
				if ( is_array( $error ) ) {
					$message = $error['message'] ?? __( 'Claude API error', 'limb-chatbot' );
				} else {
					$message = (string) $error;
				}
			}
		}

		if ( isset( $message ) && isset( $error ) ) {
			$error_type = is_array( $error ) ? ( $error['type'] ?? 'unknown' ) : 'unknown';
			$error_code = $this->map_error_type_to_code( $error_type );

			throw new Exception( $error_code, $message, $error, $this->get_status_code() );
		}
	}

	/**
	 * Map Claude error type to internal error code.
	 *
	 * @param  string  $error_type  The Claude error type.
	 *
	 * @return int Internal error code.
	 * @since 1.0.9
	 */
	private function map_error_type_to_code( string $error_type ): int {
		$error_map = array(
			'authentication_error'  => Error_Codes::AUTHENTICATION_UNAUTHORIZED,
			'permission_error'      => Error_Codes::AUTHENTICATION_UNAUTHORIZED,
			'invalid_api_key'       => 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::CLAUDE_ERROR,
			'overloaded_error'      => Error_Codes::CLAUDE_ERROR,
		);

		return $error_map[ $error_type ] ?? Error_Codes::CLAUDE_ERROR;
	}
}

