<?php
namespace TeknoTok\AiTranslator\Frontend;

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

use TeknoTok\AiTranslator\Database\MemoryRepository;
use TeknoTok\AiTranslator\Database\JobRepository;

/**
 * Filter manager to translate frontend strings dynamically.
 */
class TranslationFilters {
	/**
	 * Constructor. Registers translation hooks.
	 */
	public function __construct() {
		if ( is_admin() ) {
			return;
		}

		// Always output hreflang tags on frontend requests
		add_action( 'wp_head', array( $this, 'render_hreflang_tags' ) );

		// Only apply translation filters if active language differs from default
		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$settings = get_option( 'teknotok_ait_settings', array() );
		$source_lang = $settings['source_language'] ?? 'en';

		if ( $active_lang !== $source_lang ) {
			add_filter( 'the_title', array( $this, 'translate_title' ), 10, 2 );
			add_filter( 'the_content', array( $this, 'translate_content' ), 1 );
			add_filter( 'the_excerpt', array( $this, 'translate_excerpt' ) );
			add_filter( 'wp_get_nav_menu_items', array( $this, 'translate_menu_items' ) );
			add_filter( 'get_post_metadata', array( $this, 'translate_metadata' ), 10, 4 );
			add_filter( 'gettext', array( $this, 'translate_gettext' ), 10, 3 );
			add_action( 'template_redirect', array( $this, 'start_page_translation_buffer' ) );
			add_filter( 'woocommerce_add_to_cart_fragments', array( $this, 'translate_woocommerce_fragments' ) );
			add_filter( 'woocommerce_update_order_review_fragments', array( $this, 'translate_woocommerce_fragments' ) );
		}
	}

	/**
	 * Translate the page/post title.
	 *
	 * @param string $title   Original title.
	 * @param int    $post_id Post ID.
	 * @return string Translated title.
	 */
	public function translate_title( $title, $post_id = 0 ) {
		if ( empty( $title ) || ! $post_id ) {
			return esc_html( (string) $title );
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$cached = MemoryRepository::get_translation( $title, $active_lang );

		if ( false !== $cached ) {
			return esc_html( $cached );
		}

		// Queue job if not cached
		if ( \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
			JobRepository::add_job( 'post', $post_id, $active_lang );
		}

		return esc_html( (string) $title );
	}

	/**
	 * Translate post content.
	 *
	 * @param string $content Original content.
	 * @return string Translated content.
	 */
	public function translate_content( $content ) {
		if ( empty( $content ) ) {
			return wp_kses_post( (string) $content );
		}

		global $post;
		if ( ! $post ) {
			return wp_kses_post( (string) $content );
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$cached = MemoryRepository::get_translation( $content, $active_lang );

		if ( false !== $cached ) {
			$cached = \TeknoTok\AiTranslator\Utils\HtmlParser::repair_inline_anchor_spacing( $cached, $active_lang );
			$cached = UrlManager::localize_internal_links_in_html( $cached, $active_lang );
			return wp_kses_post( $cached );
		}

		if ( isset( $post->post_content ) && (string) $post->post_content !== (string) $content ) {
			$cached = MemoryRepository::get_translation( (string) $post->post_content, $active_lang );
			if ( false !== $cached ) {
				$cached = \TeknoTok\AiTranslator\Utils\HtmlParser::repair_inline_anchor_spacing( $cached, $active_lang );
				$cached = UrlManager::localize_internal_links_in_html( $cached, $active_lang );
				return wp_kses_post( $cached );
			}
		}

		if ( \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
			JobRepository::add_job( 'post', $post->ID, $active_lang );
		}

		return wp_kses_post( (string) $content );
	}

	/**
	 * Translate post excerpt.
	 *
	 * @param string $excerpt Original excerpt.
	 * @return string Translated excerpt.
	 */
	public function translate_excerpt( $excerpt ) {
		if ( empty( $excerpt ) ) {
			return wp_kses_post( (string) $excerpt );
		}

		global $post;
		if ( ! $post ) {
			return wp_kses_post( (string) $excerpt );
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$cached = MemoryRepository::get_translation( $excerpt, $active_lang );

		if ( false !== $cached ) {
			return wp_kses_post( $cached );
		}

		if ( \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
			JobRepository::add_job( 'post', $post->ID, $active_lang );
		}

		return wp_kses_post( (string) $excerpt );
	}

	/**
	 * Translate navigation menu items.
	 *
	 * @param array $items List of menu items.
	 * @return array Translated menu items.
	 */
	public function translate_menu_items( $items ) {
		if ( empty( $items ) ) {
			return $items;
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();

		foreach ( $items as $item ) {
			$title = $item->title;
			if ( empty( $title ) ) {
				continue;
			}

			$cached = MemoryRepository::get_translation( $title, $active_lang );
			if ( false !== $cached ) {
				$item->title = $cached;
			} else {
				if ( ! $this->is_warmup_request() && 'post_type' === $item->type && \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
					JobRepository::add_job( 'post', $item->object_id, $active_lang );
				}
				if ( ! $this->is_warmup_request() && \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
					JobRepository::add_string_job( $title, $active_lang );
				}
			}
		}

		return $items;
	}

	/**
	 * Intercept metadata lookups (e.g. WooCommerce product descriptions, short descriptions).
	 *
	 * @param mixed  $value     Meta value.
	 * @param int    $object_id Object ID.
	 * @param string $meta_key  Meta key.
	 * @param bool   $single    Single value flag.
	 * @return mixed Translated metadata.
	 */
	public function translate_metadata( $value, $object_id, $meta_key, $single ) {
		$seo_whitelist = array(
			'_yoast_wpseo_title',
			'_yoast_wpseo_metadesc',
			'_metaseo_description',
			'rank_math_title',
			'rank_math_description',
			'rank_math_focus_keyword',
		);

		$is_translatable = false;
		if ( strpos( $meta_key, '_' ) !== 0 ) {
			$is_translatable = true;
		} elseif ( in_array( $meta_key, $seo_whitelist, true ) ) {
			$is_translatable = true;
		}

		if ( ! $is_translatable ) {
			return $value;
		}

		// Prevent infinite recursion loops by temporarily unhooking the filter
		remove_filter( 'get_post_metadata', array( $this, 'translate_metadata' ), 10 );
		$original_meta = get_post_meta( $object_id, $meta_key, $single );
		add_filter( 'get_post_metadata', array( $this, 'translate_metadata' ), 10, 4 );

		if ( empty( $original_meta ) ) {
			return $value;
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$cache_miss = false;

		if ( is_array( $original_meta ) ) {
			// Check if single-level (flat) array. Skip recursive/multidimensional array translation.
			$is_flat = true;
			foreach ( $original_meta as $item ) {
				if ( is_array( $item ) || is_object( $item ) ) {
					$is_flat = false;
					break;
				}
			}

			if ( ! $is_flat ) {
				return $original_meta;
			}

			$translated_meta = array();
			foreach ( $original_meta as $k => $v ) {
				if ( is_string( $v ) && ! empty( trim( $v ) ) && ! is_numeric( $v ) ) {
					$cached = MemoryRepository::get_translation( $v, $active_lang );
					if ( false !== $cached ) {
						$translated_meta[$k] = $cached;
					} else {
						$translated_meta[$k] = $v;
						$cache_miss = true;
					}
				} else {
					$translated_meta[$k] = $v;
				}
			}

			if ( $cache_miss && \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
				JobRepository::add_job( 'post', $object_id, $active_lang );
			}

			return $single ? array( $translated_meta ) : $translated_meta;
		}

		if ( is_string( $original_meta ) ) {
			if ( empty( trim( $original_meta ) ) || is_numeric( $original_meta ) ) {
				return $single ? $original_meta : array( $original_meta );
			}

			$cached = MemoryRepository::get_translation( $original_meta, $active_lang );
			if ( false !== $cached ) {
				return $single ? $cached : array( $cached );
			}

			if ( \TeknoTok\AiTranslator\Plugin::is_ready_for_translations() ) {
				JobRepository::add_job( 'post', $object_id, $active_lang );
			}
			return $single ? $original_meta : array( $original_meta );
		}

		return $value;
	}

	/**
	 * Translate whitelisted theme and plugin strings.
	 *
	 * @param string $translated The translated text.
	 * @param string $text       The original text.
	 * @param string $domain     The textdomain identifier.
	 * @return string Translated string if cached, otherwise original.
	 */
	public function translate_gettext( $translated, $text, $domain ) {
		if ( empty( $text ) ) {
			return $translated;
		}

		if ( 'woocommerce' === $domain && is_string( $translated ) && $translated !== $text ) {
			\TeknoTok\AiTranslator\Utils\HtmlParser::remember_native_translation( $translated );
			return $translated;
		}

		// Avoid calling wp_get_theme() or parsing themes before the init action is ready
		if ( ! did_action( 'init' ) ) {
			$whitelisted_domains = array( 'woocommerce', 'twentytwentyfour' );
		} else {
			static $whitelisted_domains = null;
			if ( null === $whitelisted_domains ) {
				$theme = wp_get_theme();
				$theme_domain = $theme ? $theme->get( 'TextDomain' ) : '';

				$whitelisted_domains = array(
					'woocommerce',
					'twentytwentyfour',
					get_template(),
					get_stylesheet(),
				);

				if ( ! empty( $theme_domain ) ) {
					$whitelisted_domains[] = $theme_domain;
				}
				$whitelisted_domains = array_unique( $whitelisted_domains );
			}
		}

		if ( ! in_array( $domain, $whitelisted_domains, true ) ) {
			return $translated;
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$cached = MemoryRepository::get_translation( $text, $active_lang );

		if ( false !== $cached ) {
			return $cached;
		}

		return $translated;
	}

	/**
	 * Start page template output buffering for translation.
	 *
	 * @return void
	 */
	public function start_page_translation_buffer() {
		if ( wp_doing_ajax() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
			return;
		}

		ob_start( array( $this, 'translate_page_output' ) );
	}

	/**
	 * Callback to parse and translate the entire captured HTML page.
	 *
	 * @param string $buffer Raw page HTML.
	 * @return string Translated HTML.
	 */
	public function translate_page_output( $buffer ) {
		if ( empty( $buffer ) ) {
			return $buffer;
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$settings = get_option( 'teknotok_ait_settings', array() );
		$source_lang = $settings['source_language'] ?? 'en';

		if ( $active_lang === $source_lang ) {
			return $buffer;
		}

		try {
			$buffer = $this->replace_cached_post_body_fields_in_output( $buffer, $active_lang );

			$queue_all_targets   = false;
			$shared_chrome_only = false;

			$is_html = ( false !== stripos( $buffer, '<html' ) );
			if ( $is_html ) {
				$buffer = \TeknoTok\AiTranslator\Utils\HtmlParser::translate_html( $buffer, $source_lang, $active_lang, null, false, true, $queue_all_targets, $shared_chrome_only );
				return UrlManager::localize_internal_links_in_html( $buffer, $active_lang );
			}
		} catch ( \Throwable $e ) {
			\TeknoTok\AiTranslator\Utils\Logger::log( "translate_page_output Error: " . $e->getMessage() . "\n" . $e->getTraceAsString(), 'error' );
			return $buffer;
		}

		return $buffer;
	}

	/**
	 * Replace saved post/product body translations in full-page HTML and embedded JSON payloads.
	 *
	 * @param string $buffer      Raw page HTML.
	 * @param string $active_lang Active target language.
	 * @return string Updated page HTML.
	 */
	private function replace_cached_post_body_fields_in_output( $buffer, $active_lang ) {
		global $post;

		if ( empty( $post ) || empty( $post->ID ) ) {
			return $buffer;
		}

		foreach ( $this->get_post_body_source_fields( $post ) as $source_text ) {
			$buffer = $this->replace_cached_text_variants( $buffer, $source_text, $active_lang );
		}

		return $buffer;
	}

	/**
	 * Get body source fields that queue processing stores in translation memory.
	 *
	 * @param \WP_Post|object $post Post object.
	 * @return array Source field strings.
	 */
	private function get_post_body_source_fields( $post ) {
		$fields = array(
			isset( $post->post_content ) ? (string) $post->post_content : '',
		);

		if ( isset( $post->post_type ) && 'product' === $post->post_type ) {
			$fields[] = isset( $post->post_excerpt ) ? (string) $post->post_excerpt : '';
		}

		return array_filter(
			array_unique( $fields ),
			function( $value ) {
				return is_string( $value ) && '' !== trim( $value );
			}
		);
	}

	/**
	 * Replace plain, JSON-encoded, and attribute-escaped variants of a cached source string.
	 *
	 * @param string $buffer      HTML or JSON-bearing output.
	 * @param string $source_text Source text.
	 * @param string $active_lang Active target language.
	 * @return string Updated output.
	 */
	private function replace_cached_text_variants( $buffer, $source_text, $active_lang ) {
		$cached = MemoryRepository::get_translation( $source_text, $active_lang );
		if ( false === $cached ) {
			return $buffer;
		}

		$cached = \TeknoTok\AiTranslator\Utils\HtmlParser::repair_inline_anchor_spacing( $cached, $active_lang );
		$cached = UrlManager::localize_internal_links_in_html( $cached, $active_lang );
		$pairs  = array(
			$source_text => $cached,
			html_entity_decode( $source_text, ENT_QUOTES, 'UTF-8' ) => html_entity_decode( $cached, ENT_QUOTES, 'UTF-8' ),
			wp_strip_all_tags( html_entity_decode( $source_text, ENT_QUOTES, 'UTF-8' ) ) => wp_strip_all_tags( html_entity_decode( $cached, ENT_QUOTES, 'UTF-8' ) ),
		);

		$source_json = wp_json_encode( $source_text );
		$cached_json = wp_json_encode( $cached );
		if ( is_string( $source_json ) && is_string( $cached_json ) ) {
			$pairs[ $source_json ] = $cached_json;
			$pairs[ esc_attr( $source_json ) ] = esc_attr( $cached_json );
		}

		foreach ( $pairs as $source_variant => $cached_variant ) {
			if ( '' === trim( (string) $source_variant ) ) {
				continue;
			}

			$buffer = str_replace( (string) $source_variant, (string) $cached_variant, $buffer );
		}

		return $buffer;
	}

	/**
	 * Translate WooCommerce AJAX JSON response fragments.
	 *
	 * @param array $fragments WooCommerce fragments array.
	 * @return array Translated fragments array.
	 */
	public function translate_woocommerce_fragments( $fragments ) {
		if ( empty( $fragments ) || ! is_array( $fragments ) ) {
			return $fragments;
		}

		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$settings = get_option( 'teknotok_ait_settings', array() );
		$source_lang = $settings['source_language'] ?? 'en';

		if ( $active_lang === $source_lang ) {
			return $fragments;
		}

		foreach ( $fragments as $selector => $html ) {
			if ( ! empty( $html ) && is_string( $html ) ) {
				$fragments[ $selector ] = \TeknoTok\AiTranslator\Utils\HtmlParser::translate_html( $html, $source_lang, $active_lang, null, false, true );
			}
		}

		return $fragments;
	}

	/**
	 * Check whether the current frontend request is a background warmup render.
	 *
	 * @return bool True for warmup requests.
	 */
	private function is_warmup_request() {
		$warmup_param = isset( $_GET['teknotok_ait_warmup'] ) ? sanitize_key( wp_unslash( $_GET['teknotok_ait_warmup'] ) ) : '';
		$warmup_header = isset( $_SERVER['HTTP_X_TEKNOTOK_WARMUP'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_TEKNOTOK_WARMUP'] ) ) : '';

		return ! empty( $warmup_param ) || ! empty( $warmup_header );
	}

	/**
	 * Output alternate hreflang tags for target languages in the head.
	 *
	 * @return void
	 */
	public function render_hreflang_tags() {
		if ( is_404() || is_search() || is_feed() || is_preview() || wp_doing_ajax() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
			return;
		}

		$settings = get_option( 'teknotok_ait_settings', array() );
		$source = $settings['source_language'] ?? 'en';
		$targets = $settings['target_languages'] ?? array();

		if ( empty( $targets ) ) {
			return;
		}

		$all_langs = array_merge( array( $source ), $targets );
		foreach ( $all_langs as $lang ) {
			$url = \TeknoTok\AiTranslator\Frontend\UrlManager::get_clean_url_for_language( $lang );
			printf(
				'<link rel="alternate" hreflang="%s" href="%s" />' . "\n",
				esc_attr( $lang ),
				esc_url( $url )
			);
		}

		// Output x-default pointing to the source language version
		$default_url = \TeknoTok\AiTranslator\Frontend\UrlManager::get_clean_url_for_language( $source );
		printf(
			'<link rel="alternate" hreflang="x-default" href="%s" />' . "\n",
			esc_url( $default_url )
		);
	}
}
