<?php

class WPML_Compatibility_Divi {

	const REGEX_REMOVE_OPENING_PARAGRAPH = '/(<p>[\n\r]*)([\n\r]{1}\[\/et_)/m';
	const REGEX_REMOVE_CLOSING_PARAGRAPH = '/(\[et_.*\][\n\r]{1})([\n\r]*<\/p>)/m';

	/** @var SitePress */
	private $sitepress;

	/**
	 * @param SitePress $sitepress
	 */
	public function __construct( SitePress $sitepress ) {
		$this->sitepress = $sitepress;
	}

	public function add_hooks() {
		add_action( 'init', array( $this, 'load_resources_if_they_are_required' ), 10, 0 );

		if ( $this->sitepress->is_setup_complete() ) {
			add_action( 'admin_init', array( $this, 'display_warning_notice' ), 10, 0 );
			add_filter( 'wpml_pb_should_handle_content', array( $this, 'should_handle_shortcode_content' ), 10, 2 );
		}

		add_filter( 'wpml_pb_shortcode_content_for_translation', array( $this, 'cleanup_global_layout_content' ), 10, 2 );
	}

	/**
	 * @return bool
	 */
	private function is_standard_editor_used() {
		$tm_settings = $this->sitepress->get_setting( 'translation-management', array() );

		return ! isset( $tm_settings['doc_translation_method'] ) ||
			ICL_TM_TMETHOD_MANUAL === $tm_settings['doc_translation_method'];
	}

	public function display_warning_notice() {
		$notices = wpml_get_admin_notices();

		if ( $this->is_standard_editor_used() ) {
			$notices->add_notice( new WPML_Compatibility_Divi_Notice() );
		} elseif ( $notices->get_notice( WPML_Compatibility_Divi_Notice::ID, WPML_Compatibility_Divi_Notice::GROUP ) ) {
			$notices->remove_notice( WPML_Compatibility_Divi_Notice::GROUP, WPML_Compatibility_Divi_Notice::ID );
		}
	}

	public function load_resources_if_they_are_required() {
		if ( ! isset( $_GET['page'] ) || ! is_admin() ) { /* phpcs:disable */
			return;
		}

		$pages = array( self::get_duplication_action_page() );
		if ( self::is_tm_active() ) {
			$pages[] = self::get_translation_dashboard_page();
			$pages[] = self::get_translation_editor_page();
		}

		if ( in_array( $_GET['page'], $pages, true ) ) { /* phpcs:disable */
			$this->register_layouts();
		}
	}

	private static function get_translation_dashboard_page() {
		return constant( 'WPML_TM_FOLDER' ) . '/menu/main.php';
	}

	private static function get_translation_editor_page() {
		return constant( 'WPML_TM_FOLDER' ) . '/menu/translations-queue.php';
	}

	private static function get_duplication_action_page() {
		return constant( 'WPML_PLUGIN_FOLDER' ) . '/menu/languages.php';
	}

	private static function is_tm_active() {
		return defined( 'WPML_TM_FOLDER' );
	}

	private function register_layouts() {
		if ( function_exists( 'et_builder_should_load_framework' ) && ! et_builder_should_load_framework() ) {
			if ( function_exists( 'et_builder_register_layouts' ) ) {
				et_builder_register_layouts();
			} else {
				$lib_file = ET_BUILDER_DIR . 'feature/Library.php';

				if ( ! class_exists( 'ET_Builder_Library' )
					&& defined( 'ET_BUILDER_DIR' )
					&& file_exists( $lib_file )
				) {
					require_once $lib_file;
				}

				if ( class_exists( 'ET_Builder_Library' ) ) {
					ET_Builder_Library::instance();
				}
			}
		}
	}

	/**
	 * The global layout is not properly extracted from the page
	 * because it adds <p> tags either not opened or not closed.
	 *
	 * See the global content below as an example:
	 *
	 * [et_pb_section prev_background_color="#000000" next_background_color="#000000"][et_pb_text]
	 *
	 * </p>
	 * <p>Global text 1 EN5</p>
	 * <p>
	 *
	 * [/et_pb_text][/et_pb_section]
	 *
	 * We also need to remove `prev_background` and `next_background` attributes which are added from the page.
	 *
	 * @param string $content
	 * @param int    $post_id
	 */
	public function cleanup_global_layout_content( $content, $post_id ) {
		if ( 'et_pb_layout' === get_post_type( $post_id ) ) {
			$content = preg_replace( self::REGEX_REMOVE_OPENING_PARAGRAPH, '$2', $content );
			$content = preg_replace( self::REGEX_REMOVE_CLOSING_PARAGRAPH, '$1', $content );
			$content = preg_replace( '/( prev_background_color="#[0-9a-f]*")/', '', $content );
			$content = preg_replace( '/( next_background_color="#[0-9a-f]*")/', '', $content );
		}

		return $content;
	}

	public function should_handle_shortcode_content( $handle_content, $shortcode ) {
		if (
			strpos( $shortcode['tag'], 'et_' ) === 0 &&
			strpos( $shortcode['attributes'], 'global_module=' ) !== false
		) {
			// If a translatable attribute has been excluded from sync, we need to handle it.
			$handle_content = $this->is_excluded_from_sync( $shortcode );
		}
		return $handle_content;
	}

	/**
	 * Check if a global module has excluded any translatable text that we need to handle
	 *
	 * @param array $shortcode  {
	 *      @type string $tag.
	 *      @type string $content.
	 *      @type string $attributes.
	 * }
	 * @return bool
	 */
	private function is_excluded_from_sync( $shortcode ) {
		$handle_content = false;

		preg_match( '/global_module="([0-9]+)"/', $shortcode['attributes'], $matches );
		$excluded   = json_decode( get_post_meta( $matches[1], '_et_pb_excluded_global_options', true ), true );

		if ( is_array( $excluded ) && sizeof( $excluded ) > 0 ) {
			$attributes = $this->get_translatable_shortcode_attributes( $shortcode['tag'] );

			foreach ( $excluded as $field ) {
				if ( in_array( $field, $attributes, true ) ) {
					$handle_content = true;
					break;
				}
			}
		}

		return $handle_content;
	}

	/**
	 * Get a list of translatable attributes for a shortcode tag.
	 * This includes the inner content and any attributes found in XML configuration.
	 *
	 * @param string $tag The shortcode tag.
	 * @return array
	 */
	private function get_translatable_shortcode_attributes( $tag ) {
		$attributes = [ 'et_pb_content_field' ];
		$settings   = get_option( 'icl_st_settings', [] );

		if ( ! isset( $settings['pb_shortcode'] ) ) {
			return $attributes;
		}

		foreach ( $settings['pb_shortcode'] as $setting ) {
			if ( $tag === $setting['tag']['value'] ) {
				foreach ( $setting['attributes'] as $attribute ) {
					if ( empty( $attribute['type'] ) ) {
						$attributes[] = $attribute['value'];
					}
				}
				break;
			}
		}

		return $attributes;
	}

}
