<?php
/**
 * Class ETM_Check_Invalid_Text
 *
 * Used to exclude problematic strings triggering 'WordPress database error: Could not perform query because it contains invalid data.' from ETM query functions.
 *
 * Divide et impera method used to minimise number of queries needed to detect needle in haystack. Applied for key functions:
 * get_existing_translations, insert_strings and update_strings.
 */
class ETM_Check_Invalid_Text {
	/**
	 * The character set used by the database table.
	 *
	 * @var string $table_charset
	 */
	protected $table_charset;

	/**
	 * Flag indicating if the current query is being checked for invalid data errors.
	 *
	 * @var bool $check_current_query
	 */
	protected $check_current_query;

	/**
	 * Metadata related to columns in the database table.
	 *
	 * @var array $col_meta
	 */
	protected $col_meta;

	/**
	 * Retrieves existing translations without invalid text from the provided dictionary.
	 *
	 * @param array  $dictionary An associative array of translations.
	 * @param string $prepared_query The prepared query string.
	 * @param array  $strings_array An array of strings to be translated.
	 * @param string $language_code The language code for the translations.
	 * @param string $block_type The type of block being processed.
	 * @return array The updated dictionary with translations excluding invalid text entries.
	 */
	public function get_existing_translations_without_invalid_text( $dictionary, $prepared_query, $strings_array, $language_code, $block_type ) {
		if ( $this->is_invalid_data_error() ) {
			$count = count( $strings_array );
			if ( $count <= 1 ) {
				// fake translated so it doesn't get auto translated or updated in DB later
				$entry               = new stdClass();
				$entry->translated   = $strings_array[0];
				$entry->original     = $strings_array[0];
				$entry->status       = '1';
				$entry->invalid_data = true;
				return array( $strings_array[0] => $entry );
			} else {
				$etm       = ETM_eTranslation_Multilingual::get_etm_instance();
				$etm_query = $etm->get_component( 'query' );

				$half = floor( $count / 2 );

				$array1 = $etm_query->get_existing_translations( array_slice( $strings_array, 0, $half ), $language_code, $block_type );
				$array2 = $etm_query->get_existing_translations( array_slice( $strings_array, $half ), $language_code, $block_type );
				return array_merge( $array1, $array2 );
			}
		}
		return $dictionary;
	}

	/**
	 * Inserts translations without invalid text into the database.
	 *
	 * @param array  $new_strings An array of new strings to be translated.
	 * @param string $language_code The language code for the translations.
	 * @param string $block_type The type of block being processed.
	 * @return void
	 */
	public function insert_translations_without_invalid_text( $new_strings, $language_code, $block_type ) {
		if ( $this->is_invalid_data_error() ) {
			$count = count( $new_strings );
			if ( $count <= 1 ) {
				return;
			} else {
				$etm       = ETM_eTranslation_Multilingual::get_etm_instance();
				$etm_query = $etm->get_component( 'query' );

				$half = floor( $count / 2 );

				$etm_query->insert_strings( array_slice( $new_strings, 0, $half ), $language_code, $block_type );
				$etm_query->insert_strings( array_slice( $new_strings, $half ), $language_code, $block_type );
				return;
			}
		}
	}

	/**
	 * Updates translations without invalid text in the database.
	 *
	 * @param array  $update_strings An array of strings to be updated.
	 * @param string $language_code The language code for the translations.
	 * @param string $block_type The type of block being processed.
	 * @return void
	 */
	public function update_translations_without_invalid_text( $update_strings, $language_code, $block_type ) {
		if ( $this->is_invalid_data_error() ) {
			$count = count( $update_strings );
			if ( $count <= 1 ) {
				return;
			} else {
				$etm       = ETM_eTranslation_Multilingual::get_etm_instance();
				$etm_query = $etm->get_component( 'query' );

				$half = floor( $count / 2 );

				$etm_query->update_strings( array_slice( $update_strings, 0, $half ), $language_code, $block_type );
				$etm_query->update_strings( array_slice( $update_strings, $half ), $language_code, $block_type );
				return;
			}
		}
	}

	/**
	 * Checks if there is an invalid data error in the last database query.
	 *
	 * @return bool True if there is an invalid data error, false otherwise.
	 */
	public function is_invalid_data_error() {
		// Using $etm_disable_invalid_data_detection as a sort of apply_filters to turn off this feature.
		// Not using proper WP filter to reduce page load time. This function is executed many times.
		global $wpdb, $etm_disable_invalid_data_detection;
		if ( ! empty( $wpdb->last_error ) && ! isset( $etm_disable_invalid_data_detection ) ) {
            $invalid_data_error = __( 'WordPress database error: Could not perform query because it contains invalid data.' ); /* phpcs:ignore */ /* $domain arg is purposely omitted because we want to identify the exact wpdb last_error message. Only used for comparison reasons, it's not actually displayed. */
			if ( $wpdb->last_error == $invalid_data_error ) {
				return true;
			}
		}
		return false;
	}
}
