<?php
declare( strict_types=1 );

namespace FiboFilters\Integrations;

use FiboFilters\Config\Menu;
use FiboFilters\Filters\StoreFilters;
use FiboFilters\Integrations\Multilingual\Polylang;
use FiboFilters\Integrations\Multilingual\ProviderInterface;
use FiboFilters\Integrations\Multilingual\TranslatePress;
use FiboFilters\Integrations\Multilingual\WPML;
use FiboFilters\Util\Helpers;

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

/**
 * Class Multilingual
 */
class Multilingual {
	/** @var bool|null */
	private $is_multilingual;

	/** @var string */
	private $previous_language = '';

	/** @var ProviderInterface */
	private $provider = null;

	/** @var Polylang */
	private $polylang;

	/** @var StoreFilters */
	private $store_filters;

	/** @var TranslatePress */
	private $translatepress;

	/** @var WPML */
	private $wpml;

	public function __construct( Polylang $polylang, StoreFilters $store_filters, TranslatePress $translatepress, WPML $wpml ) {
		$this->polylang       = $polylang;
		$this->translatepress = $translatepress;
		$this->store_filters  = $store_filters;
		$this->wpml           = $wpml;
	}

	public function init(): void {
		$this->maybe_set_provider();

		if ( $this->get_provider_name() === 'not set' ) {
			return;
		}

		$this->provider->init();

		if ( $this->get_provider_name() === 'WPML' ) {
			add_action( 'fibofilters/storage/update/filters', [ $this->provider, 'register_strings_for_translation' ], 10, 0 );
		}
		if ( $this->get_provider_name() === 'Polylang' ) {
			// Polylang requires that strings to be translated be registered in one of the Dashboard actions.
			add_action( 'admin_init', [ $this->provider, 'register_strings_for_translation' ], 10, 0 );
		}

		if ( ! Menu::is_on_settings_admin_page() ) {
			$this->provider->perform_frontend_actions();
		}
	}

	private function maybe_set_provider(): void {
		if ( $this->wpml->is_active() ) {
			$this->provider = $this->wpml;
		} elseif ( $this->polylang->is_active() ) {
			$this->provider = $this->polylang;
		}
		// For now, only WPML and Polylang is supported.
		// } elseif ( $this->translatepress->is_active() ) {
		// $this->provider = $this->translatepress;
		// }
	}

	/**
	 * Check if the website is multilingual
	 *
	 * @return bool
	 */
	public function is_multilingual(): bool {
		if ( is_bool( $this->is_multilingual ) ) {
			return $this->is_multilingual;
		}

		if ( defined( 'FIBOFILTERS_DISABLE_MULTILINGUAL' ) && FIBOFILTERS_DISABLE_MULTILINGUAL ) {
			$this->is_multilingual = false;

			return $this->is_multilingual;
		}

		if ( $this->get_provider_name() !== 'not set' && count( $this->get_languages() ) > 0 ) {
			$this->is_multilingual = true;
		}

		return (bool) $this->is_multilingual;
	}

	/**
	 * Get provider name
	 *
	 * @return string
	 */
	public function get_provider_name(): string {
		$provider_name = 'not set';

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$provider_name = $this->provider->get_name();
		}

		return (string) apply_filters( 'fibofilters/multilingual/provider_name', $provider_name );
	}

	/**
	 * Get default language
	 *
	 * @return string
	 */
	public function get_default_language(): string {
		$default_language = 'en';

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$default_language = $this->provider->get_default_language();
		}

		if ( empty( $default_language ) ) {
			$locale           = get_locale();
			$default_language = substr( $locale, 0, 2 );
		}

		return apply_filters( 'fibofilters/multilingual/default_language', $default_language );
	}

	/**
	 * Get current language
	 *
	 * @return string
	 */
	public function get_current_language(): string {
		$current_language = $this->get_default_language();

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$current_language = $this->provider->get_current_language();
		}

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( empty( $current_language ) && ! empty( $_GET['lang'] ) && Helpers::is_language_code( $_GET['lang'] ) ) {
			$current_language = strtolower( $_GET['lang'] );
		} // phpcs:enable WordPress.Security.NonceVerification.Recommended

		return apply_filters( 'fibofilters/multilingual/current_language', $current_language );
	}

	/**
	 * Get Language of post or product
	 *
	 * @param int    $post_id Post ID.
	 * @param string $post_type Post type.
	 *
	 * @return string
	 */
	public function get_post_language( int $post_id, string $post_type = 'product' ): string {
		$language = $this->get_default_language();

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_post_language( $post_id, $post_type );
			if ( ! empty( $result ) ) {
				$language = $result;
			}
		}

		return apply_filters( 'fibofilters/multilingual/post_language', $language, $post_id, $post_type );
	}

	/**
	 * Get term language
	 *
	 * @param int    $term_id Term ID.
	 * @param string $taxonomy Taxonomy slug.
	 *
	 * @return string
	 */
	public function get_term_language( int $term_id, string $taxonomy ): string {
		$language = $this->get_default_language();

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_term_language( $term_id, $taxonomy );
			if ( ! empty( $result ) ) {
				$language = $result;
			}
		}

		// TranslatePress/qTranslate-XT has no language relationship with the post, so we always return the default.
		return apply_filters( 'fibofilters/multilingual/term_language', $language, $term_id, $taxonomy );
	}

	/**
	 * Get permalink
	 *
	 * @param string $post_id Post ID.
	 * @param string $permalink URL.
	 * @param string $language Language code.
	 *
	 * @return string
	 */
	public function get_permalink( string $post_id, string $permalink = '', string $language = '' ): string {
		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_permalink( $post_id, $permalink, $language, $this->get_default_language() );
			if ( ! empty( $result ) ) {
				$permalink = $result;
			}
		}

		return apply_filters( 'fibofilters/multilingual/post_permalink', $permalink, $language, $post_id );
	}

	/**
	 * Get active languages
	 *
	 * @param bool $include_invalid Also return invalid languages.
	 */
	public function get_languages( bool $include_invalid = false ): array {
		$languages = [];

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_languages( $include_invalid );
			if ( ! empty( $result ) ) {
				$languages = $result;
			}
		}

		if ( empty( $languages ) ) {
			$languages[] = $this->get_default_language();
		}

		return apply_filters( 'fibofilters/multilingual/languages', $languages, $include_invalid );
	}

	/**
	 * Check if language is indexable
	 *
	 * @param string $language Language code.
	 */
	public function is_language_indexable( string $language = '' ): bool {
		return Helpers::is_language_code( $language ) && in_array( $language, $this->get_languages(), true );
	}

	/**
	 * Get all terms in one taxonomy for all languages
	 *
	 * @param string $taxonomy Taxonomy slug.
	 *
	 * @return \WP_Term[]
	 */
	public function get_terms_in_all_languages( string $taxonomy ): array {
		$terms = [];

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_terms_in_all_languages( $taxonomy, $this->get_languages(), $this->get_current_language() );
			if ( ! empty( $result ) ) {
				$terms = $result;
			}
		}

		return apply_filters( 'fibofilters/multilingual/terms_in_all_languages', $terms, $taxonomy );
	}

	/**
	 * Get terms in specific language
	 *
	 * @param array  $args Get terms arguments.
	 * @param string $language Language code.
	 *
	 * @return \WP_Term[]
	 */
	public function get_terms_in_language( array $args = [], string $language = '' ): array {
		$terms = [];

		if ( empty( $language ) ) {
			$language = $this->get_default_language();
		}

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_terms_in_language( $args, $language, $this->get_current_language() );
			if ( ! empty( $result ) ) {
				$terms = $result;
			}
		}

		return apply_filters( 'fibofilters/multilingual/terms_in_language', $terms, $args, $language );
	}

	/**
	 * Get term in specific language
	 *
	 * @param int    $term_id Term ID.
	 * @param string $taxonomy Taxonomy slug.
	 * @param string $language Language code.
	 */
	public function get_term( int $term_id, string $taxonomy, string $language ): ?\WP_Term {
		$term = null;

		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$result = $this->provider->get_term( $term_id, $taxonomy, $language, $this->get_current_language() );
			if ( ! empty( $result ) ) {
				$term = $result;
			}
		}

		return apply_filters( 'fibofilters/multilingual/term', $term, $term_id, $taxonomy, $language );
	}

	/**
	 * Switch language
	 *
	 * @param string $language Language code.
	 */
	public function switch_language( string $language ): void {
		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$this->previous_language = $this->provider->get_current_language();
			$this->provider->switch_language( $language );
		}

		/**
		 * Switch language
		 *
		 * @param string $language Language code.
		 */
		do_action( 'fibofilters/multilingual/switch_language', $language );
	}

	/**
	 * Restore language
	 */
	public function restore_language(): void {
		if ( is_a( $this->provider, 'FiboFilters\Integrations\Multilingual\ProviderInterface' ) ) {
			$this->provider->switch_language( $this->previous_language );
		}
	}
}
