<?php
/**
 * Provides helper functions related to language detection.
 *
 * @package Ilabs\Firevert\Core\Services\Helper\Integration
 */

declare( strict_types=1 );

namespace Ilabs\Firevert\Core\Services\Helper\Integration;

use Ilabs\Firevert\Core\Integration\Language\LanguageProviderInterface;
use Ilabs\Firevert\Core\Integration\Language\PolylangLanguageProvider;
use Ilabs\Firevert\Core\Integration\Language\WpmlLanguageProvider;

/**
 * Class LanguageHelper
 *
 * Detects the active language code from query param, WPML or Polylang.
 */
class LanguageHelper {

	/**
	 * Cached language provider instance.
	 *
	 * @var LanguageProviderInterface|null
	 */
	private static ?LanguageProviderInterface $provider = null;

	/**
	 * Gets the appropriate language provider based on active plugins.
	 *
	 * @return LanguageProviderInterface|null Language provider or null if none is active.
	 * @since 1.0.0
	 */
	private static function get_provider(): ?LanguageProviderInterface {
		if ( null !== self::$provider ) {
			return self::$provider;
		}

		$wpml = new WpmlLanguageProvider();
		$pll  = new PolylangLanguageProvider();

		if ( $wpml->is_active() ) {
			self::$provider = $wpml;

			return $wpml;
		}

		if ( $pll->is_active() ) {
			self::$provider = $pll;

			return $pll;
		}

		return null;
	}

	/**
	 * Checks if WPML is active.
	 *
	 * @return bool True if WPML is active.
	 * @since 1.0.0
	 */
	public static function is_wpml_active(): bool {
		$provider = self::get_provider();

		return $provider instanceof WpmlLanguageProvider && $provider->is_active();
	}

	/**
	 * Checks if Polylang is active.
	 *
	 * @return bool True if Polylang is active.
	 * @since 1.0.0
	 */
	public static function is_polylang_active(): bool {
		$provider = self::get_provider();

		return $provider instanceof PolylangLanguageProvider && $provider->is_active();
	}

	/**
	 * Checks if any translation plugin is active.
	 *
	 * @return bool True if either WPML or Polylang is active.
	 * @since 1.0.0
	 */
	public static function is_translation_system_active(): bool {
		return null !== self::get_provider();
	}

	/**
	 * Returns the current active language code, e.g. 'en_EN', 'pl_PL', etc.
	 *
	 * Priority: ?lang=xx > WPML > Polylang > null
	 *
	 * @return string|null Language code or null if unavailable.
	 * @since 1.0.0
	 */
	public static function get_active_region_code(): ?string {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$get_lang = sanitize_key( wp_unslash( $_GET['lang'] ?? '' ) );

		if ( '' !== $get_lang ) {
			$map = self::get_locale_map();
			if ( isset( $map[ $get_lang ] ) ) {
				return $map[ $get_lang ];
			}
			if ( preg_match( '/^[a-z]{2}(_[A-Z]{2})?$/', $get_lang ) ) {
				return $get_lang;
			}
		}

		$provider = self::get_provider();

		return $provider ? $provider->get_current_locale() : null;
	}

	/**
	 * Returns list of available language locale codes, e.g. ['pl_PL', 'en_GB'].
	 *
	 * Only if translation system is active.
	 *
	 * @return string[] Array of locale codes or empty if none.
	 * @since 1.0.0
	 */
	public static function get_available_languages(): array {
		$provider = self::get_provider();

		return $provider ? $provider->get_available_locales() : array();
	}

	/**
	 * Returns current language code (e.g. 'pl', 'en') only if WPML or Polylang is active.
	 *
	 * @return string|null Two-letter language code or null if no system is active.
	 * @since 1.0.0
	 */
	public static function get_current_simple_code(): ?string {
		$provider = self::get_provider();

		return $provider ? $provider->get_current_slug() : null;
	}

	/**
	 * Returns default language code in full format (e.g. 'pl_PL') if WPML or Polylang is active.
	 *
	 * @return string|null Default locale code or null if unavailable.
	 * @since 1.0.0
	 */
	public static function get_default_region_code(): ?string {
		$provider = self::get_provider();
		if ( ! $provider ) {
			return null;
		}

		$default_slug = $provider->get_default_slug();
		if ( ! $default_slug ) {
			return null;
		}

		$map = $provider->get_slug_to_locale_map();

		return $map[ $default_slug ] ?? null;
	}

	/**
	 * Returns all language slugs, e.g. ['pl', 'en'], if translation system is active.
	 *
	 * @return string[] Array of language slugs or empty array.
	 * @since 1.0.0
	 */
	public static function get_available_language_slugs(): array {
		$provider = self::get_provider();

		return $provider ? $provider->get_available_slugs() : array();
	}

	/**
	 * Returns a map of language slugs to locales, e.g. ['pl' => 'pl_PL'].
	 *
	 * @return array<string, string> Language slug => locale.
	 * @since 1.0.0
	 */
	public static function get_locale_map(): array {
		$provider = self::get_provider();

		return $provider ? $provider->get_slug_to_locale_map() : array();
	}
}
