<?php
namespace TeknoTok\AiTranslator\Frontend;

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

/**
 * Controller to manage dynamic permalinks and subfolder rewrite rules.
 */
class UrlManager {
	/**
	 * Constructor. Registers hooks.
	 */
	public function __construct() {
		add_filter( 'rewrite_rules_array', array( $this, 'filter_rewrite_rules' ) );

		add_action( 'update_option_show_on_front', 'flush_rewrite_rules' );
		add_action( 'update_option_page_on_front', 'flush_rewrite_rules' );

		if ( ! is_admin() ) {
			add_filter( 'post_link', array( $this, 'prefix_permalink' ), 10, 2 );
			add_filter( 'page_link', array( $this, 'prefix_permalink' ), 10, 2 );
			add_filter( 'post_type_link', array( $this, 'prefix_permalink' ), 10, 2 );
			add_filter( 'term_link', array( $this, 'prefix_term_permalink' ), 10, 3 );
			add_filter( 'home_url', array( $this, 'prefix_home_url' ), 10, 4 );
		}
	}

	/**
	 * Retrieve the configured URL mode with a safe fallback.
	 *
	 * @param array $settings Plugin settings.
	 * @return string URL mode.
	 */
	private static function get_url_mode( $settings ) {
		$url_mode = isset( $settings['url_mode'] ) ? sanitize_key( $settings['url_mode'] ) : 'subfolder';
		return in_array( $url_mode, array( 'subfolder', 'query' ), true ) ? $url_mode : 'subfolder';
	}

	/**
	 * Filter rewrite rules to add language prefix rules.
	 *
	 * @param array $rules Existing rewrite rules.
	 * @return array Filtered rewrite rules.
	 */
	public function filter_rewrite_rules( $rules ) {
		$settings = get_option( 'teknotok_ait_settings', array() );
		$url_mode = self::get_url_mode( $settings );

		if ( 'subfolder' !== $url_mode ) {
			return $rules;
		}

		$targets = $settings['target_languages'] ?? array();
		if ( empty( $targets ) ) {
			return $rules;
		}

		$languages_regex = implode( '|', array_map( 'preg_quote', $targets ) );
		$new_rules = array();

		// Add home page rule for languages (respect static front page settings)
		$page_on_front = get_option( 'page_on_front' );
		if ( 'page' === get_option( 'show_on_front' ) && $page_on_front ) {
			$new_rules['^(' . $languages_regex . ')/?$'] = 'index.php?page_id=' . intval( $page_on_front ) . '&lang=$matches[1]';
		} else {
			$new_rules['^(' . $languages_regex . ')/?$'] = 'index.php?lang=$matches[1]';
		}

		foreach ( $rules as $regex => $redirect ) {
			// Prefix the regex with the language code capture group
			$new_regex = '^(' . $languages_regex . ')/' . ltrim( $regex, '^' );

			// Shift all matches in the redirect string because we added a new capture group at the beginning
			$new_redirect = preg_replace_callback(
				'/([\$\b]matches\[)([0-9]+)(\])/i',
				function( $match ) {
					return $match[1] . ( (int) $match[2] + 1 ) . $match[3];
				},
				$redirect
			);

			// Append the lang query parameter
			if ( strpos( $new_redirect, '?' ) !== false ) {
				$new_redirect .= '&lang=$matches[1]';
			} else {
				$new_redirect .= '?lang=$matches[1]';
			}

			$new_rules[ $new_regex ] = $new_redirect;
		}

		// Merge new rules on top so they are evaluated first
		return $new_rules + $rules;
	}

	/**
	 * Helper to recursively clean any language prefix from a relative path.
	 *
	 * @param string $path    Relative path.
	 * @param array  $targets List of target languages.
	 * @return string Cleaned relative path.
	 */
	public static function clean_path_from_language_prefix( $path, $targets ) {
		$path = ltrim( $path, '/' );
		if ( empty( $targets ) ) {
			return $path;
		}
		$languages_regex = implode( '|', array_map( 'preg_quote', $targets ) );
		while ( preg_match( '#^(' . $languages_regex . ')(/|$)#i', $path ) ) {
			$path = preg_replace( '#^(' . $languages_regex . ')(/|$)#i', '', $path );
			$path = ltrim( $path, '/' );
		}
		return $path;
	}

	/**
	 * Internal helper to prefix any local URL with the active language code.
	 *
	 * @param string $url         Original URL.
	 * @param string $active_lang Active language code.
	 * @param array  $settings    Plugin settings.
	 * @return string Prefixed URL.
	 */
	private function prefix_url( $url, $active_lang, $settings ) {
		$source = $settings['source_language'] ?? 'en';
		$targets = $settings['target_languages'] ?? array();
		$url_mode = self::get_url_mode( $settings );

		if ( $active_lang === $source ) {
			return $url;
		}

		if ( 'subfolder' === $url_mode ) {
			// Use the raw home option (unfiltered) to prevent prefix nesting loops
			$home = rtrim( get_option( 'home' ), '/' );

			// Adjust scheme if the request is HTTPS
			$is_https = is_ssl() || ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) );
			if ( $is_https ) {
				$home = str_replace( 'http://', 'https://', $home );
				$url  = str_replace( 'http://', 'https://', $url );
			}

			if ( 0 === strpos( $url, $home ) ) {
				$path = substr( $url, strlen( $home ) );
				$path = self::clean_path_from_language_prefix( $path, $targets );
				return $home . '/' . $active_lang . '/' . $path;
			}
		} else {
			return add_query_arg( 'lang', $active_lang, $url );
		}

		return $url;
	}

	/**
	 * Overwrite permalinks dynamically for posts, pages, and custom post types.
	 *
	 * @param string $url  Original URL.
	 * @param object $post Post object.
	 * @return string Modified URL.
	 */
	public function prefix_permalink( $url, $post ) {
		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$settings = get_option( 'teknotok_ait_settings', array() );
		return $this->prefix_url( $url, $active_lang, $settings );
	}

	/**
	 * Overwrite taxonomy term links.
	 *
	 * @param string $url      Original link.
	 * @param object $term     Term object.
	 * @param string $taxonomy Taxonomy name.
	 * @return string Modified link.
	 */
	public function prefix_term_permalink( $url, $term, $taxonomy ) {
		$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
		$settings = get_option( 'teknotok_ait_settings', array() );
		return $this->prefix_url( $url, $active_lang, $settings );
	}

	/**
	 * Prefix home URL checks.
	 *
	 * @param string      $url
	 * @param string      $path
	 * @param string|null $scheme
	 * @param int|null    $blog_id
	 * @return string
	 */
	public function prefix_home_url( $url, $path, $scheme, $blog_id ) {
		if ( empty( $path ) || '/' === $path ) {
			$active_lang = \TeknoTok\AiTranslator\Plugin::get_active_language();
			$settings = get_option( 'teknotok_ait_settings', array() );
			return $this->prefix_url( $url, $active_lang, $settings );
		}

		return $url;
	}

	/**
	 * Get the URL of the current request for a specific language.
	 *
	 * @param string $lang Target language code.
	 * @return string Target URL.
	 */
	public static function get_clean_url_for_language( $lang ) {
		$settings = get_option( 'teknotok_ait_settings', array() );
		$source = $settings['source_language'] ?? 'en';
		$targets = $settings['target_languages'] ?? array();
		$url_mode = self::get_url_mode( $settings );

		// Get current request URI path relative to home
		global $wp;
		$path = isset( $wp->request ) ? $wp->request : '';

		// Get other query parameters (excluding 'lang')
		$query_params = $_GET;
		unset( $query_params['lang'] );

		// Use the raw home option (unfiltered) to prevent prefix nesting loops
		$home = rtrim( get_option( 'home' ), '/' );

		// Adjust scheme if the request is HTTPS
		$is_https = is_ssl() || ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === strtolower( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) );
		if ( $is_https ) {
			$home = str_replace( 'http://', 'https://', $home );
		}

		// Clean the path from any existing language prefixes
		$path = self::clean_path_from_language_prefix( $path, $targets );

		if ( 'subfolder' === $url_mode ) {
			if ( $lang === $source ) {
				$url = $home . '/' . $path;
			} else {
				$url = $home . '/' . $lang . '/' . $path;
			}
		} else {
			$url = $home . '/' . $path;
			if ( $lang !== $source ) {
				$query_params['lang'] = $lang;
			}
		}

		if ( ! empty( $query_params ) ) {
			$url = add_query_arg( $query_params, $url );
		}

		return esc_url( $url );
	}
}
