<?php

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Custom provider MT engine implementation.
 */
class ETM_Other_Machine_Translator extends ETM_Machine_Translator {

	/**
	 * Send request to Generic MT API
	 *
	 * @param string $source_language       Translate from language.
	 * @param string $target_language       Translate to language.
	 * @param array  $strings_array         Array of string to translate.
	 * @param array  $domain                Translation domain.
	 *
	 * @return array|WP_Error               Response
	 */
	public function send_translation_request( $source_language, $target_language, $strings_array, $domain = null ) {
		$data          = (object) array();
		$data->srcLang = $source_language;
		$data->trgLang = $target_language;
		$data->text    = array_values( $strings_array );

		if ( $domain ) {
			$data->domain = $domain;
		}

		$response = wp_remote_post(
			$this->get_api_url() . '/translate/text',
			array(
				'headers' => array(
					'Content-Type' => 'application/json',
					'accept'       => 'text/plain',
					'X-API-KEY'    => $this->get_api_key(),
					'timeout'      => 45,
				),
				'body'    => json_encode( $data, JSON_UNESCAPED_SLASHES ),
			)
		);

		return $response;
	}

	/**
	 * Returns an array with the API provided translations of the $new_strings array.
	 *
	 * @param array  $new_strings                   array with the strings that need translation. The keys are the node number in the DOM so we need to preserve them.
	 * @param string $target_language_code          language code of the language that we will be translating to.
	 * @param string $source_language_code          language code of the language that we will be translating from.
	 * @return array                                array with the translation strings and the preserved keys or an empty array if something went wrong.
	 */
	public function translate_array( $new_strings, $target_language_code, $source_language_code = null ) {
		if ( $source_language_code === null ) {
			$source_language_code = $this->settings['default-language'];
		}
		if ( empty( $new_strings ) || ! $this->verify_request_parameters( $target_language_code, $source_language_code ) ) {
			return array();
		}

		$source_language = $this->machine_translation_codes[ $source_language_code ];
		$target_language = $this->machine_translation_codes[ $target_language_code ];
		$domain          = $this->settings['translation-languages-domain-parameter'][ $target_language_code ];

		$translated_strings = array();

		/* split our strings that need translation in chunks of maximum 40 strings  */
		$new_strings_chunks = array_chunk( $new_strings, 40, true );
		/* if there are more than 40 strings we make multiple requests */
		foreach ( $new_strings_chunks as $new_strings_chunk ) {
			$i        = 0;
			$response = $this->send_translation_request( $source_language, $target_language, $new_strings_chunk, $domain );

			// this is run only if "Log machine translation queries." is set to Yes.
			$this->machine_translator_logger->log(
				array(
					'strings'     => serialize( $new_strings_chunk ),
					'response'    => serialize( $response ),
					'lang_source' => $source_language,
					'lang_target' => $target_language,
				)
			);

			/* analyze the response */
			if ( is_array( $response ) && ! is_wp_error( $response ) && isset( $response['response'] ) &&
				isset( $response['response']['code'] ) && $response['response']['code'] === 200 ) {

				$this->machine_translator_logger->count_towards_quota( $new_strings_chunk );

				$translation_response = json_decode( $response['body'] );
				$translations         = array_map(
					function( $item ) {
						return stripslashes( $item->translation );
					},
					$translation_response->translations
				);

				foreach ( $new_strings_chunk as $key => $old_string ) {
					if ( isset( $translations[ $i ] ) ) {
						$translated_strings[ $key ] = $translations[ $i ];
					} else {
						$translated_strings[ $key ] = $old_string;
					}
					$i++;
				}

				if ( $this->machine_translator_logger->quota_exceeded() ) {
					break;
				}
			} else {
				error_log( 'Error on translation: ' . print_r( $response, true ) . ' Please check your MT provider API URL and API Key or try again later!' );
			}
		}
		// will have the same indexes as $new_string or it will be an empty array if something went wrong.
		return $translated_strings;
	}

	/**
	 * Send a request to retrieve language directions from the MT provider.
	 *
	 * @return array|WP_Error The response from the MT provider or WP_Error if there's an issue with the request.
	 */
	private function send_lang_direction_request() {
		$response = wp_remote_get(
			$this->get_api_url() . '/translate/language-directions',
			array(
				'headers' => array(
					'Content-Type' => 'application/json',
					'accept'       => 'text/plain',
					'X-API-KEY'    => $this->get_api_key(),
					'timeout'      => 45,
				),
			)
		);
		return $response;
	}

	/**
	 * Send a test request to verify if the functionality is working.
	 *
	 * @return array|WP_Error The response from the MT provider or WP_Error if there's an issue with the request.
	 */
	public function test_request() {
		$response = $this->send_lang_direction_request();
		return array(
			'body'     => wp_remote_retrieve_body( $response ),
			'response' => wp_remote_retrieve_response_code( $response ),
			'error'    => is_wp_error( $response ) ? $response->get_error_message() : null,
			'raw'      => $response,
			'client'   => 'WordPress HTTP API',
		);
	}

	/**
	 * Check if the credentials for the machine translator are set.
	 *
	 * @return bool True if both API URL and API Key are set, false otherwise.
	 */
	public function credentials_set() {
		return ! empty( $this->get_api_url() ) && ! empty( $this->get_api_key() );
	}

	/**
	 * Get the API URL for the machine translator.
	 *
	 * @return string The API URL.
	 */
	public function get_api_url() {
		return isset( $this->settings['etm_machine_translation_settings'], $this->settings['etm_machine_translation_settings']['other-mt-url'] ) ? $this->settings['etm_machine_translation_settings']['other-mt-url'] : '';
	}

	/**
	 * Get the API Key for the machine translator.
	 *
	 * @return string The API Key.
	 */
	public function get_api_key() {
		return isset( $this->settings['etm_machine_translation_settings'], $this->settings['etm_machine_translation_settings']['other-mt-key'] ) ? $this->settings['etm_machine_translation_settings']['other-mt-key'] : '';
	}

	/**
	 * Get the supported languages for translation based on the language directions received from the MT provider.
	 *
	 * @return array An array of supported language codes.
	 */
	public function get_supported_languages() {
		$response             = $this->send_lang_direction_request();
		$source_language_code = $this->settings['default-language'];
		$source_language      = $this->machine_translation_codes[ $source_language_code ];
		$supported_languages  = array();

		if ( is_array( $response ) && ! is_wp_error( $response ) && isset( $response['response'] ) &&
		isset( $response['response']['code'] ) && $response['response']['code'] === 200 ) {
			$decoded_response = json_decode( $response['body'] );
			foreach ( $decoded_response->languageDirections as $direction ) {
				if ( $direction->srcLang === $source_language ) {
					$supported_languages[] = $direction->srcLang;
					$supported_languages[] = $direction->trgLang;
				}
			}
		}
		return array_values( array_unique( $supported_languages ) );
	}

	/**
	 * Get the list of domains supported by the machine translator based on the language directions received.
	 *
	 * @return array An array containing the response status and the list of supported domains.
	 */
	public function get_domain_list() {
		$response    = $this->send_lang_direction_request();
		$http_status = wp_remote_retrieve_response_code( $response );
		$body        = wp_remote_retrieve_body( $response );

		if ( $http_status != 200 ) {
			error_log( "Error retrieving language directions from MT provider: $body [status: $http_status] Please check your MT provider API URL and API Key or try again later!" );
		}

		return array(
			'response' => $http_status,
			'body'     => json_decode( $body ),
		);
	}

	/**
	 * Get the engine-specific language codes based on the provided languages.
	 *
	 * @param array $languages An array of language codes to be translated.
	 * @return array The engine-specific language codes.
	 */
	public function get_engine_specific_language_codes( $languages ) {
		return $this->etm_languages->get_iso_codes( $languages );
	}

	/**
	 * Check the validity of the API key for the custom provider.
	 *
	 * @return array An array containing the result of the API key validity check.
	 *               - 'message': The message describing the status of the API key.
	 *               - 'error': A boolean indicating whether there was an error with the API key.
	 */
	public function check_api_key_validity() {
		$is_error       = false;
		$return_message = '';

		if ( isset( $this->correct_api_key ) && $this->correct_api_key != null ) {
			return $this->correct_api_key;
		}

		if ( ! $this->credentials_set() ) {
			$is_error       = true;
			$return_message = __( 'Please enter your Custom provider Base URL & API key.', 'etranslation-multilingual' );
		} else {
			$response = $this->test_request();
			$code     = $response['response'];
			if ( 200 !== $code ) {
				$is_error           = true;
				$translate_response = etm_othermt_response_codes( $code );
				$return_message     = $translate_response['message'] ? $translate_response['message'] : __( 'Error on Custom provider HTTP request', 'etranslation-multilingual' );

				error_log( 'Error on Custom provider request: ' . print_r( $response, true ) . ' Please check your MT provider API URL and API Key or try again later!' );
			}
		}
		$this->correct_api_key = array(
			'message' => $return_message,
			'error'   => $is_error,
		);
		return $this->correct_api_key;
	}
}
