<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'SftcyWordaiAnthropicApi' ) ) :

class SftcyWordaiAnthropicApi {

	protected static $API_KEY = null;

	public static $AI_MESSAGES_EP = 'https://api.anthropic.com/v1/messages';
	public static $MODEL          = 'claude-sonnet-5';
	public static $STREAM         = null;
	public static $output         = [];

	private static $STREAM_MODE   = 'raw';
	private static $STREAM_BUFFER = '';

	public function __construct() {
		self::ensure_api_key();
	}

	protected static function ensure_api_key() {
		if ( ! is_null( self::$API_KEY ) ) {
			return;
		}

		if ( ! class_exists( 'SftcyWordaiBase' ) ) {
			return;
		}

		$data = SftcyWordaiBase::sc_wordai_get_current_api_settings();

		self::$API_KEY = ! empty( $data['wordai-anthropic-api-key-data'] )
			? trim( (string) $data['wordai-anthropic-api-key-data'] )
			: null;
	}

	public static function sc_anthropic_streaming_status() {
		$data = SftcyWordaiBase::sc_wordai_get_current_api_settings();
		return ( isset( $data['sc-wordai-streaming'] ) && intval( $data['sc-wordai-streaming'] ) === 1 );
	}

	public static function set_stream_mode( $mode ) {
		$mode = strtolower( (string) $mode );
		self::$STREAM_MODE = in_array( $mode, [ 'raw', 'sse' ], true ) ? $mode : 'raw';
	}

	public static function sc_curl_add_streaming_hook() {
		add_action( 'http_api_curl', [ __CLASS__, 'sc_wordai_anthropic_stream_response' ], 10, 3 );
	}

	public static function sc_curl_remove_streaming_hook() {
		remove_action( 'http_api_curl', [ __CLASS__, 'sc_wordai_anthropic_stream_response' ], 10 );
	}

	public static function sc_wordai_anthropic_stream_response( $handle, $r = [], $url = '' ) {
		if ( self::$STREAM !== true ) {
			return;
		}

		self::$STREAM_BUFFER = '';

		@ob_end_clean();
		@ob_start();

		curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, 1 );
		curl_setopt(
			$handle,
			CURLOPT_WRITEFUNCTION,
			function ( $curl, $data ) {
				if ( self::$STREAM_MODE === 'raw' ) {
					echo $data;
					@ob_flush();
					flush();
					return strlen( $data );
				}

				self::$STREAM_BUFFER .= (string) $data;

				while ( false !== strpos( self::$STREAM_BUFFER, "\n\n" ) ) {
					list( $event_block, $remaining ) = explode( "\n\n", self::$STREAM_BUFFER, 2 );
					self::$STREAM_BUFFER = $remaining;

					$event = '';
					$data_lines = [];

					foreach ( preg_split( "/\r?\n/", trim( $event_block ) ) as $line ) {
						$line = trim( $line );
						if ( strpos( $line, 'event:' ) === 0 ) {
							$event = trim( substr( $line, 6 ) );
						} elseif ( strpos( $line, 'data:' ) === 0 ) {
							$data_lines[] = trim( substr( $line, 5 ) );
						}
					}

					if ( empty( $data_lines ) ) {
						continue;
					}

					$json = implode( "\n", $data_lines );

					if ( $event === 'message_stop' ) {
						echo "data: [DONE]\n\n";
						@ob_flush();
						flush();
						continue;
					}

					$decoded = json_decode( $json, true );
					if ( ! is_array( $decoded ) ) {
						continue;
					}

					if ( isset( $decoded['error']['message'] ) ) {
						echo "data: " . wp_json_encode( [ 'error' => [ 'message' => $decoded['error']['message'] ] ] ) . "\n\n";
						@ob_flush();
						flush();
						continue;
					}

					if (
						$event === 'content_block_delta'
						&& isset( $decoded['delta']['type'] )
						&& $decoded['delta']['type'] === 'text_delta'
						&& isset( $decoded['delta']['text'] )
					) {
						echo "data: " . wp_json_encode( [ 'replyChunk' => (string) $decoded['delta']['text'] ] ) . "\n\n";
						@ob_flush();
						flush();
					}
				}

				return strlen( $data );
			}
		);
	}

	public static function anthropic_models() {
		return [
			'Claude 5 (Latest)' => [
				'claude-sonnet-5' => __( 'Claude Sonnet 5 (Recommended)', 'wordai-pro' ),
				'claude-fable-5'  => __( 'Claude Fable 5 (Maximum Capability)', 'wordai-pro' ),
			],
			'Claude Opus 4.x (Current)' => [
				'claude-opus-4-8' => __( 'Claude Opus 4.8', 'wordai-pro' ),
				'claude-opus-4-7' => __( 'Claude Opus 4.7', 'wordai-pro' ),
				'claude-opus-4-6' => __( 'Claude Opus 4.6', 'wordai-pro' ),
			],
			'Claude Efficient & Compatibility' => [
				'claude-sonnet-4-6'         => __( 'Claude Sonnet 4.6 (Stable Compatibility)', 'wordai-pro' ),
				'claude-haiku-4-5-20251001' => __( 'Claude Haiku 4.5', 'wordai-pro' ),
				'claude-sonnet-4-5-20250929' => __( 'Claude Sonnet 4.5 (Pinned Snapshot)', 'wordai-pro' ),
			],
		];
	}

	public static function normalize_anthropic_model_slug( $model = '' ) {
		$model   = sanitize_text_field( (string) $model );
		$aliases = [
			'claude-haiku-4-5'  => 'claude-haiku-4-5-20251001',
			'claude-sonnet-4-5' => 'claude-sonnet-4-5-20250929',
		];

		if ( isset( $aliases[ $model ] ) ) {
			$model = $aliases[ $model ];
		}

		foreach ( self::anthropic_models() as $models ) {
			if ( isset( $models[ $model ] ) ) {
				return $model;
			}
		}

		return self::$MODEL;
	}

	/**
	 * Anthropic models commonly reject requests that include both temperature
	 * and top_p together. Keep temperature as the primary sampling control
	 * and only send top_p when temperature is intentionally absent.
	 *
	 * @param array $body
	 * @return array
	 */
	private static function normalize_sampling_params( array $body ) {
		$model = isset( $body['model'] ) ? self::normalize_anthropic_model_slug( $body['model'] ) : self::$MODEL;
		$body['model'] = $model;

		if ( in_array( $model, [ 'claude-sonnet-5', 'claude-fable-5', 'claude-opus-4-8', 'claude-opus-4-7' ], true ) ) {
			unset( $body['temperature'], $body['top_p'], $body['top_k'] );
			return $body;
		}

		$has_temperature = array_key_exists( 'temperature', $body ) && $body['temperature'] !== null && $body['temperature'] !== '';
		$has_top_p       = array_key_exists( 'top_p', $body ) && $body['top_p'] !== null && $body['top_p'] !== '';

		if ( $has_temperature && $has_top_p ) {
			unset( $body['top_p'] );
		}

		return $body;
	}

	public static function set_anthropic_params( $prompt, $system_instruction = '', $overrides = [] ) {
		$data = class_exists( 'SftcyWordaiBase' )
			? SftcyWordaiBase::sc_wordai_get_current_api_settings()
			: [];

		$model = ! empty( $data['sc-wordai-anthropic-model-slug'] )
			? trim( (string) $data['sc-wordai-anthropic-model-slug'] )
			: self::$MODEL;
		$model = self::normalize_anthropic_model_slug( $model );

		$temperature = isset( $data['sc-wordai-temperature'] ) ? floatval( $data['sc-wordai-temperature'] ) : 0.7;
		$top_p       = isset( $data['sc-wordai-top-p'] ) ? floatval( $data['sc-wordai-top-p'] ) : 0.9;
		$max_tokens  = ! empty( $data['sc-wordai-max-tokens'] ) ? intval( $data['sc-wordai-max-tokens'] ) : 2048;
		$stop_input  = ! empty( $data['sc-wordai-stop-input'] ) ? trim( (string) $data['sc-wordai-stop-input'] ) : '';

		if ( isset( $overrides['temperature'] ) ) {
			$temperature = floatval( $overrides['temperature'] );
		}
		if ( isset( $overrides['top_p'] ) ) {
			$top_p = floatval( $overrides['top_p'] );
		}
		if ( isset( $overrides['max_tokens'] ) ) {
			$max_tokens = intval( $overrides['max_tokens'] );
		}

		$temperature = max( 0.0, min( 1.0, $temperature ) );
		$top_p       = max( 0.0, min( 1.0, $top_p ) );
		$max_tokens  = max( 64, $max_tokens );

		$body = [
			'model'      => $model,
			'max_tokens' => $max_tokens,
			'messages'   => [
				[
					'role'    => 'user',
					'content' => [
						[
							'type' => 'text',
							'text' => trim( (string) $prompt ),
						],
					],
				],
			],
			'temperature' => $temperature,
			'top_p'       => $top_p,
		];

		if ( $system_instruction !== '' ) {
			$body['system'] = trim( (string) $system_instruction );
		}

		if ( $stop_input !== '' ) {
			$body['stop_sequences'] = array_map(
				'trim',
				array_filter( explode( ',', $stop_input ) )
			);
		}

		$body = self::normalize_sampling_params( $body );

		return [
			'model' => $model,
			'body'  => $body,
		];
	}

	private static function extract_text_blocks( $content_blocks ) {
		$text = '';

		if ( ! is_array( $content_blocks ) ) {
			return $text;
		}

		foreach ( $content_blocks as $block ) {
			if ( isset( $block['type'] ) && $block['type'] === 'text' && isset( $block['text'] ) ) {
				$text .= (string) $block['text'];
			}
		}

		return $text;
	}

	private static function send_messages_request( $body, $stream = false, $stream_mode = 'raw' ) {
		self::$output = [];
		self::$output['wordAIRequestParams'] = $body;

		self::ensure_api_key();

		if ( empty( self::$API_KEY ) ) {
			self::$output['status']              = 'fail';
			self::$output['comment']             = 'Valid API Key missing.';
			self::$output['wordAIAPIKeyMissing'] = __( 'Valid Anthropic API Key required.', 'wordai-pro' );
			return self::$output;
		}

		$request_body = is_array( $body ) ? $body : [];
		$request_body['stream'] = (bool) $stream;

		if ( $stream ) {
			self::$STREAM = true;
			self::set_stream_mode( $stream_mode );
			self::sc_curl_add_streaming_hook();
		} else {
			self::$STREAM = false;
			self::set_stream_mode( 'raw' );
		}

		$args = [
			'headers'     => [
				'x-api-key'         => self::$API_KEY,
				'anthropic-version' => '2023-06-01',
				'Content-Type'      => 'application/json; charset=UTF-8',
			],
			'timeout'     => 90,
			'httpversion' => '1.1',
			'sslverify'   => false,
			'data_format' => 'body',
			'body'        => wp_json_encode( $request_body ),
		];

		$response = wp_remote_post( self::$AI_MESSAGES_EP, $args );

		if ( $stream ) {
			self::sc_curl_remove_streaming_hook();
			exit;
		}

		if ( is_wp_error( $response ) ) {
			self::$output['status']       = 'fail';
			self::$output['errorMessage'] = $response->get_error_message();
			return self::$output;
		}

		$body_decoded = json_decode( wp_remote_retrieve_body( $response ), true );
		$http_code    = wp_remote_retrieve_response_code( $response );

		self::$output['responseBody'] = $body_decoded;

		if ( $http_code < 200 || $http_code >= 300 ) {
			self::$output['status']       = 'fail';
			self::$output['errorMessage'] = $body_decoded['error']['message'] ?? __( 'Anthropic request failed.', 'wordai-pro' );
			self::$output['errorType']    = $body_decoded['error']['type'] ?? 'anthropic_error';
			return self::$output;
		}

		$text = self::extract_text_blocks( $body_decoded['content'] ?? [] );

		if ( $text === '' ) {
			self::$output['status']       = 'fail';
			self::$output['errorMessage'] = __( 'Anthropic returned no text response.', 'wordai-pro' );
			return self::$output;
		}

		self::$output['status']       = 'success';
		self::$output['responseText'] = wp_kses_post( $text );
		self::$output['model']        = esc_html( $request_body['model'] ?? self::$MODEL );

		return self::$output;
	}

	public static function create_content( $api_params = [], $stream = false ) {
		if ( ! isset( $api_params['body'] ) || ! is_array( $api_params['body'] ) ) {
			return [
				'status'       => 'fail',
				'errorMessage' => __( 'Invalid Anthropic parameters received.', 'wordai-pro' ),
				'errorType'    => 'anthropic_params_error',
			];
		}

		return self::send_messages_request( $api_params['body'], (bool) $stream, 'raw' );
	}

	public static function create_chat_reply(
		$user_prompt,
		$model,
		$temperature,
		$system_message = '',
		$stream = false,
		$assistant_context = ''
	) {
		self::ensure_api_key();

		if ( empty( self::$API_KEY ) ) {
			return [
				'status' => 'error',
				'reply'  => __( 'Valid Anthropic API key required.', 'wordai-pro' ),
			];
		}

		$user_prompt = trim( (string) $user_prompt );
		if ( $user_prompt === '' ) {
			return [
				'status' => 'error',
				'reply'  => __( 'Empty message.', 'wordai-pro' ),
			];
		}

		$messages = [];

		if ( $assistant_context !== '' ) {
			$messages[] = [
				'role'    => 'assistant',
				'content' => [
					[
						'type' => 'text',
						'text' => "Website context:\n" . trim( (string) $assistant_context ),
					],
				],
			];
		}

		$messages[] = [
			'role'    => 'user',
			'content' => [
				[
					'type' => 'text',
					'text' => $user_prompt,
				],
			],
		];

		$model = self::normalize_anthropic_model_slug( $model ?: self::$MODEL );

		$body = [
			'model'       => $model,
			'max_tokens'  => 2048,
			'temperature' => max( 0.0, min( 1.0, floatval( $temperature ) ) ),
			'messages'    => $messages,
		];

		if ( $system_message !== '' ) {
			$body['system'] = trim( (string) $system_message );
		}

		$body = self::normalize_sampling_params( $body );

		if ( $stream ) {
			self::send_messages_request( $body, true, 'sse' );
			exit;
		}

		$response = self::send_messages_request( $body, false, 'raw' );

		if ( ! is_array( $response ) || ( $response['status'] ?? '' ) !== 'success' ) {
			return [
				'status' => 'error',
				'reply'  => $response['errorMessage'] ?? __( 'Anthropic request failed.', 'wordai-pro' ),
			];
		}

		return [
			'status' => 'success',
			'reply'  => $response['responseText'] ?? '',
			'model'  => $body['model'],
		];
	}
}

endif;
