<?php

use WPML\FP\Obj;
use WPML\TM\ATE\Review\PreviewLink;

/**
 * Class WPML_Languages
 *
 * @package wpml-core
 */
class WPML_Languages extends WPML_SP_And_PT_User {

	/** @var  WPML_Term_Translation $term_translation */
	private $term_translation;

	/** @var WPML_Query_Utils $query_utils */
	private $query_utils;

	/**
	 * @param WPML_Term_Translation $term_translation
	 * @param SitePress             $sitepress
	 * @param WPML_Post_Translation $post_translation
	 */
	public function __construct( &$term_translation, &$sitepress, &$post_translation ) {
		parent::__construct( $post_translation, $sitepress );
		$this->term_translation = &$term_translation;
		$this->query_utils      = $sitepress->get_query_utils();
	}

	/**
	 * @param WP_Query $wp_query
	 * @param WP_Query $_wp_query_back
	 * @param WP_Query $saved_query
	 *
	 * @return array<array<string,\stdClass>, \WP_Query>
	 */
	public function get_ls_translations( $wp_query, $_wp_query_back, $saved_query ) {
		list( $taxonomy, $term_id ) = $this->extract_tax_archive_data( $wp_query );
		if ( $taxonomy && $term_id ) {
			if ( $this->sitepress->is_translated_taxonomy( $taxonomy ) ) {
				$icl_taxonomy = 'tax_' . $taxonomy;
				$trid         = $this->term_translation->trid_from_tax_and_id( $term_id, $taxonomy );
				$translations = $this->sitepress->get_element_translations( $trid, $icl_taxonomy, false );
			} elseif ( 'post_format' === $taxonomy ) {
				$translations = $this->get_post_format_translations( $taxonomy, $term_id );
			} else {
				$translations[ $this->sitepress->get_current_language() ] = (object) array(
					'translation_id' => 0,
					'language_code'  => $this->sitepress->get_default_language(),
					'original'       => 1,
					'name'           => $taxonomy,
					'term_id'        => $term_id,
				);
			}
		} elseif ( $wp_query->is_archive() && ! empty( $wp_query->posts ) ) {
			$translations = array();
		} elseif ( $wp_query->is_attachment() ) {
			$trid         = $this->post_translation->get_element_trid( $wp_query->get_queried_object_id() );
			$translations = $this->sitepress->get_element_translations( $trid, 'post_attachment' );
		} elseif ( $wp_query->is_page()
				   || ( 'page' === $this->sitepress->get_wp_api()->get_option( 'show_on_front' )
						&& ( isset( $saved_query->queried_object_id )
							 && $saved_query->queried_object_id == $this->sitepress->get_wp_api()->get_option( 'page_on_front' )
							 || ( isset( $saved_query->queried_object_id )
								  && $saved_query->queried_object_id == $this->sitepress->get_wp_api()->get_option( 'page_for_posts' ) ) ) )
		) {
			$trid         = $this->sitepress->get_element_trid( $wp_query->get_queried_object_id(), 'post_page' );
			$translations = $this->sitepress->get_element_translations( $trid, 'post_page' );
		} elseif ( $wp_query->is_singular() && ! empty( $wp_query->posts )
				   || ( isset( $_wp_query_back->query['name'] ) && isset( $_wp_query_back->query['post_type'] ) )
				   || isset( $_wp_query_back->query['p'] )
		) {
			$pid          = ! empty( $saved_query->post->ID ) ? $saved_query->post->ID : ( ! empty( $saved_query->query['p'] ) ? $saved_query->query['p'] : 0 );
			$trid         = $this->post_translation->get_element_trid( $pid );
			$post_type    = get_post_type( $pid );

			// Check for preview_nonce - it's added to the url of a "Translation Review" page.
			// When the nonce passes we want to skip privilege check for the translations, because also a
			// Subscriber Translator does currently preview a draft post (translation preview) and the related language
			// should appear in the Language Switcher. See wpmlcore-8602 for more details.
			$previewNonce          = Obj::propOr( '', 'preview_nonce', $_GET );
			$previewNonceName      = PreviewLink::getNonceName( (int) Obj::propOr( 0, 'preview_id', $_GET ) );
			$skipPrivilegeChecking = \wp_verify_nonce( $previewNonce, $previewNonceName );

			$translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post_type, false, false, false, false, $skipPrivilegeChecking );
		} else {
			$wp_query->is_singular = false;
			$wp_query->is_archive  = false;
			$wp_query->is_category = false;
			$wp_query->is_404      = true;
			$translations          = null;
		}

		$translations = apply_filters( 'wpml_get_ls_translations', $translations, $wp_query );
		return array( $translations, $wp_query );
	}

	/**
	 * @param array                              $lang
	 * @param array                              $translations
	 * @param bool                               $icl_lso_link_empty
	 * @param bool                               $skip_lang
	 * @param string                             $link_empty_to
	 * @param WPML_LS_Display_As_Translated_Link $display_as_translated_ls_link
	 *
	 * @return array
	 */
	public function add_tax_url_to_ls_lang( $lang, $translations, $icl_lso_link_empty, $skip_lang, $link_empty_to, WPML_LS_Display_As_Translated_Link $display_as_translated_ls_link ) {
		if ( isset( $translations[ $lang['code'] ] ) ) {
			// force  the taxonomy id adjustment to not modify this
			$queried_object = $this->sitepress->get_wp_api()->get_queried_object();
			$taxonomy       = isset( $queried_object->taxonomy ) ? $queried_object->taxonomy : null;

			if ( $taxonomy ) {
				$translated_url = get_term_link( (int) $translations[ $lang['code'] ]->term_id, $taxonomy );

				if ( ! $translated_url instanceof WP_Error ) {
					$lang['translated_url'] = $translated_url;
					$lang['missing']        = 0;

					if ( 'post_format' === $taxonomy ) {
						$lang['translated_url'] = $this->sitepress->convert_url( $lang['translated_url'], $lang['code'] );
					}
				} else {
					$skip_lang = true;
				}
			}
		}

		if ( ! isset( $translations[ $lang['code'] ] ) || ! isset( $taxonomy ) ) {

			$translated_url = $display_as_translated_ls_link->get_url( $translations, $lang['code'] );
			if ( $translated_url ) {
				$lang['translated_url'] = $translated_url;
				$lang['missing']        = 0;
			} else {

				$args = array(
					'skip_lang'        => $skip_lang,
					'link_empty'       => $icl_lso_link_empty,
					'override_missing' => false,
					'link_empty_to'    => $link_empty_to,
				);

				list( $lang, $skip_lang ) = $this->maybe_mark_lang_missing( $lang, $args );
			}
		}

		return array( $lang, $skip_lang );
	}

	/**
	 * @param array          $lang
	 * @param object|WP_User $author_data
	 * @param bool           $icl_lso_link_empty
	 * @param bool           $skip_lang
	 * @param bool           $link_empty_to
	 *
	 * @return array
	 */
	public function add_author_url_to_ls_lang( $lang, $fallback_lang, $author_data, $icl_lso_link_empty, $skip_lang, $link_empty_to ) {
		$post_type = get_query_var( 'post_type' ) ? get_query_var( 'post_type' ) : 'post';
		if ( $this->query_utils->author_query_has_posts( $post_type, $author_data, $lang['code'], $fallback_lang ) ) {
			$lang['translated_url'] = $this->sitepress->convert_url( $this->sitepress->get_wp_api()->get_author_posts_url( $author_data->ID ), $lang['code'] );
			$lang['missing']        = 0;
		} else {

			$args = array(
				'skip_lang'        => $skip_lang,
				'link_empty'       => $icl_lso_link_empty,
				'override_missing' => false,
				'link_empty_to'    => $link_empty_to,
			);

			list( $lang, $skip_lang ) = $this->maybe_mark_lang_missing( $lang, $args );
		}

		return array( $lang, $skip_lang );
	}

	/**
	 * @param array    $lang
	 * @param string   $fallback_lang
	 * @param WP_Query $current_query
	 * @param bool     $icl_lso_link_empty
	 * @param bool     $skip_lang
	 * @param string   $link_empty_to
	 *
	 * @return array
	 */
	public function add_date_or_cpt_url_to_ls_lang( $lang, $fallback_lang, $current_query, $icl_lso_link_empty, $skip_lang, $link_empty_to ) {
		list( $year, $month, $day ) = $this->extract_date_data_from_query( $current_query );
		$query_helper               = new WPML_WP_Query_API( $current_query );
		$post_type                  = ( $_type = $query_helper->get_first_post_type() ) ? $_type : 'post';
		$lang_code                  = $lang['code'];
		$mark_missing               = false;
		$override                   = false;
		if ( $current_query->is_year() && $this->query_utils->archive_query_has_posts(
			$lang_code,
			$fallback_lang,
			$year,
			null,
			null,
			$post_type
		)
		) {
			$date_archive_url = $this->sitepress->get_wp_api()->get_year_link( $year );
		} elseif ( $current_query->is_month() && $this->query_utils->archive_query_has_posts(
			$lang_code,
			$fallback_lang,
			$year,
			$month,
			null,
			$post_type
		)
		) {
			$date_archive_url = $this->sitepress->get_wp_api()->get_month_link( $year, $month );
		} elseif ( $current_query->is_day() && $this->query_utils->archive_query_has_posts( $lang_code, $fallback_lang, $year, $month, $day, $post_type ) ) {
			$date_archive_url = $this->sitepress->get_wp_api()->get_day_link( $year, $month, $day );
		} elseif ( ! empty( $current_query->query_vars['post_type'] ) ) {
			$override     = ! $this->sitepress->is_translated_post_type( $post_type );
			$mark_missing = true;
			if ( ! $override && $this->query_utils->archive_query_has_posts( $lang_code, $fallback_lang, null, null, null, $post_type ) ) {
				$getArchiveLinkWithLanguage = function( $post_type, $lang_code ) {
					$current_language = $this->sitepress->get_current_language();
					$this->sitepress->switch_lang( $lang_code );
					$url = $this->sitepress->convert_url( $this->sitepress->get_wp_api()->get_post_type_archive_link( $post_type ), $lang_code );
					$this->sitepress->switch_lang( $current_language );

					return $url;
				};
				$url                        = $getArchiveLinkWithLanguage( $post_type, $lang_code );
				$lang['translated_url']     = $this->sitepress->adjust_cpt_in_url( $url, $post_type, $lang_code );
				$mark_missing               = false;
			}
		} else {
			$mark_missing = true;
		}

		if ( $mark_missing ) {

			$args = array(
				'skip_lang'        => $skip_lang,
				'link_empty'       => $icl_lso_link_empty,
				'override_missing' => $override,
				'link_empty_to'    => $link_empty_to,
			);

			list( $lang, $skip_lang ) = $this->maybe_mark_lang_missing( $lang, $args );

		} elseif ( isset( $date_archive_url ) ) {
			$lang['translated_url'] = $this->sitepress->convert_url( $date_archive_url, $lang_code );
		}

		return array( $lang, $skip_lang );
	}

	public function get_ls_language( $lang_code, $current_language, $language_array = false ) {
		$ls_language = $language_array
			? $language_array : $this->sitepress->get_language_details( $lang_code );
		$native_name = $this->sitepress->get_display_language_name( $lang_code, $lang_code );
		if ( ! $native_name ) {
			$native_name = $ls_language['english_name'];
		}
		$ls_language['native_name'] = $native_name;
		$translated_name            = $this->sitepress->get_display_language_name( $lang_code, $current_language );
		if ( ! $translated_name ) {
			$translated_name = $ls_language['english_name'];
		}
		$ls_language['translated_name'] = $translated_name;
		if ( isset( $ls_language['translated_url'] ) ) {
			$ls_language['url'] = $ls_language['translated_url'];
			unset( $ls_language['translated_url'] );
		} else {
			$ls_language['url'] = $this->sitepress->language_url( $lang_code, true );
		}

		$flag_url = $this->sitepress->get_flag_url( $lang_code );

		$ls_language['country_flag_url'] = $flag_url;
		$ls_language['active']           = $current_language === $lang_code ? '1' : 0;
		$ls_language['language_code']    = $lang_code;

		unset( $ls_language['display_name'], $ls_language['english_name'] );

		return $ls_language;
	}

	public function sort_ls_languages( $w_active_languages, $template_args ) {
		// sort languages according to parameters
		$order_by = isset( $template_args['orderby'] ) ? $template_args['orderby'] : 'custom';
		$order    = isset( $template_args['order'] ) ? $template_args['order'] : 'asc';

		switch ( $order_by ) {
			case 'id':
				uasort( $w_active_languages, array( $this, 'sort_by_id' ) );
				break;
			case 'code':
				krsort( $w_active_languages );
				break;
			case 'name':
				uasort( $w_active_languages, array( $this, 'sort_by_name' ) );
				break;
			case 'custom':
			default:
				$w_active_languages = $this->sitepress->order_languages( $w_active_languages );
		}

		return $order !== 'asc' ? array_reverse( $w_active_languages, true ) : $w_active_languages;
	}

	/**
	 * @param array $lang
	 * @param array $args with keys below
	 * - `skip_lang`        bool|int
	 * - `link_empty`       bool|int
	 * - `link_empty_to`    string a URL possibly with a {%lang} placeholder (e.g. http://example.tld/{%lang}/notify-no-translation/)
	 * - `override_missing` bool if true language will always be shown ( Example: untranslated CPT archives)
	 *
	 * @return array
	 */
	private function maybe_mark_lang_missing( $lang, $args ) {

		$args = array_merge(
			array(
				'skip_lang'        => 0,
				'link_empty'       => 0,
				'link_empty_to'    => '',
				'override_missing' => false,
			),
			$args
		);

		if ( $args['link_empty'] ) {
			if ( ! empty( $args['link_empty_to'] ) ) {
				$lang['translated_url'] = str_replace(
					'{%lang}',
					$lang['code'],
					$args['link_empty_to']
				);
			} else {
				$lang['translated_url'] = $this->sitepress->language_url( $lang['code'], true );
			}
		} else {
			if ( $this->sitepress->get_current_language() != $lang['code'] ) {
				$args['skip_lang'] = true;
			}
		}
		$lang['missing'] = $args['override_missing'] ? 0 : 1;

		return array( $lang, $args['skip_lang'] );
	}

	/**
	 * @param WP_Query $query
	 *
	 * @return array()
	 */
	private function extract_date_data_from_query( $query ) {
		$year  = ! empty( $query->query_vars['year'] )
			? $query->query_vars['year']
			: ( ! empty( $query->query_vars['m'] )
				? substr( $query->query_vars['m'], 0, 4 ) : null );
		$month = ! empty( $query->query_vars['monthnum'] )
			? $query->query_vars['monthnum']
			: ( ! empty( $query->query_vars['m'] )
				? substr( $query->query_vars['m'], 4, 2 ) : null );
		$day   = ! empty( $query->query_vars['day'] )
			? $query->query_vars['day']
			: ( ! empty( $query->query_vars['m'] )
				? substr( $query->query_vars['m'], 6, 2 ) : null );

		return array( $year, $month, $day );
	}

	/**
	 * @param WP_Query $wp_query
	 *
	 * @return array()
	 */
	private function extract_tax_archive_data( $wp_query ) {
		$taxonomy = false;
		$term_id  = false;
		if ( $wp_query->is_category() ) {
			$taxonomy = 'category';
			$term_id  = $wp_query->get( 'cat' );
		} elseif ( $wp_query->is_tag() ) {
			$taxonomy = 'post_tag';
			$term_id  = $wp_query->get( 'tag_id' );
		} elseif ( $wp_query->is_tax() ) {
			$term     = $wp_query->get_queried_object();
			$taxonomy = $term->taxonomy;
			$term_id  = $term->term_id;
		}

		return array( $taxonomy, $term_id );
	}

	/**
	 * @param string $taxonomy
	 * @param int    $term_id
	 *
	 * @return array
	 */
	private function get_post_format_translations( $taxonomy, $term_id ) {
		$translations = array();

		foreach ( $this->sitepress->get_active_languages() as $code => $active_language ) {
			$translations[ $code ] = (object) array(
				'translation_id' => 0,
				'language_code'  => $code,
				'original'       => 1,
				'name'           => $taxonomy,
				'term_id'        => $term_id,
			);
		}

		return $translations;
	}

	private function sort_by_id( $array_a, $array_b ) {

		return (int) $array_a['id'] > (int) $array_b['id'] ? - 1 : 1;
	}

	private function sort_by_name( $array_a, $array_b ) {

		return $array_a['translated_name'] > $array_b['translated_name'] ? 1 : - 1;
	}
}
