<?php
/**
 * Icon List Child Module.
 *
 * @package DiviSupreme
 */

declare(strict_types=1);

namespace DiviSupreme\Modules;

if (!defined('ABSPATH')) {
	die('Direct access forbidden.');
}


use ET\Builder\Framework\DependencyManagement\Interfaces\DependencyInterface;
use ET\Builder\Framework\Utility\HTMLUtility;
use ET\Builder\FrontEnd\Module\Style;
use ET\Builder\Packages\Module\Module;
use ET\Builder\Packages\Module\Options\Element\ElementClassnames;
use ET\Builder\Packages\ModuleLibrary\ModuleRegistration;
use ET\Builder\Packages\Module\Layout\Components\StyleCommon\CommonStyle;
use ET\Builder\Packages\Module\Options\Css\CssStyle;
use ET\Builder\Packages\ModuleUtils\ModuleUtils;
use DiviSupreme\Extensions\IconLibraries\LegacyModuleIconStyles;
use DiviSupreme\Includes\ModuleRegisterAttrsNormalize;
use DiviSupreme\Includes\UploadImageMarkup;
use ET\Builder\Packages\Module\Layout\Components\ModuleElements\ModuleElements;


/**
 * Class that handles "IconListChild Module" module.
 */
class IconListChild implements DependencyInterface
{


	/**
	 * Register module.
	 * `DependencyInterface` interface ensures class method name `load()` is executed for initialization.
	 */
	public function load(): void
	{
		add_filter(
			'divi_module_library_register_module_attrs',
			array( self::class, 'filter_register_module_attrs' ),
			10,
			2
		);
		add_action('init', array(self::class, 'register_module'));
	}

	/**
	 * Normalize migrated tooltip `content` rich-text shape after merged attrs.
	 *
	 * @param array<string, mixed> $module_attrs Merged module attrs.
	 * @param array<string, mixed> $filter_args  Filter args (`name`, `attrs`, `id`, `storeInstance`).
	 * @return array<string, mixed>
	 */
	public static function filter_register_module_attrs( $module_attrs, $filter_args ) {
		if ( ! is_array( $module_attrs ) || ! is_array( $filter_args ) ) {
			return is_array( $module_attrs ) ? $module_attrs : array();
		}

		$name = $filter_args['name'] ?? '';
		if ( 'dsm/icon-list-child' !== $name ) {
			return $module_attrs;
		}

		ModuleRegisterAttrsNormalize::icon_list_child_merged( $module_attrs );

		return $module_attrs;
	}

	/**
	 * Initilises the module.
	 *
	 * @return void
	 */
	public static function dsm_initialise(): void
	{
		add_action(
			'divi_module_library_modules_dependency_tree',
			static function ($dependency_tree): void {
				$dependency_tree->add_dependency(new self());
			}
		);
	}

	/**
	 * Register module.
	 */
	public static function register_module(): void
	{
		$module_json_path = DSM_DIR_PATH . 'divi-5/public/packages/module-library/icon-list-child';

		ModuleRegistration::register_module(
			$module_json_path,
			array(
				'render_callback' => array(self::class, 'render_callback'),
			)
		);
	}


	/**
	 * Default tooltip max-width aligned with D4 `default_on_front`.
	 */
	private const TOOLTIP_MAX_WIDTH_DEFAULT = '180px';

	/**
	 * Ensure tooltip max-width innerContent has a desktop default when Divi omits the key.
	 *
	 * @param array<string, mixed> $attrs Module attrs.
	 * @return array<string, mixed>
	 */
	private static function tooltip_max_width_inner_content( array $attrs ): array {
		$inner = $attrs['tooltip_max_width']['innerContent'] ?? array();

		if ( ! is_array( $inner ) ) {
			$inner = array();
		}

		$desktop_value = $inner['desktop']['value'] ?? '';

		if ( '' === (string) $desktop_value ) {
			$inner['desktop']['value'] = self::TOOLTIP_MAX_WIDTH_DEFAULT;
		}

		return $inner;
	}

	/**
	 * @param mixed $params Style params from CommonStyle.
	 */
	public static function icon_style_declaration( $params ): string {
		return LegacyModuleIconStyles::build_pseudo_icon_declaration( $params );
	}

	/**
	 * Render module style.
	 *
	 * @param array $args - Arguments.
	 */
	public static function module_styles(array $args): void
	{
		$args = \DiviSupreme\Includes\DsmDiviBuilderCssScope::normalize_module_styles_args( $args );
		$attrs = $args['attrs'] ?? array();
		$elements = $args['elements'];
		$order_class = (string) ( $args['orderClass'] ?? '' );
		$base_order_class = (string) ( $args['baseOrderClass'] ?? $args['orderClass'] ?? '' );
		$tooltip_placement = $attrs['tooltip_placement']['innerContent']['desktop']['value'] ?? '';
		$tooltip_box_selector = $base_order_class . '.tippy-box.dsm_icon_list_child_tooltip_wrapper';
		$tooltip_content_selector = $tooltip_box_selector . ' .tippy-content';

		Style::add(
			array(
				'id' => $args['id'],
				'name' => $args['name'],
				'orderIndex' => $args['orderIndex'],
				'storeInstance' => $args['storeInstance'],
				'styles' => array(
					// Module.
					$elements->style(
						array(
							'attrName' => 'module',
							'styleProps' => array(
								'disabledOn' => array(
									'disabledModuleVisibility' => $args['settings']['disabledModuleVisibility'] ?? null,
								),
							),
						)
					),

					CssStyle::style(
						array(
							'selector' => $order_class,
							'attr' => $attrs['css'] ?? array(),
						)
					),

					$elements->style(
						array(
							'attrName' => 'iconStyling',
						)
					),

					$elements->style(
						array(
							'attrName' => 'imageStyling',
						)
					),

					$elements->style(
						array(
							'attrName' => 'text',
						)
					),

					$elements->style(
						array(
							'attrName' => 'tooltip_padding',
						)
					),

					$elements->style(
						array(
							'attrName' => 'content',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_icon",
							'attr' => $attrs['icon_gap_width']['innerContent'] ?? array(),
							'property' => 'width',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
							'orderClass' => $order_class,
							'selectors' => array(
								'desktop' => array(
									'value' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
									'hover' => "{$order_class}.dsm_icon_list_child:hover .dsm_icon_list_wrapper > .dsm_icon_list_icon",
								),
								'tablet' => array(
									'value' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
									'hover' => "{$order_class}.dsm_icon_list_child:hover .dsm_icon_list_wrapper > .dsm_icon_list_icon",
								),
								'phone' => array(
									'value' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
									'hover' => "{$order_class}.dsm_icon_list_child:hover .dsm_icon_list_wrapper > .dsm_icon_list_icon",
								),
							),
							'attr' => $attrs['icon_color']['innerContent'] ?? array(),
							'property' => 'color',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
							'orderClass' => $order_class,
							'selectors' => array(
								'desktop' => array(
									'value' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
									'hover' => "{$order_class}.dsm_icon_list_child:hover .dsm_icon_list_wrapper > .dsm_icon_list_icon",
								),
								'tablet' => array(
									'value' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
									'hover' => "{$order_class}.dsm_icon_list_child:hover .dsm_icon_list_wrapper > .dsm_icon_list_icon",
								),
								'phone' => array(
									'value' => "{$order_class}.dsm_icon_list_child .dsm_icon_list_wrapper > .dsm_icon_list_icon",
									'hover' => "{$order_class}.dsm_icon_list_child:hover .dsm_icon_list_wrapper > .dsm_icon_list_icon",
								),
							),
							'attr' => $attrs['icon_background_color']['innerContent'] ?? array(),
							'property' => 'background',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_wrapper .dsm_icon_list_icon",
							'attr' => $attrs['icon_padding']['innerContent'] ?? array(),
							'property' => 'padding',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_wrapper .dsm_icon_list_icon",
							'attr' => $attrs['icon_font_size']['innerContent'] ?? array(),
							'property' => 'font-size',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_icon::after",
							'attr' => $attrs['font_icon']['innerContent'] ?? array(),
							'declarationFunction' => array(static::class, 'icon_style_declaration'),
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_image",
							'attr' => $attrs['image_background_color']['innerContent'] ?? array(),
							'property' => 'background',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_image",
							'attr' => $attrs['image_padding']['innerContent'] ?? array(),
							'property' => 'padding',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$order_class} .dsm_icon_list_image img",
							'attr' => $attrs['image_max_width']['innerContent'] ?? array(),
							'property' => 'width',
						)
					),

					'' !== $tooltip_box_selector ?

					CommonStyle::style(
						array(
							'selector' => $tooltip_box_selector,
							'attr' => $attrs['tooltip_background_color']['innerContent'] ?? array(),
							'property' => 'background-color',
						)
					) : '',

					'' !== $tooltip_content_selector ?

					CommonStyle::style(
						array(
							'selector' => $tooltip_content_selector,
							'attr' => self::tooltip_max_width_inner_content( $attrs ),
							'property' => 'max-width',
						)
					) : '',

					( '' !== $tooltip_box_selector && 'top' === $tooltip_placement ) ?

					CommonStyle::style(
						array(
							'selector' => "{$tooltip_box_selector}[data-placement^='top'] .tippy-arrow::before",
							'attr' => $attrs['tooltip_background_color']['innerContent'] ?? array(),
							'property' => 'border-top-color',
						)
					) : '',

					( '' !== $tooltip_box_selector && 'bottom' === $tooltip_placement ) ?

					CommonStyle::style(
						array(
							'selector' => "{$tooltip_box_selector}[data-placement^='bottom'] .tippy-arrow::before",
							'attr' => $attrs['tooltip_background_color']['innerContent'] ?? array(),
							'property' => 'border-bottom-color',
						)
					) : '',

					( '' !== $tooltip_box_selector && 'left' === $tooltip_placement ) ?

					CommonStyle::style(
						array(
							'selector' => "{$tooltip_box_selector}[data-placement^='left'] .tippy-arrow::before",
							'attr' => $attrs['tooltip_background_color']['innerContent'] ?? array(),
							'property' => 'border-left-color',
						)
					) : '',

					( '' !== $tooltip_box_selector && 'right' === $tooltip_placement ) ?

					CommonStyle::style(
						array(
							'selector' => "{$tooltip_box_selector}[data-placement^='right'] .tippy-arrow::before",
							'attr' => $attrs['tooltip_background_color']['innerContent'] ?? array(),
							'property' => 'border-right-color',
						)
					) : '',

				),
			)
		);
	}

	/**
	 * Render module script data.
	 *
	 * @param array $args - Arguments.
	 */
	public static function module_script_data(array $args): void
	{
		$elements = $args['elements'];

		// Element Script Data Options.
		$elements->script_data(
			array(
				'attrName' => 'module',
			)
		);
	}

	/**
	 * Render module classnames.
	 *
	 * @param array $args - Arguments.
	 */
	public static function module_classnames(array $args): void
	{
		$classnames_instance = $args['classnamesInstance'];
		$attrs = $args['attrs'];

		// Module.
		$classnames_instance->add(
			ElementClassnames::classnames(
				array(
					'attrs' => $attrs['module']['decoration'] ?? array(),
				)
			)
		);

		$classnames_instance->add('dsm_icon_list_child');
	}

	/**
	 * Render module HTML output.
	 *
	 * @param array     $attrs - Modules Attributes.
	 * @param string    $content - Content.
	 * @param \WP_Block $block - Block.
	 * @param mixed     $elements - Elements.
	 */
	public static function render_callback($attrs, $content, $block, $elements): string
	{
		if ( $elements instanceof ModuleElements && is_array( $elements->module_attrs ) ) {
			ModuleRegisterAttrsNormalize::icon_list_child_merged( $elements->module_attrs );
		}

		if ( is_array( $attrs ) ) {
			ModuleRegisterAttrsNormalize::icon_list_child_merged( $attrs );
		}

		$use_icon    = $attrs['use_icon']['innerContent']['desktop']['value'] ?? 'on';
		$image_raw   = $attrs['image']['innerContent']['desktop']['value'] ?? '';
		$use_tooltip = $attrs['use_tooltip']['innerContent']['desktop']['value'] ?? 'off';
		$tooltip_placement = $attrs['tooltip_placement']['innerContent']['desktop']['value'] ?? 'right';
		$link_url = $attrs['module']['advanced']['link']['desktop']['value']['url'] ?? '';
		$link_target = $attrs['module']['advanced']['link']['desktop']['value']['target'] ?? '';
		$block_id    = isset( $block->parsed_block['id'] ) ? (string) $block->parsed_block['id'] : '';
		$store_instance = $block->parsed_block['storeInstance'] ?? null;
		$order_class_name = ModuleUtils::get_module_order_class_name( $block_id, $store_instance );
		if ( '' === $order_class_name ) {
			$order_class_name = 'dsm_icon_list_child_' . (int) ( $block->parsed_block['orderIndex'] ?? 0 );
		}

		$text_markup = $elements->render(
			array(
				'attrName' => 'text',
			)
		);

		$tooltip_content = $elements->render(
			array(
				'attrName'    => 'content',
				'attrSubName' => 'text',
			)
		);

		$alt_rendered = isset( $attrs['alt'] )
			? (string) $elements->render(
				array(
					'attrName' => 'alt',
				)
			)
			: '';
		$alt_text     = trim( wp_strip_all_tags( $alt_rendered ) );
		$fallback_alt = '' !== $alt_text ? $alt_text : trim( wp_strip_all_tags( (string) $text_markup ) );

		$font_icon_settings = null;
		if (
			isset( $attrs['font_icon']['innerContent']['desktop']['value'] )
			&& is_array( $attrs['font_icon']['innerContent']['desktop']['value'] )
		) {
			$font_icon_settings = $attrs['font_icon']['innerContent']['desktop']['value'];
		}

		// DSM webfont glyphs render via `<i>` inside `.et-pb-icon`; native Divi/FA use `::after` CSS.
		$icon = LegacyModuleIconStyles::render_custom_icon_host( $font_icon_settings, 'dsm_icon_list_icon' );

		$img_html = UploadImageMarkup::render_img_html($image_raw, $fallback_alt);
		$image_markup = '' !== $img_html
			? sprintf('<span class="dsm_icon_list_image">%s</span>', $img_html)
			: '';

		$markup_with_tooltip = sprintf(
			'<div class="dsm-tooltip dsm_icon_list_tooltip dsm-frontend" data-dsm-tooltip-placement="%4$s" data-dsm-icon-list-tooltip-id="%5$s" data-order-class="%6$s">
			   <span class="dsm_icon_list_wrapper">
			     %1$s
			  </span>
			  <span class="dsm_icon_list_text">%2$s</span>
			</div>
			<div class="tooltip-content">%3$s</div>',
			'off' === $use_icon ? $image_markup : $icon,
			et_core_esc_previously( $text_markup ),
			et_core_esc_previously( $tooltip_content ),
			$tooltip_placement,
			esc_attr( $block_id ),
			esc_attr( $order_class_name )
		);

		$markup_without_tooltip = sprintf(
			'<span class="dsm_icon_list_wrapper">
			     %1$s
			  </span>
			  <span class="dsm_icon_list_text">%2$s</span>
			',
			'off' === $use_icon ? $image_markup : $icon,
			et_core_esc_previously( $text_markup )
		);

		$container = sprintf(
			'%1$s',
			!empty($link_url) ? sprintf(
				'<a href="%1$s" %2$s>%3$s</a>',
				$link_url,
				'on' === $link_target ? 'target="_blank"' : '',
				'on' === $use_tooltip ? $markup_with_tooltip : $markup_without_tooltip
			) : (
				'on' === $use_tooltip ? $markup_with_tooltip : $markup_without_tooltip
			)
		);

		// Module Inner.
		// Essentially, this is the module content.
		// Were wrapping the title and content in a div with class `et_pb_module_inner`.
		$module_inner = HTMLUtility::render(
			array(
				'tag' => 'div',
				'attributes' => array(
					'class' => 'et_pb_module_inner',
				),
				'childrenSanitizer' => 'et_core_esc_previously',
				'children' => $container,
			)
		);

		// This are the module elements that will be rendered in the frontend.

		$module_elements = $elements->style_components(
			array(
				'attrName' => 'module',
			)
		);

		// This are the children of the module container, which are the module elements and the module inner.
		$module_container_children = $module_elements . $container;

		return Module::render(
			array(
				// FE only.
				'orderIndex' => $block->parsed_block['orderIndex'],
				'storeInstance' => $block->parsed_block['storeInstance'],
				// VB equivalent.
				'tag' => 'li',
				'attrs' => $attrs,
				'elements' => $elements,
				'id' => $block->parsed_block['id'],
				'name' => $block->block_type->name,
				'classnamesFunction' => array(self::class, 'module_classnames'),
				'moduleCategory' => $block->block_type->category,
				'stylesComponent' => array(self::class, 'module_styles'),
				'scriptDataComponent' => array(self::class, 'module_script_data'),
				'children' => $module_container_children,
			)
		);
	}
}
