<?php
/**
 * Class: Eac_Tools_Util
 *
 * Description: Met à disposition un ensemble de méthodes utiles pour les composants
 *
 * @since 1.0.0
 */

namespace EACCustomWidgets\Core\Utils;

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Elementor\TemplateLibrary\Source_Local;

class Eac_Tools_Util {

	/**
	 * @var $user_meta_field
	 *
	 * Liste des metas acceptés pour les informations Auteur et User
	 */
	private static $user_meta_field = array(
		'locale',
		'syntax_highlighting',
		'avatar',
		'nickname',
		'first_name',
		'last_name',
		'description',
		'rich_editing',
		'role',
		'twitter',
		'facebook',
		'instagram',
		'linkedin',
		'youtube',
		'pinterest',
		'tumblr',
		'flickr',
		'adrs_address',
		'adrs_city',
		'adrs_zipcode',
		'adrs_country',
		'adrs_occupation',
		'adrs_full',
		'show_admin_bar_front',
	);

	/**
	 * @var $filtered_taxonomy
	 *
	 * Exclusion de catégories
	 */
	private static $filtered_taxonomy = array(
		'nav_menu',
		'link_category',
		'post_format',
		Source_Local::TAXONOMY_TYPE_SLUG,
		Source_Local::TAXONOMY_CATEGORY_SLUG,
		'elementor_font_type',
		'yst_prominent_words',
		'product_type',
		'product_shipping_class',
		'product_visibility',
		'action-group',
		'translation_priority',
		'flamingo_contact_tag',
		'flamingo_inbound_channel',
		'sdm_categories',
		'sdm_tags',
		'wpforms_log_type',
		'wp_theme',
		'wp_template_part_area',
		'page_options_category',
	);

	/**
	 * @var $filtered_post_type
	 *
	 * Exclusion de types de post
	 */
	private static $filtered_post_type = array(
		// WP
		'wp_navigation',
		'wp_template_part',
		'wp_global_styles',
		'wp_template',
		'wp_block',
		'wp_font_face',
		'wp_font_family',
		'user_request',
		'attachment',
		'revision',
		'oembed_cache',
		'nav_menu_item',
		// GENERIC PLUGINS
		'ae_global_templates',
		'sdm_downloads',
		'mailpoet_page',
		'custom_css',
		'customize_changeset',
		'custom-css-js',
		// ELEMENTOR
		'elementor_library',
		'e-landing-page',
		// FLAMINGO
		'flamingo_contact',
		'flamingo_inbound',
		'flamingo_outbound',
		// WPFORMS
		'wpforms',
		'wpforms_log',
		// WPCF7
		'wpcf7_contact_form',
		// FORMINATOR
		'forminator_forms',
		'forminator_polls',
		'forminator_quizzes',
		// ACF
		'acf-field-group',
		'acf-field',
		'acf-post-type',
		// EAC Options page
		'eac_options_page',
		// WOOCOMMERCE
		'shop_order',
		'shop_coupon',
		'product_variation',
		'shop_order_placehold',
		'shop_order_refund',
	);

	/**
	 * @var $social_media
	 *
	 * La liste des réseaux sociaux et de leurs icones
	 */
	private static $social_media = array(
		'email'     => array(
			'name'    => 'Email',
			'icon'    => '<i class="fas fa-envelope" aria-hidden="true"></i>',
			'library' => 'fa-solid',
		),
		'phone'       => array(
			'name'    => 'Phone',
			'icon'    => '<i class="fas fa-phone-alt" aria-hidden="true"></i>',
			'library' => 'fa-solid',
		),
		'url'       => array(
			'name'    => 'Website',
			'icon'    => '<i class="fas fa-globe" aria-hidden="true"></i>',
			'library' => 'fa-solid',
		),
		'facebook'  => array(
			'name'    => 'Facebook',
			'icon'    => '<i class="fab fa-facebook-f" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'flickr'    => array(
			'name'    => 'Flickr',
			'icon'    => '<i class="fab fa-flickr" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'github'    => array(
			'name'    => 'Github',
			'icon'    => '<i class="fab fa-github" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'instagram' => array(
			'name'    => 'Instagram',
			'icon'    => '<i class="fab fa-instagram" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'linkedin'  => array(
			'name'    => 'Linkedin',
			'icon'    => '<i class="fab fa-linkedin" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'mastodon'  => array(
			'name'    => 'Mastodon',
			'icon'    => '<i class="fab fa-mastodon" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'pinterest' => array(
			'name'    => 'Pinterest',
			'icon'    => '<i class="fab fa-pinterest" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'quora'     => array(
			'name'    => 'Quora',
			'icon'    => '<i class="fab fa-quora" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'reddit'    => array(
			'name'    => 'Reddit',
			'icon'    => '<i class="fab fa-reddit" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'spotify'   => array(
			'name'    => 'Spotify',
			'icon'    => '<i class="fab fa-spotify" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'telegram'  => array(
			'name'    => 'Telegram',
			'icon'    => '<i class="fab fa-telegram" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'tiktok'    => array(
			'name'    => 'TikTok',
			'icon'    => '<i class="fab fa-tiktok" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'tumblr'    => array(
			'name'    => 'Tumblr',
			'icon'    => '<i class="fab fa-tumblr" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'twitch'    => array(
			'name'    => 'Twitch',
			'icon'    => '<i class="fab fa-twitch" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'whatsapp'  => array(
			'name'    => 'WhatsApp',
			'icon'    => '<i class="fab fa-whatsapp" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'twitter'   => array(
			'name'    => 'X (Twitter)',
			'icon'    => '<i class="fab fa-x-twitter" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
		'youtube'   => array(
			'name'    => 'Youtube',
			'icon'    => '<i class="fab fa-youtube" aria-hidden="true"></i>',
			'library' => 'fa-brands',
		),
	);

	/**
	 * @var $wp_widgets
	 *
	 * La liste des widgets autorisés pour le composant Off-canvas
	 */
	private static $wp_widgets = array(
		'WP_Widget_Search',
		'WP_Widget_Pages',
		'WP_Widget_Calendar',
		'WP_Widget_Archives',
		'WP_Widget_Meta',
		'WP_Widget_Categories',
		'WP_Widget_Recent_Posts',
		'WP_Widget_Recent_Comments',
		'WP_Widget_RSS',
		'WP_Widget_Tag_Cloud',
	);

	/**
	 * @var $instance
	 */
	private static $instance = null;

	/**
	 * Constructeur de la class
	 */
	public function __construct() {
		$this->has_json_enable();
	}

	/**
	 * Garantir une seule instance de la class
	 *
	 * @return Eac_Tools_Util une instance de la class
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * get_widget_list
	 *
	 * @return la liste des widgets standards
	 *
	 * https://gist.github.com/kingkool68/3418186
	 */
	public static function get_widget_list(): array {
		global $wp_widget_factory, $wp_registered_sidebars;
		/** global $wp_registered_widgets; */
		$widgets = self::$wp_widgets;
		$options = array();

		/**
		 * console_log($wp_registered_sidebars);
		 * console_log($wp_registered_widgets['media_image-2']);
		*/
		// Boucle sur les Wigets standards
		foreach ( $wp_widget_factory->widgets as $key => $widget ) {
			if ( in_array( $key, $widgets, true ) ) {
				$options[ $key ] = $widget->name;
			}
		}

		// Boucle sur les sidebars
		$sidebars = get_option( 'sidebars_widgets' );

		// Boucle sur les sidebars actives et non vides
		foreach ( $sidebars as $sidebar_id => $sidebar_widgets ) {
			if ( 'wp_inactive_widgets' !== $sidebar_id && is_array( $sidebar_widgets ) && ! empty( $sidebar_widgets ) ) {
				$sidebar_name                                  = isset( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : 'No name';
				$options[ $sidebar_id . '::' . $sidebar_name ] = 'Sidebar::' . $sidebar_name;

				/**
				foreach ($sidebar_widgets as $widget) {
					$name = $wp_registered_widgets[$widget]['callback'][0]->name;
					$option_name = $wp_registered_widgets[$widget]['callback'][0]->option_name;
					$id_base = $wp_registered_widgets[$widget]['callback'][0]->id_base;
					$key = $wp_registered_widgets[$widget]['params'][0]['number'];

					$widget_data = get_option($option_name);
					$data = $widget_data[$key];
					$title = ! empty($data['title']) ? $data['title'] : 'Empty title';
					//console_log($title."::".$widget."::".$name."::".$option_name."::".$id_base);
					//console_log($wp_registered_widgets[$widget]);
				}
				*/
			}
		}

		// Widget Search premier indice du tableau
		$search  = 'WP_Widget_Search';
		$options = array( $search => $options[ $search ] ) + $options;
		return $options;
	}

	/**
	 * get_menus_location_list
	 *
	 * @return array la liste des localisations des menus
	 */
	public static function get_menus_location_list(): array {
		$options = array( '' => esc_html__( 'Select...', 'eac-components' ) );

		$locations = get_registered_nav_menus();
		$menus     = get_nav_menu_locations();

		foreach ( $locations as $key => $location_name ) {
			if ( isset( $menus[ $key ] ) && (int) $menus[ $key ] > 0 ) {
				$options[ $key ] = $locations[ $key ];
			}
		}
		return $options;
	}

	/**
	 * get_menus_list
	 *
	 * @return array la liste des menus
	 */
	public static function get_menus_list(): array {
		$menus   = wp_get_nav_menus();
		$options = array( '' => esc_html__( 'Select...', 'eac-components' ) );

		foreach ( $menus as $menu ) {
			$options[ $menu->slug ] = $menu->name;
		}
		return $options;
	}

	/**
	 * @access public
	 *
	 * @param $plugin_path string plugin path
	 *
	 * @return boolean
	 */
	public static function is_plugin_installed( string $plugin_path ): bool {
		if ( ! function_exists( 'get_plugins' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}
		$plugins = get_plugins();
		return isset( $plugins[ $plugin_path ] );
	}

	/**
	 * get_all_social_media_name
	 *
	 * @return array la liste des noms des réseaux sociaux
	 */
	public static function get_all_social_media_name(): array {
		$networks = self::$social_media;
		$options  = array();

		foreach ( $networks as $index => $value ) {
			$options[ $index ] = $value['name'];
		}
		return $options;
	}

	/**
	 * get_all_social_media_icon
	 *
	 * @return array la liste des icones des réseaux sociaux
	 */
	public static function get_all_social_media_icon(): array {
		$networks = self::$social_media;
		$options  = array();

		foreach ( $networks as $index => $value ) {
			$options[ $index ] = array(
				'name' => $value['name'],
				'icon' => $value['icon'],
			);
		}
		return $options;
	}

	/**
	 * get_social_media_info
	 *
	 * @param string $media
	 *
	 * @return array|null les données d'un réseaux social
	 */
	public static function get_social_media_info( string $media = '' ): ?array {
		$networks = self::$social_media;
		if ( ! empty( $media ) && array_key_exists( $media, $networks ) ) {
			return array(
				'name'    => $networks[ $media ]['name'],
				'icon'    => $networks[ $media ]['icon'],
				'library' => $networks[ $media ]['library'],
			);
		}
		return null;
	}

	/**
	 * get_supported_user_meta_field
	 *
	 * @return array Liste des metas acceptés pour les données Auteur et User
	 */
	public static function get_supported_user_meta_field(): array {
		$user_fields = self::$user_meta_field;

		/**
		 * Liste des métadonnées supportées pour un auteur/user
		 *
		 * Filtrer/Ajouter métadonnées
		 *
		 * @param array $user_fields Liste des métadonnées
		 */
		$user_fields = apply_filters( 'eac/tools/user_meta_fields', $user_fields );
		return $user_fields;
	}

	/**
	 * get_palettes_color
	 *
	 * @param bool $custom Ajouter les couleurs personnalisées
	 * @param bool $system Ajouter les couleurs système
	 *
	 * @return array la liste de toutes les couleurs personnalisées et système format hexadecimal
	 */
	public static function get_palettes_color( bool $custom = true, bool $system = false ): array {
		$palette = array();
		$kit = \Elementor\Plugin::$instance->kits_manager->get_active_kit_for_frontend();
		$custom_kit_color = $kit->get_settings_for_display( 'custom_colors' );
		$system_kit_color = $kit->get_settings_for_display( 'system_colors' );

		// Les custom_color existent
		if ( $custom_kit_color && is_array( $custom_kit_color ) && $custom ) {
			foreach ( $custom_kit_color as $key => $custom_color ) {
				if ( isset( $custom_color['color'] ) && $key < 10 ) {
					$palette[] = $custom_color['color'];
				}
			}
		}
		// Les system_colors existent
		if ( $system_kit_color && is_array( $system_kit_color ) && $system ) {
			foreach ( $system_kit_color as $system_color ) {
				$palette[] = $system_color['color'];
			}
		}

		return $palette;
	}

	/**
	 * get_post_excerpt
	 *
	 * @param int $post_id ID du post
	 * @param int $excerpt_length Le nombre de mots à extraire
	 *
	 * @return string Lecture du résumé ou du contenu pour un post et réduction au nombre de mots
	 */
	public static function get_post_excerpt( int $post_id, int $excerpt_length ): string {
		$the_post      = get_post( $post_id );
		$the_excerpt   = '';
		$the_post_type = $the_post->post_type;

		if ( 'product' === $the_post_type && function_exists( 'wc_get_product' ) ) {
			$product     = wc_get_product( $post_id );
			$the_excerpt = ! empty( $product->get_description() ) ? $product->get_description() : $product->get_short_description();
			return wp_trim_words( $the_excerpt, $excerpt_length, '...' );
		} elseif ( $the_post ) {
			$the_excerpt = self::get_gutenberg_content( $the_post );
			if ( empty( $the_excerpt ) ) {
				return '[...]';
			}

			// On supprime tous les shortcode du contenu
			$the_excerpt = strip_shortcodes( $the_excerpt );
			return wp_trim_words( $the_excerpt, $excerpt_length, '...' ); // wp_trim_words fait un strip_all_tags en interne
		}

		return '[...]';
	}

	/**
	 * get_gutenberg_content
	 * Extraction du résumé ou du contenu d'un article standard ou Gutenberg
	 *
	 * @param \WP_post $post
	 *
	 * @return string
	 */
	public static function get_gutenberg_content( \WP_post $post ): string {
		$blocks  = parse_blocks( $post->post_content );
		$excerpt = $post->post_excerpt;
		if ( ! empty( $excerpt ) ) {
			return $excerpt;
		}

		// C'est pas une page gutenberg
		if ( 1 === count( $blocks ) && null === $blocks[0]['blockName'] ) {
			return $post->post_content;
		} else {
			$the_excerpt = self::get_block_recursively( $blocks, 'core/paragraph' );
			return is_array( $the_excerpt ) && ! empty( $the_excerpt ) ? implode( ' ', $the_excerpt ) : '';
		}
	}

	/**
	 * get_block_recursively
	 * Extraction du contenu du block_name avec recherche récursive pour les types de block group
	 *
	 * @param array $blocks
	 * @param string $block_name
	 *
	 * @return array
	 */
	public static function get_block_recursively( array $blocks, string $block_name ): array {
		$block_content = array();
		foreach ( $blocks as $block ) {
			if ( isset( $block['blockName'] ) && $block_name === $block['blockName'] ) {
				$block_content[] = $block['innerHTML'];
			} elseif ( is_array( $block['innerBlocks'] ) && ! empty( $block['innerBlocks'] ) ) {
				$block_content = array_merge( $block_content, self::get_block_recursively( $block['innerBlocks'], $block_name ) );
			}
		}
		return $block_content;
	}

	/**
	 * get_thumbnail_sizes
	 *
	 * @return array Format des images
	 */
	public static function get_thumbnail_sizes(): array {
		$options = array();
		$sizes   = get_intermediate_image_sizes();
		foreach ( $sizes as $s ) {
			$options[ $s ] = ucfirst( $s );
		}
		return $options;
	}

	/**
	 * get_post_orderby
	 *
	 * @return array Les options de tri des articles
	 */
	public static function get_post_orderby(): array {
		$options = array(
			'author'         => esc_html__( 'Author', 'eac-components' ),
			'title'          => esc_html__( 'Title', 'eac-components' ),
			'date'           => esc_html__( 'Date', 'eac-components' ),
			'modified'       => esc_html__( 'Last modification', 'eac-components' ),
			'ID'             => esc_html( 'ID' ),
			'comment_count'  => esc_html__( 'Comments count', 'eac-components' ),
			'meta_value_num' => esc_html__( 'Numeric meta value', 'eac-components' ),
		);

		/**
		 * Liste des options de tri
		 *
		 * Filtrer les options de tri
		 *
		 * @param array $options Liste des options de tri
		 */
		$options = apply_filters( 'eac/tools/post_orderby', $options );
		return $options;
	}

	/**
	 * get_all_post_by_id
	 *
	 * @param array $posttype
	 *
	 * @return array Un tableau "index::ID du post" => "Titre du post"
	 */
	public static function get_all_post_by_id( array $posttype = array( 'post' ) ): array {
		$post_list = array();

		$posts = get_posts(
			array(
				'post_type'      => $posttype,
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'orderby'        => 'title',
				'order'          => 'ASC',
			)
		);

		if ( ! empty( $posts ) && ! is_wp_error( $posts ) ) {
			foreach ( $posts as $index => $value ) {
				// Ajoute l'index du tableau pour conserver le tri sur le titre
				$post_list[ $index . '::' . $value->ID ] = $value->post_title;
			}
		}
		return $post_list;
	}

	/**
	 * get_elementor_templates
	 *
	 * @param string $type
	 *
	 * @return array la liste des templates Elementor
	 */
	public static function get_elementor_templates( string $type = 'page' ): array {
		$post_list = array( '' => esc_html__( 'Select...', 'eac-components' ) );

		$data = get_posts(
			array(
				'cache_results'  => false,
				'post_type'      => Source_Local::CPT,
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'orderby'        => 'title',
				'sort_order'     => 'ASC',
				'tax_query'      => array(
					array(
						'taxonomy' => Source_Local::TAXONOMY_TYPE_SLUG,
						'field'    => 'slug',
						'terms'    => $type,
					),
				),
			)
		);

		if ( ! empty( $data ) && ! is_wp_error( $data ) ) {
			foreach ( $data as $key ) {
				$post_list[ $key->ID ] = $key->post_title;
			}
			asort( $post_list, SORT_STRING | SORT_FLAG_CASE );
		}
		return $post_list;
	}

	/**
	 * get_all_elementor_templates
	 *
	 * @return array la liste de tous les templates Elementor
	 */
	public static function get_all_elementor_templates(): array {
		$template_grouped = array(
			array(
				'label'   => esc_html__( 'Default', 'eac-components' ),
				'options' => array( '' => esc_html__( 'None', 'eac-components' ) ),
			),
		);
		$args = array(
			'post_type'      => Source_Local::CPT, // Type de post pour les templates Elementor
			'posts_per_page' => -1, // Récupérer tous les templates
			'post_status'    => 'publish', // Filtrer pour ne récupérer que les templates publiés
		);

		$templates = get_posts( $args );

		if ( ! is_wp_error( $templates ) && ! empty( $templates ) ) {
			foreach ( $templates as $template ) {
				// Récupérer le type de template (par exemple, 'section', 'page', etc.)
				$template_type = get_post_meta( $template->ID, \Elementor\Core\Base\Document::TYPE_META_KEY, true );

				if ( ! $template_type || 'kit' === $template_type ) {
					continue;
				}

				$label_exists = false;
				foreach ( $template_grouped as &$group ) { // Utiliser une référence pour modifier le groupe
					if ( $group['label'] === $template_type ) {
						$label_exists = true;
						// Ajouter l'ID et le titre au tableau des options
						$group['options'][ $template->ID ] = esc_html( $template->post_title );
						break;
					}
				}

				// Si le label n'existe pas, l'ajouter
				if ( ! $label_exists ) {
					$template_grouped[] = array(
						'label' => $template_type,
						'options' => array( $template->ID => esc_html( $template->post_title ) ),
					);
				}
				usort( $template_grouped, function ( $a, $b ) {
					return strcmp( $a['label'], $b['label'] );
				} );
			}
		}
		return $template_grouped;
	}

	/**
	 * get_filter_post_types
	 *
	 * @return array tous les types d'articles publics filtrés
	 */
	public static function get_filter_post_types( array $exclude_post_type = array(), bool $associatif = true ): array {
		$options             = array();
		$filtered_post_types = self::$filtered_post_type;

		/**
		 * Liste des opérateurs de comparaison des meta_query
		 *
		 * Ajouter/Supprimer des types d'articles
		 *
		 * @param array $filtered_post_types Liste des types d'articles
		 */
		$filtered_post_types = apply_filters( 'eac/tools/post_types', $filtered_post_types );
		$filtered_post_types = array_merge( $exclude_post_type, $filtered_post_types );

		$post_types = get_post_types( array( 'public' => true ), 'objects' );

		foreach ( $post_types as $post_type ) {
			if ( is_array( $filtered_post_types ) && ! in_array( $post_type->name, $filtered_post_types, true ) ) {
				if ( $associatif ) {
					$options[ $post_type->name ] = $post_type->labels->singular_name;
				} else {
					$options[] = $post_type->name;
				}
			}
		}
		if ( $associatif ) {
			asort( $options, SORT_STRING | SORT_FLAG_CASE );
		}

		return $options;
	}

	/**
	 * get_all_post_types
	 *
	 * @return array tous les types d'articles publics non filtrés
	 */
	public static function get_all_post_types(): array {
		$options    = array();
		$post_types = get_post_types( array( 'public' => true ), 'objects' );

		foreach ( $post_types as $post_type ) {
			$options[ $post_type->name ] = $post_type->labels->singular_name;
		}
		asort( $options, SORT_STRING | SORT_FLAG_CASE );
		return $options;
	}

	/**
	 * get_all_taxonomies
	 *
	 * @param array $exclude_post_type le name du post type à exclure de la recherche
	 *
	 * @return array un tableau filtré de toutes les taxonomies de WP à l'exclusion du post type
	 */
	public static function get_all_taxonomies( array $exclude_post_type = array() ): array {
		$options       = array();
		$filtered_taxo = self::$filtered_taxonomy;
		$taxonomies    = get_taxonomies( array(), 'objects' );

		foreach ( $taxonomies as $taxonomy ) {
			$exist_post_type = ! empty( $exclude_post_type ) ? ! empty( array_intersect( $exclude_post_type, $taxonomy->object_type ) ) : false;
			if ( ! $exist_post_type && ! in_array( $taxonomy->name, $filtered_taxo, true ) ) {
				$options[ $taxonomy->name ] = $taxonomy->label;
			}
		}
		asort( $options, SORT_STRING | SORT_FLAG_CASE );
		return $options;
	}

	/**
	 * get_categories_by_all_post_types
	 *
	 * @param bool $associatif
	 *
	 * @return array
	 */
	public static function get_categories_by_all_post_types( bool $associatif = false ): array {
		// Récupérer tous les post types
		$post_types = get_post_types( array( 'public' => true ), 'objects' );
		$all_categories = array();

		foreach ( $post_types as $post_type ) {
			// Récupérer les taxonomies du post type
			$taxonomies = get_object_taxonomies( $post_type->name, 'objects' );

			foreach ( $taxonomies as $taxonomy ) {
				// Vérifier s'il s'agit d'une taxonomie de catégorie
				if ( $taxonomy->hierarchical ) {
					$terms = get_terms( array(
						'taxonomy'   => $taxonomy->name,
						'hide_empty' => true,
					) );

					if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
						if ( ! $associatif ) {
							$all_categories[] = $taxonomy->name;
						} else {
							$all_categories[ $taxonomy->name ] = $taxonomy->label;
						}
					}
				}
			}
		}
		return $all_categories;
	}

	/**
	 * get_all_taxonomies_by_name
	 *
	 * @return array un tableau filtré de toutes les taxonomies par leur nom
	 */
	public static function get_all_taxonomies_by_name(): array {
		$options       = array();
		$filtered_taxo = self::$filtered_taxonomy;

		/**
		 * Liste des taxonomies
		 *
		 * Filtre pour ajouter des taxonomies à exclure
		 *
		 * @param array $filtered_taxo Liste des taxonomies
		 */
		$filtered_taxo = apply_filters( 'eac/tools/taxonomies_by_name', $filtered_taxo );

		$taxonomies = get_taxonomies( array(), 'objects' ); // Retourne un objet

		foreach ( $taxonomies as $taxonomy ) {
			if ( is_array( $filtered_taxo ) && ! in_array( $taxonomy->name, $filtered_taxo, true ) ) {
				$options[] = $taxonomy->name;
			}
		}
		return $options;
	}

	/**
	 * get_all_terms
	 *
	 * @param array $exclude_post_type le name du post type à exclure de la recherche
	 *
	 * @return array un tableau filtré de tous les terms de WP à l'exclusion du post type
	 */
	public static function get_all_terms( array $exclude_post_type = array() ): array {
		$all_terms     = array();
		$taxos         = array();
		$taxo_singular = array();
		$filtered_taxo = self::$filtered_taxonomy;

		$taxonomies = get_taxonomies( array(), 'objects' ); // Retourne un tableau d'objets

		// Boucle sur les taxonomies
		foreach ( $taxonomies as $taxonomy ) {
			$exist_post_type = ! empty( $exclude_post_type ) ? ! empty( array_intersect( $exclude_post_type, $taxonomy->object_type ) ) : false;
			if ( ! $exist_post_type && ! in_array( $taxonomy->name, $filtered_taxo, true ) ) {
				$taxos[]                          = $taxonomy->name;
				$taxo_singular[ $taxonomy->name ] = $taxonomy->labels->singular_name;
			}
		}

		// Boucle sur les terms d'une taxonomie
		if ( ! empty( $taxos ) ) {
			foreach ( $taxos as $taxo ) {
				$terms = get_terms(
					array(
						'taxonomy'   => $taxo,
						'hide_empty' => true,
					)
				);

				if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
					foreach ( $terms as $term ) {
						$all_terms[ $taxo . '::' . $term->slug ] = $taxo_singular[ $taxo ] . '::' . $term->name;
					}
				}
			}
		}
		asort( $all_terms, SORT_STRING | SORT_FLAG_CASE );
		return $all_terms;
	}

	/**
	 * get_product_post_types
	 *
	 * @return array un tableau de tous les types de produits WooCommerce
	 */
	public static function get_product_post_types(): array {
		return array(
			'product' => esc_html__( 'Product', 'eac-components' ),
			/**
			'product_variation'    => esc_html__('Variations', 'eac-components'),
			'shop_coupon'          => esc_html__('Codes promo', 'eac-components'),
			'shop_order'           => esc_html__('Commandes', 'eac-components'),
			'shop_order_placehold' => esc_html__('Articles', 'eac-components'),
			'shop_order_refund'    => esc_html__('Remboursements', 'eac-components'),
			*/
		);
	}

	/**
	 * get_product_taxonomies
	 *
	 * @return array un tableau filtré de toutes les taxonomies d'un produit
	 */
	public static function get_product_taxonomies(): array {
		$options = array();

		/** Retourne un tableau d'objet */
		$taxonomies = get_taxonomies( array( 'object_type' => array( 'product' ) ), 'objects' );

		foreach ( $taxonomies as $taxonomy ) {
			$options[ $taxonomy->name ] = $taxonomy->labels->singular_name;
		}
		uasort( $options, function ( $a, $b ) {
			return strcasecmp( $a, $b );
		});
		return $options;
	}

	/**
	 * get_product_terms
	 *
	 * @return array un tableau filtré de tous les terms d'un produit
	 */
	public static function get_product_terms(): array {
		$all_terms     = array();
		$taxos         = array();
		$taxo_singular = array();

		/** Retourne un tableau d'objet */
		$taxonomies = get_taxonomies( array( 'object_type' => array( 'product' ) ), 'objects' );

		/** Boucle sur les taxonomies */
		foreach ( $taxonomies as $taxonomy ) {
			$taxos[]                          = $taxonomy->name;
			$taxo_singular[ $taxonomy->name ] = $taxonomy->labels->singular_name;
		}

		/** Boucle sur les terms d'une taxonomie */
		if ( ! empty( $taxos ) ) {
			foreach ( $taxos as $taxo ) {
				$terms = get_terms(
					array(
						'taxonomy'   => $taxo,
						'hide_empty' => true,
					)
				);

				if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
					foreach ( $terms as $term ) {
						$all_terms[ $taxo . '::' . $term->slug ] = $taxo_singular[ $taxo ] . '::' . $term->name;
					}
				}
			}
		}
		asort( $all_terms, SORT_STRING | SORT_FLAG_CASE );
		return $all_terms;
	}

	/**
	 * get_pages_by_name
	 *
	 * @return array un tableau de toutes les pages avec le titre pour clé
	 */
	public static function get_pages_by_name(): array {
		$select_pages = array( '' => esc_html__( 'Select...', 'eac-components' ) );
		$args         = array(
			'sort_order'  => 'ASC',
			'sort_column' => 'post_title',
		);
		$pages        = get_pages( $args );

		foreach ( $pages as $page ) {
			$select_pages[ $page->post_title ] = ucfirst( $page->post_title );
		}
		return $select_pages;
	}

	/**
	 * get_pages_by_id
	 *
	 * @return array un tableau de toutes les pages avec l'ID pour clé
	 */
	public static function get_pages_by_id(): array {
		$select_pages = array( '' => esc_html__( 'Select...', 'eac-components' ) );
		$args         = array(
			'sort_order'  => 'DESC',
			'sort_column' => 'post_title',
		);
		$pages        = get_pages( $args );

		foreach ( $pages as $page ) {
			$select_pages[ $page->ID ] = ucfirst( $page->post_title );
		}

		return $select_pages;
	}

	/**
	 * wp_get_attachment_data
	 *
	 * @param int $attachment_id
	 * @param string $attachment_size
	 * @param string $filter
	 * @param int $current_id
	 * @param int $count_element
	 *
	 * @return array Les attributs du media et ceux nécessaires au responsiveness
	 */
	public static function wp_get_attachment_data( int $attachment_id, string $attachment_size, string $filter = '', int $current_id = null, int $count_element = 0 ): array {
		$attachment_array = array();
		$attachment       = get_post( $attachment_id );
		$excerpt_len      = 40;

		if ( 0 === $attachment_id || ! $attachment ) {
			return $attachment_array;
		}

		$srcset      = wp_get_attachment_image_srcset( $attachment_id, $attachment_size );
		$srcsize     = wp_get_attachment_image_sizes( $attachment_id, $attachment_size );
		$image_data  = wp_get_attachment_image_src( $attachment_id, $attachment_size );
		$image_url   = wp_get_attachment_image_url( $attachment_id, $attachment_size );
		$width       = $image_data ? $image_data[1] : 300;
		$height      = $image_data ? $image_data[2] : 300;
		$media_url   = '';
		$media_cat   = '';
		$parent_id   = ! empty( $attachment->post_parent ) && 0 !== $attachment->post_parent ? $attachment->post_parent : false;
		$description = ! empty( $attachment->post_content ) ? wp_trim_words( $attachment->post_content, $excerpt_len, '[...]' ) : '';
		$title       = $attachment->post_title;
		$caption     = $attachment->post_excerpt;

		/** Les meilleures ventes de produit, les produits vedettes ou une catégorie */
		if ( in_array( $filter, array( 'selling', 'featured', 'category', 'product', 'recent' ), true ) && ! is_null( $current_id ) ) {
			if ( 'product' === get_post_type( $current_id ) && function_exists( 'wc_get_product' ) ) {
				$product = wc_get_product( $current_id );
				if ( is_a( $product, 'WC_Product' ) ) {
					$media_url   = $product->get_permalink();
					$title       = $product->get_name();
					$description = self::get_post_excerpt( $product->get_id(), $excerpt_len );
					if ( 'selling' === $filter ) {
						$count       = sprintf( '%1$s %2$d', esc_html__( 'Quantity sold', 'eac-components' ), $product->get_total_sales() );
						$description = 0 !== strlen( $description ) ? $count . '|' . $description : $count;
					} elseif ( 'recent' === $filter ) {
						$count       = sprintf( '%1$s %2$d', esc_html__( 'Quantity sold', 'eac-components' ), $count_element );
						$description = 0 !== strlen( $description ) ? $count . '|' . $description : $count;
					}
				}
			}
		} elseif ( taxonomy_exists( 'product_cat' ) && 'categories' === $filter && ! is_null( $current_id ) ) { /** Les catégories des produits et leur nombre */
			$term = get_term( $current_id, 'product_cat' );
			if ( is_a( $term, 'WP_Term' ) ) {
				$media_url   = get_term_link( $term, 'product_cat' );
				$title       = $term->name;
				$count       = sprintf( '%1$d %2$s', $count_element, $title );
				$description = 0 !== strlen( $term->description ) ? $count . '|' . $term->description : $count;
			}
		} elseif ( $parent_id ) {/** Affecte l'URL et la description du parent si le media est attaché à un article, champ 'Uploaded to' renseigné */
			$post_parent = get_post( $parent_id );
			if ( $post_parent ) {
				$media_url = get_permalink( $parent_id );
				if ( 'product' === get_post_type( $post_parent ) && function_exists( 'wc_get_product' ) ) {
					$product = wc_get_product( $parent_id );
					if ( $product && is_a( $product, 'WC_Product' ) ) {
						$media_url  = $product->get_permalink();
					}
				}
				$excerpt     = self::get_post_excerpt( $parent_id, $excerpt_len );
				$description = ! empty( $excerpt ) ? $excerpt : $description;
			}
		} elseif ( ! $parent_id ) {
			$posts = get_posts(
				array(
					'post_type'      => array( 'product', 'post', 'page' ),
					'post_status'    => 'publish',
					'meta_key'       => '_thumbnail_id',
					'meta_value'     => $attachment_id,
					'posts_per_page' => 1,
				)
			);
			if ( ! is_wp_error( $posts ) && is_array( $posts ) && isset( $posts[0]->ID ) ) {
				$post_parent = $posts[0];
				$postid      = $post_parent->ID;
				if ( 'product' === get_post_type( $postid ) && function_exists( 'wc_get_product' ) ) {
					$product = wc_get_product( absint( $postid ) );
					if ( $product && is_a( $product, 'WC_Product' ) ) {
						$media_url  = $product->get_permalink();
					}
				} else {
					$media_url  = get_permalink( $postid );
				}
				$excerpt     = self::get_post_excerpt( $postid, $excerpt_len );
				$description = ! empty( $excerpt ) ? $excerpt : $description;
			}
		}

		/** Both champs supplémentaires sont activés dans les medias */
		if ( \EACCustomWidgets\Core\Eac_Load_Config::is_feature_active( 'extend-fields-medias' ) ) {
			$url       = get_post_meta( $attachment_id, 'eac_media_url', true );
			$media_url = ! empty( $url ) ? $url : $media_url;
			$media_cat = get_post_meta( $attachment_id, 'eac_media_cat', true );
		}

		$alt        = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
		$attach_alt = ! empty( $alt ) ? $alt : $title;
		$attachment_array = array(
			'alt'         => $attach_alt,
			'caption'     => $caption,
			'description' => $description,
			'image_url'   => $image_url,
			'src'         => wp_get_attachment_url( $attachment_id ),
			'title'       => $title,
			'srcset'      => $srcset,
			'srcsize'     => $srcsize,
			'width'       => $width,
			'height'      => $height,
			'style'       => sprintf( 'block-size:auto; inline-size:%dpx;', $width ),
			'media_url'   => $media_url,
			'media_cat'   => $media_cat,
		);

		return $attachment_array;
	}

	/**
	 * get_directory_file_list
	 * 'wp_check_filetype' retourne null si ce n'est pas un type mime de fichier activé (JSON)
	 *
	 * @param string $relative_path Le chemin d'accès aux fichiers de configuration JSON
	 * @param string $ext le nom de l'extension
	 * @param string $type le mime type
	 *
	 * @return array la liste des fichiers d'un répertoire sous forme [url] => filename
	 */
	public static function get_directory_file_list( string $relative_path = 'includes/config', string $ext = '', string $type = '' ): array {
		$path       = EAC_PLUGIN_PATH . $relative_path;
		$dir        = opendir( $path );
		$files_list = array( 'none' => esc_html__( 'None', 'eac-components' ) );

		if ( empty( $ext ) || empty( $type ) ) {
			return $files_list;
		}

		if ( $dir ) {
			while ( false !== ( $file = readdir( $dir ) ) ) { // phpcs:disable Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
				if ( '.' !== $file && '..' !== $file && ! is_dir( $path . '/' . $file ) ) {
					$filetype = wp_check_filetype( basename( $file ), array( $ext => $type ) );
					if ( $filetype['type'] === $type ) {
						$files_list[ EAC_PLUGIN_URL . $relative_path . '/' . basename( $file ) ] = basename( $file );
					}
				}
			}
			closedir( $dir );
		}
		return $files_list;
	}

	/**
	 * has_json_enable
	 * Check si les option EAC 'Upload unfiltered files'
	 * ou 'Enable the option to upload JSON files' du module Role manager Elementor sont activées
	 *
	 * Note: The 'json-upload' capability is managed by the Role Manager as a part of its blacklist restrictions.
	 * In this context, we are negating the user's permission check to use it as a whitelist, allowing uploads.
	 *
	 * @return void
	 */
	private function has_json_enable(): void {
		/**if ( ( isset( $_GET['action'] ) && 'elementor' === $_GET['action'] ) || is_preview() ) { // phpcs:disable WordPress.Security.NonceVerification.Recommended*/
		/**return current_user_can( 'manage_options' ) || ! \Elementor\Plugin::$instance->role_manager->user_can( 'json-upload' );*/
		if ( is_user_logged_in() ) {
			$option = (bool) get_option( 'elementor_unfiltered_files_upload' ) && \Elementor\User::is_current_user_can_upload_json();
			update_option( 'eac_options_upload_json', $option, false );
		}
	}

	/**
	 * is_json_enable
	 *
	 * @return bool
	 */
	public static function is_json_enable(): bool {
		return get_option( 'eac_options_upload_json' );
	}

	/**
	 * compress_html_output
	 * Compression du code HTML
	 *
	 * @param String $buffer
	 *
	 * @return string
	 * @since 2.3.5
	 */
	public static function compress_html_output( string $buffer ): string {
		if ( '' === $buffer ) {
			return $buffer;
		}

		$search = array(
			'/ {2,}/',
			'/<!--.*?-->|\t|(?:\r?\n[ \t]*)+/s',
		);
		$replace = array(
			' ',
			'',
		);
		$buffer = preg_replace( $search, $replace, $buffer );
		return $buffer;
	}

	/**
	 * compress_html_full_output
	 *
	 * @param string $buffer
	 *
	 * @return string
	 */
	public static function compress_html_full_output( string $buffer ): string {
		if ( '' === $buffer ) {
			return $buffer;
		}

		// Préserver <script> et <style>
		$preserve = array();
		$buffer = preg_replace_callback( '#<(script|style)(\b[^>]*)>.*?</\1>#is', function ( $m ) use ( &$preserve ) {
			$k = '###PRESERVE_' . count( $preserve ) . '###';
			$preserve[ $k ] = $m[0];
			return $k;
		}, $buffer );

		// Supprimer tous les commentaires HTML
		$buffer = preg_replace( '/<!--.*?-->/s', '', $buffer );

		// Retours ligne -> espace, supprimer tabulations
		$buffer = str_replace( array( "\r\n", "\n", "\r", "\t" ), ' ', $buffer );

		// Réduire multiples espaces à 1, supprimer espaces entre balises et avant '/>'
		$buffer = preg_replace(
			array(
				'/ {2,}/',   // plusieurs espaces -> 1
				'/>\s+</',   // espaces entre balises -> '><'
				'/\s+\/>/',  // espace avant /> -> '/>',
			),
			array(
				' ',
				'><',
				'/>',
			),
			$buffer
		);

		// Restaurer scripts/styles
		if ( ! empty( $preserve ) ) {
			$buffer = str_replace( array_keys( $preserve ), array_values( $preserve ), $buffer );
		}

		return trim( $buffer );
	}

	/**
	 * is_valid_email_mx
	 *
	 * @param string $email
	 *
	 * @return bool
	 */
	public static function is_valid_email_mx( string $email ): bool {
		// Syntaxe basique (suffisante en pratique)
		if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
			return false;
		}

		// Extraire le domaine
		/**list( $person, $domain ) = explode( '@', $email, 2 );*/
		$domain = substr( strrchr( $email, '@' ), 1 );
		if ( ! $domain ) {
			return false;
		}

		// Vérifier enregistrements MX ou A
		if ( checkdnsrr( $domain, 'MX' ) ) {
			return true;
		}

		// fallback : certains domaines n'ont pas d'MX explicite mais ont un A
		if ( checkdnsrr( $domain, 'A' ) ) {
			return true;
		}

		return false;
	}
}
