<?php

namespace WeglotWP\Services;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Weglot\Client\Api\Exception\ApiError;
use Weglot\Client\Api\LanguageEntry;
use WeglotWP\Helpers\Helper_Json_Inline_Weglot;
use WeglotWP\Helpers\Helper_API;


/**
 * @since 2.3.0
 */
class Translate_Service_Weglot {
	/**
	 * @var Parser_Service_Weglot
	 */
	private $parser_services;
	/**
	 * @var string
	 */
	private $current_language;
	/**
	 * @var string
	 */
	private $original_language;
	/**
	 * @var Request_Url_Service_Weglot
	 */
	private $request_url_services;
	/**
	 * @var Language_Service_Weglot
	 */
	private $language_services;
	/**
	 * @var Replace_Url_Service_Weglot
	 */
	private $replace_url_services;
	/**
	 * @var Option_Service_Weglot
	 */
	private $option_services;
	/**
	 * @var Generate_Switcher_Service_Weglot
	 */
	private $generate_switcher_service;


	/**
	 * @since 2.3.0
	 */
	public function __construct() {
		$this->option_services           = weglot_get_service( Option_Service_Weglot::class );
		$this->request_url_services      = weglot_get_service( Request_Url_Service_Weglot::class );
		$this->replace_url_services      = weglot_get_service( Replace_Url_Service_Weglot::class );
		$this->parser_services           = weglot_get_service( Parser_Service_Weglot::class );
		$this->generate_switcher_service = weglot_get_service( Generate_Switcher_Service_Weglot::class );
		$this->language_services         = weglot_get_service( Language_Service_Weglot::class );
	}


	/**
	 * @return void
	 * @since 2.3.0
	 */
	public function weglot_translate() {
		$is_wp_engine = apply_filters( 'weglot_is_wp_engine_hosting', false );

		if ( $is_wp_engine ) {
			add_filter( 'final_output', array( $this, 'weglot_treat_page' ), 999 );
		} else {
			ob_start( array( $this, 'weglot_treat_page' ) );
		}
	}

	/**
	 * @param LanguageEntry $current_language
	 *
	 * @return Translate_Service_Weglot
	 * @since 2.3.0
	 */
	public function set_current_language( $current_language ) {
		$this->current_language = $current_language->getInternalCode();

		return $this;
	}

	/**
	 * @param LanguageEntry $original_language
	 *
	 * @return Translate_Service_Weglot
	 * @since 2.3.0
	 */
	public function set_original_language( $original_language ) {
		$this->original_language = $original_language->getInternalCode();

		return $this;
	}

	/**
	 * @param string $content
	 *
	 * @return string
	 */
	public function get_canonical_url_from_content( $content ) {
		$check_canonical = preg_match( '/<link rel="canonical"(.*?)?href=(\"|\')([^\s\>]+?)(\"|\')/', $content, $matches );

		if ( 1 === $check_canonical ) {
			if ( isset( $matches[3] ) && ! empty( $matches[3] ) ) {
				return $matches[3];
			} else {
				return '';
			}
		} else {
			return '';
		}
	}

	/**
	 * @return boolean
	 */
	public function check_ajax_exclusion_before_treat() { //phpcs:ignore
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX && is_string( wp_get_referer() ) ) {
			if ( ! $this->request_url_services->create_url_object( wp_get_referer() )->getForLanguage( $this->request_url_services->get_current_language(), false ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * @return boolean
	 */
	public function check_404_exclusion_before_treat() { //phpcs:ignore
		if ( http_response_code() == 404 ) {
			$excluded_urls = $this->option_services->get_exclude_urls();
			foreach ( $excluded_urls as $item ) {
				if ( '^/404$' === $item[0] ) {
					return true;
				}
			}

			return false;
		} else {
			return false;
		}
	}

	/**
	 * @param string $content
	 *
	 * @return string
	 * @throws \Exception
	 * @since 2.3.0
	 * @see weglot_init / ob_start
	 */
	public function weglot_treat_page( $content ) {
		if ( ! is_string( $content ) ) {
			return $content;
		}

		$active_translation = apply_filters( 'weglot_active_translation', true );
		if ( empty( $content ) || ! $active_translation ) {
			return $content;
		}
		$this->set_original_language( $this->language_services->get_original_language() );
		$this->set_current_language( $this->request_url_services->get_current_language() ); // Need to reset.

		$content = apply_filters(
			'weglot_modify_original_content',
			$content,
			$this->current_language,
			$this->original_language
		);

		// Choose type translate.
		$type = ( Helper_Json_Inline_Weglot::is_json( $content ) ) ? 'json' : 'html';
		if ( 'json' !== $type ) {
			$type = ( Helper_Json_Inline_Weglot::is_xml( $content ) ) ? 'xml' : 'html';
		}

		$type              = apply_filters( 'weglot_type_treat_page', $type );
		$canonical         = $this->get_canonical_url_from_content( $content );
		$force_request_url = apply_filters( 'weglot_get_current_canonical_url', false );

		$weglot_force_translate_cart = apply_filters( 'weglot_force_translate_cart', false );
		if ( $weglot_force_translate_cart ) {
			$content = $this->force_translate_cart( $content );
		}
		// No need to translate but prepare new dom with button.
		if (
			$this->current_language === $this->original_language
			|| $this->check_404_exclusion_before_treat()
			|| ! $this->request_url_services->get_weglot_url()->getForLanguage( $this->request_url_services->get_current_language(), false )
		) {
			if ( defined( 'DOING_AJAX' ) && DOING_AJAX && is_string( wp_get_referer() ) ) {
				if ( ! $this->request_url_services->create_url_object( wp_get_referer() )->getForLanguage( $this->request_url_services->get_current_language(), false ) ) { //phpcs:ignore
					// do nothing because the ajax referer are not exclude!
				} else {
					return $content;
				}
			} else {
				// if type is xml we render the content without treatment.
				if ( 'xml' === $type || 'json' === $type ) {
					return $content;
				} else {
					//we check if we need to translate some forced child
					$translate_inside_exclusions_blocks = $this->option_services->get_translate_inside_exclusions_blocks();
					if ( 0 < count( $translate_inside_exclusions_blocks ) ) {
						add_filter( 'weglot_parser_whitelist', function ( $whitelist ) {
							$translate_inside_exclusions_blocks = $this->option_services->get_translate_inside_exclusions_blocks();

							return array_merge( $whitelist, $translate_inside_exclusions_blocks );
						} );
						$parser = $this->parser_services->get_parser();
						if ( $force_request_url ) {
							$request_url        = $this->request_url_services->get_current_canonical_url();
							$translated_content = $parser->translate( $content, $this->original_language, $this->current_language, array(), $canonical, $request_url );
						} else {
							$translated_content = $parser->translate( $content, $this->original_language, $this->current_language, array(), $canonical );
						}

						return $this->weglot_render_dom( $translated_content, $canonical );
					} else {
						return $this->weglot_render_dom( $content, $canonical );
					}
				}
			}
		}
		do_action( 'weglot_treat_page_hook', $this->current_language );

		$parser = $this->parser_services->get_parser();

		try {
			switch ( $type ) {
				case 'json':
					$extra_keys = apply_filters( 'weglot_add_json_keys', array() );
					if ( apply_filters( 'weglot_escape_attribute_in_json', false ) ) {
						$content = $this->parser_services->preserve_attributes( $content ); // List attributes you want to escape
					}
					$translated_content = $parser->translate( $content, $this->original_language, $this->current_language, $extra_keys );
					$translated_content = wp_json_encode( $this->replace_url_services->replace_link_in_json( json_decode( $translated_content, true ) ) );
					if ( apply_filters( 'weglot_escape_attribute_in_json', false ) && is_string( $translated_content ) ) {
						$translated_content = $this->parser_services->restore_preserved_attributes( $translated_content );
					}

					return apply_filters( 'weglot_json_treat_page', $translated_content );
				case 'xml':
					$translated_content = $parser->translate( $content, $this->original_language, $this->current_language, array(), $canonical );
					if ( $this->current_language !== $this->original_language ) {
						$translated_content = $this->replace_url_services->replace_link_in_xml( $translated_content );
					}
					$translated_content = apply_filters( 'weglot_html_treat_page', $translated_content );

					return apply_filters( 'weglot_xml_treat_page', $translated_content );
				case 'html':
					$content = $this->add_ai_disclaimer( $content );

					if ( apply_filters( 'weglot_escape_attribute_in_html', false ) ) {
						$content = $this->parser_services->preserve_attributes( $content );
					}

					if ( apply_filters( 'weglot_escape_vue_js', false ) ) {
						// Escape the Vue.js attributes before processing.
						$content = $this->parser_services->escape_vue_attributes( $content );
					}


					$preserve_words_enabled = apply_filters( 'weglot_preserve_words_enabled', false );
					$preserve_words_list    = apply_filters( 'weglot_preserve_words_list', array(), $content );
					if ( $preserve_words_enabled && is_array( $preserve_words_list ) && ! empty( $preserve_words_list ) ) {
						$content = $this->parser_services->preserve_words( $content, $preserve_words_list );
					}

					if ( apply_filters( 'weglot_escape_script_templates', false ) ) {
						$content = $this->parser_services->escape_script_templates( $content );
					}


					if ( $force_request_url ) {
						$request_url        = $this->request_url_services->get_current_canonical_url();
						$translated_content = $parser->translate( $content, $this->original_language, $this->current_language, array(), $canonical, $request_url );
					} else {
						$translated_content = $parser->translate( $content, $this->original_language, $this->current_language, array(), $canonical );
					}


					// Restore script templates
					if ( apply_filters( 'weglot_escape_script_templates', false ) ) {
						$translated_content = $this->parser_services->restore_script_templates( $translated_content );
					}
					if ( $preserve_words_enabled && is_array( $preserve_words_list ) && ! empty( $preserve_words_list ) ) {
						$translated_content = $this->parser_services->restore_words( $translated_content, $preserve_words_list );
					}

					if ( apply_filters( 'weglot_escape_vue_js', false ) ) {
						$translated_content = $this->parser_services->restore_vue_attributes( $translated_content );
					}

					if ( apply_filters( 'weglot_escape_attribute_in_html', false ) ) {
						$translated_content = $this->parser_services->restore_preserved_attributes( $translated_content );
					}

					$translated_content = apply_filters( 'weglot_html_treat_page', $translated_content );
					$translated_content = $this->replace_url_services->proxify_url( $translated_content );
					$translated_content = $this->disable_automated_translation_services( $translated_content );

					return $this->weglot_render_dom( $translated_content, $canonical );
				default:
					$name_filter = sprintf( 'weglot_%s_treat_page', $type );

					// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- hook name is always prefixed with "weglot_"
					return apply_filters( $name_filter, $content, $parser, $this->original_language, $this->current_language );
			}
		} catch ( ApiError $e ) {
			if ( 'json' !== $type ) {
				if ( ! defined( 'DONOTCACHEPAGE' ) ) {
					define( 'DONOTCACHEPAGE', 1 );
				}
				nocache_headers();
				$content .= '<!--Weglot error API : ' . $this->remove_comments( $e->getMessage() ) . '-->';
			}

			return $content;
		} catch ( \Exception $e ) {
			if ( 'json' !== $type ) {
				if ( ! defined( 'DONOTCACHEPAGE' ) ) {
					define( 'DONOTCACHEPAGE', 1 );
				}
				nocache_headers();
				$content .= '<!--Weglot error : ' . $this->remove_comments( $e->getMessage() ) . '-->';
			}

			return $content;
		}
	}


	/**
	 * Remove comments from HTML.
	 *
	 * @param string $html the HTML string.
	 *
	 * @return string
	 * @since 2.3.0
	 */
	private function remove_comments( $html ) {
		return preg_replace( '/<!--(.*)-->/Uis', '', $html );
	}

	/**
	 * Force translate woocommerce cart.
	 *
	 * @param string $content the HTML string.
	 *
	 * @return string
	 * @since 2.3.0
	 */
	private function force_translate_cart( $content ) {
		if ( ! is_string( wp_get_referer() ) ) {
			return $content;
		}
		if ( false !== strpos( wp_get_referer(), '/cart/' ) ) {
			// This is the cart page
			$parser           = $this->parser_services->get_parser();
			$current_language = $this->request_url_services->create_url_object( wp_get_referer() )->getCurrentLanguage();
			if ( $current_language->getInternalCode() != $this->original_language ) {
				$translated_content = $parser->translate( $content, $this->original_language, $current_language->getInternalCode() );
				$translated_content = apply_filters( 'weglot_html_treat_page', $translated_content );

				return $this->weglot_render_dom( $translated_content );
			}
		}

		return $content;
	}

	/**
	 * @param string $dom the HTML string.
	 *
	 * @return string
	 * @since 2.3.0
	 */
	private function add_ai_disclaimer( $dom ) {
		$ai_disclaimer_selector = $this->option_services->get_option_custom_settings( 'ai_disclaimer_selector' );

		if ( ! isset( $ai_disclaimer_selector ) || '' === $ai_disclaimer_selector || ! is_string( $ai_disclaimer_selector ) ) {
			return $dom;
		}

		$disclaimer_text = 'Translated content on this website may be generated using artificial intelligence. Learn more about AI-generated translations';
		$disclaimer_text = apply_filters( 'weglot_ai_disclaimer_text', $disclaimer_text );

		$doc = new \DOMDocument();
		libxml_use_internal_errors( true );

		// Use proper encoding and flags for complete HTML documents
		$success = $doc->loadHTML(
			'<?xml version="1.0" encoding="UTF-8"?>' . $dom,
			LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
		);

		if ( ! $success ) {
			libxml_clear_errors();

			return $dom; // Return original on error
		}

		libxml_clear_errors();

		$xpath       = new \DOMXPath( $doc );
		$xpath_query = $this->css_to_xpath( $ai_disclaimer_selector );

		if ( false === $xpath_query ) {
			return $dom; // Invalid selector
		}

		$elements = $xpath->query( $xpath_query );

		if ( false === $elements || $elements->length === 0 ) {
			return $dom; // Query failed or no elements found
		}

		$target_element = $elements->item( 0 );
		if ( $target_element ) {
			$text_node = $doc->createTextNode( $disclaimer_text );
			$target_element->appendChild( $text_node );
		}

		// Remove XML processing instruction node to prevent it from appearing in output
		for ( $i = $doc->childNodes->length - 1; $i >= 0; $i -- ) {
			$node = $doc->childNodes->item( $i );
			if ( $node && $node->nodeType === XML_PI_NODE ) {
				$doc->removeChild( $node );
			}
		}

		$html = $doc->saveHTML();

		return $html !== false ? $html : $dom;

	}

	/**
	 *
	 * @param string $selector CSS selector.
	 *
	 * @return string|false XPath query or false on invalid selector.
	 */
	private function css_to_xpath( $selector ) {
		$selector = trim( $selector );

		// Validate selector format
		if ( ! preg_match( '/^[#.]?[a-zA-Z0-9_-]+$/', $selector ) ) {
			return false; // Invalid selector
		}

		if ( strpos( $selector, '#' ) === 0 ) {
			$id = substr( $selector, 1 );

			// Regex validation ensures $id contains only [a-zA-Z0-9_-], so no XPath escaping needed
			return "//*[@id='" . $id . "']";
		}

		if ( strpos( $selector, '.' ) === 0 ) {
			$class = substr( $selector, 1 );
			$class = str_replace( "'", "", $class );

			return "//*[contains(concat(' ', normalize-space(@class), ' '), ' " . $class . " ')]";
		}

		$selector = str_replace( "'", "", $selector );

		return "//" . $selector;
	}

	/**
	 * Replace links and add switcher on the final HTML.
	 *
	 * @param string $dom the final translated HTML.
	 * @param string $canonical the canonical link.
	 *
	 * @return string
	 * @since 2.3.0
	 */
	public function weglot_render_dom( $dom, $canonical = '' ) {
		$dom = $this->generate_switcher_service->generate_switcher_from_dom( $dom );

		// We only need this on translated page.
		if ( $this->current_language !== $this->original_language ) {
			$dom = $this->replace_url_services->replace_link_in_dom( $dom );
		}

		// Remove hreflangs if non-canonical page.
		if ( '' !== $canonical ) {
			$canonical   = urldecode( $canonical );
			$current_url = $this->request_url_services->get_weglot_url();
			if ( $current_url->getPath() !== $this->request_url_services->create_url_object( $canonical )->getPath() ) {
				$dom = preg_replace( '/<link rel="alternate" href=(\"|\')([^\s\>]+?)(\"|\') hreflang=(\"|\')([^\s\>]+?)(\"|\')\/>/', '', $dom );
			}

			// update canonical if page excluded page.
			if ( ! $current_url->getForLanguage( $this->request_url_services->get_current_language(), false ) ) {
				$original_language_url = $current_url->getForLanguage( $this->language_services->get_original_language() );
				if ( is_string( $original_language_url ) ) {
					$dom = preg_replace( '/<link rel="canonical"(.*?)?href=(\"|\')([^\s\>]+?)(\"|\')/', '<link rel="canonical" href="' . esc_url( $original_language_url ) . '"', $dom );
				}
			}
		}

		return apply_filters( 'weglot_render_dom', $dom );
	}

	/**
	 * Disable automated translation services adding translate="no" attributes.
	 *
	 * @param string $html the HTML string.
	 *
	 * @return string
	 * @since 2.3.0
	 */
	private function disable_automated_translation_services( $html ) {
		$remove_auto_service_translate = apply_filters( 'weglot_remove_google_translate', true );
		if ( $remove_auto_service_translate ) {
			$pattern     = '/<html(\s*>|\s+)/i';
			$replacement = '<html translate="no"$1';

			return preg_replace( $pattern, $replacement, $html );
		}

		return $html;
	}

	/**
	 * @param string $api_key Weglot API key
	 * @param string $l_from Source language
	 * @param string $l_to Target language
	 * @param string $request_url Request URL
	 * @param string $word Word to translate
	 * @param int $t Text type
	 *
	 * @return string
	 * @since 2.4.0
	 */
	public function reverseTranslate( $api_key, $l_from, $l_to, $request_url, $word, $t ) {

		$requestBody = wp_json_encode( [
			"l_from"      => $l_from,
			"l_to"        => $l_to,
			"request_url" => $request_url,
			"words"       => [
				[ "w" => $word, "t" => $t ]
			]
		] );

		$url = sprintf( '%s/translate?api_key=%s', Helper_API::get_api_url(), $api_key );

		if ( ! is_string( $requestBody ) ) {
			return "Error: Invalid request body";
		}
		$args = [
			'body'        => $requestBody,
			'headers'     => [
				'Content-Type' => 'application/json',
			],
			'method'      => 'POST',
			'data_format' => 'body',
		];

		$response = wp_remote_post( $url, $args );

		if ( is_wp_error( $response ) ) {
			return "WP Error: " . $response->get_error_message();
		}

		$response_body = wp_remote_retrieve_body( $response );

		$responseData = json_decode( $response_body, true );

		if ( ! $responseData || ! isset( $responseData['ids'] ) ) {
			return "Error: Invalid response from API";
		}

		return $responseData['to_words'][0];
	}
}



