<?php

namespace Limb_Chatbot\Includes\AI_Providers\Deep_Seek\Handlers;

use Limb_Chatbot\Includes\AI_Providers\Open_Ai\Handlers\Response_Handler as Handler;
use Limb_Chatbot\Includes\AI_Providers\Deep_Seek\Deep_Seek;
use Limb_Chatbot\Includes\Exceptions\Error_Codes;
use Limb_Chatbot\Includes\Exceptions\Exception;

/**
 * Class Response_Handler
 *
 * Handles API responses from the Deep Seek AI provider, extending the generic OpenAI response handler.
 * Checks for errors in streamed and non-streamed responses and throws exceptions accordingly.
 *
 * @package Limb_Chatbot\Includes\AI_Providers\Deep_Seek\Handlers
 * @since 1.0.0
 */
class Response_Handler extends Handler {

	/**
	 * Response_Handler constructor.
	 *
	 * Initializes the handler with response data, HTTP client, optional endpoint, and stream parser.
	 *
	 * @param mixed  $response  Raw response data from the API.
	 * @param  object  $http_client  HTTP client instance used for the request.
	 * @param  object|null  $endpoint  Optional endpoint instance associated with the request.
	 * @param  mixed  $stream_parser  Optional stream parser for handling streamed responses.
	 *
	 * @since 1.0.0
	 */
	public function __construct( $response, $http_client, $endpoint = null, $stream_parser = null ) {
		parent::__construct( $response, $http_client, $endpoint, $stream_parser );
	}

	/**
	 * Check the API response for any error messages.
	 *
	 * Throws an Exception if an error is detected either in the stream parser or the response body.
	 * Enhanced with comprehensive error detection and classification.
	 *
	 * @since 1.0.0
	 *
	 * @throws Exception If the API response contains an error.
	 */
	protected function check_for_errors(): void {
		if ( empty( $this->stream_parser ) ) {
			$error = is_object( $this->get_body() ) && ! empty( $this->get_body()->error ) ? $this->get_body()->error : ( is_array( $this->get_body() ) && ! empty( $this->get_body()['error'] ) ? $this->get_body()['error'] : null );
		} else {
			$error = $this->stream_parser->error;
		}
		if ( ! empty( $error ) ) {
			$error = (array) $error;
			$message = $error['message'] ?? Deep_Seek::$name . ' error';
			$error_code = $this->determine_deep_seek_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 for Deep Seek errors.
	 *
	 * @param array  $error   Error data from the API response.
	 * @param string $message Error message from the API.
	 * @return int Appropriate internal error code.
	 * @since 1.0.0
	 */
	private function determine_deep_seek_error_code( array $error, string $message ): int {
		$status_code = $this->get_status_code();
		$message_lower = strtolower( $message );
		
		// Check HTTP status codes first
		switch ( $status_code ) {
			case 400:
				// Invalid Format - Invalid request body format
				return Error_Codes::VALIDATION_INVALID_VALUE;
			case 401:
				// Authentication Fails - Wrong API key
				return Error_Codes::AUTHENTICATION_UNAUTHORIZED;
			case 402:
				// Insufficient Balance - Out of balance
				return Error_Codes::QUOTA_EXCEED;
			case 422:
				// Invalid Parameters - Request contains invalid parameters
				return Error_Codes::VALIDATION_INVALID_VALUE;
			case 429:
				// Rate Limit Reached - Sending requests too quickly
				return Error_Codes::QUOTA_EXCEED;
			case 500:
				// Server Error - DeepSeek server issue
				return Error_Codes::TECHNICAL_ERROR;
			case 503:
				// Server Overloaded - High traffic
				return Error_Codes::TECHNICAL_ERROR;
		}
		
		// Check error type if available (Deep Seek often uses OpenAI-compatible error types)
		if ( isset( $error['type'] ) ) {
			switch ( $error['type'] ) {
				case 'insufficient_quota':
				case 'billing_not_active':
				case 'rate_limit_exceeded':
					return Error_Codes::QUOTA_EXCEED;
					
				case 'invalid_api_key':
				case 'invalid_organization':
					return Error_Codes::AUTHENTICATION_API_KEY_MISSING;
					
				case 'permission_denied':
				case 'access_denied':
					return Error_Codes::AUTHENTICATION_UNAUTHORIZED;
				case 'invalid_format':
				case 'invalid_parameters':
				case 'invalid_request_error':
					return Error_Codes::VALIDATION_INVALID_VALUE;
				case 'server_error':
				case 'service_unavailable':
					return Error_Codes::TECHNICAL_ERROR;
				case 'model_not_found':
					return Error_Codes::AI_MODEL_NOT_SET;
			}
		}
		
		// Check error message content for specific patterns
		if ( strpos( $message_lower, 'quota' ) !== false ||
			 strpos( $message_lower, 'rate limit' ) !== false ||
			 strpos( $message_lower, 'too many requests' ) !== false ||
			 strpos( $message_lower, 'limit exceeded' ) !== false ||
			 strpos( $message_lower, 'insufficient balance' ) !== false ||
			 strpos( $message_lower, 'run out of balance' ) !== false ) {
			return Error_Codes::QUOTA_EXCEED;
		}
		
		if ( strpos( $message_lower, 'api key' ) !== false ||
			 strpos( $message_lower, 'authentication' ) !== false ||
			 strpos( $message_lower, 'unauthorized' ) !== false ) {
			return Error_Codes::AUTHENTICATION_UNAUTHORIZED;
		}
		
		if ( strpos( $message_lower, 'invalid format' ) !== false ||
			 strpos( $message_lower, 'invalid request' ) !== false ||
			 strpos( $message_lower, 'invalid parameter' ) !== false ||
			 strpos( $message_lower, 'request body' ) !== false ) {
			return Error_Codes::VALIDATION_INVALID_VALUE;
		}

		if ( strpos( $message_lower, 'model' ) !== false &&
			 ( strpos( $message_lower, 'not found' ) !== false ||
			   strpos( $message_lower, 'invalid' ) !== false ||
			   strpos( $message_lower, 'unsupported' ) !== false ) ) {
			return Error_Codes::AI_MODEL_NOT_SET;
		}
		
		if ( strpos( $message_lower, 'server error' ) !== false ||
			 strpos( $message_lower, 'server overloaded' ) !== false ||
			 strpos( $message_lower, 'service unavailable' ) !== false ||
			 strpos( $message_lower, 'high traffic' ) !== false ) {
			return Error_Codes::TECHNICAL_ERROR;
		}

		// Default to generic Deep Seek error
		return Error_Codes::DEEP_SEEK_ERROR;
	}
}
