<?php
/**
 * Mask Text module (Divi 5).
 *
 * @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\Css\CssStyle;
use ET\Builder\Packages\Module\Options\Element\ElementClassnames;
use ET\Builder\Packages\Module\Options\Text\TextStyle;
use ET\Builder\Packages\ModuleLibrary\ModuleRegistration;
use ET\Builder\Packages\Module\Layout\Components\StyleCommon\CommonStyle;
use ET\Builder\Packages\StyleLibrary\Utils\StyleDeclarations;

/**
 * Supreme Mask Text — text filled with a background image (D4 parity).
 */
class MaskText implements DependencyInterface
{

	/**
	 * Register module.
	 */
	public function load(): void
	{
		add_action('init', array(self::class, 'register_module'));
	}

	/**
	 * Initialise module dependency.
	 */
	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 with Divi.
	 */
	public static function register_module(): void
	{
		$module_json_path = DSM_DIR_PATH . 'divi-5/public/packages/module-library/mask-text';

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

	/**
	 * Resolve upload / string image value to URL for CSS background-image.
	 *
	 * @param mixed $raw Raw attr value.
	 * @return string
	 */
	private static function get_mask_image_src($raw): string
	{
		if (is_string($raw) || is_numeric($raw)) {
			return trim((string) $raw);
		}
		if (! is_array($raw)) {
			return '';
		}
		if (! empty($raw['src']) && is_string($raw['src'])) {
			return $raw['src'];
		}
		if (! empty($raw['url']) && is_string($raw['url'])) {
			return $raw['url'];
		}

		return '';
	}

	/**
	 * Declaration: background-image from image innerContent.
	 *
	 * @param array<string, mixed> $params Params from CommonStyle.
	 * @return string
	 */
	public static function mask_background_image_func(array $params): string
	{
		$raw = $params['attrValue'] ?? '';
		$src = self::get_mask_image_src($raw);

		$style_declarations = new StyleDeclarations(
			array(
				'returnType' => 'string',
				'important' => array(
					'background-image' => true,
				),
			)
		);

		if ('' === $src) {
			return $style_declarations->value();
		}

		$safe = (is_string($src) && str_starts_with($src, 'data:'))
			? esc_attr($src)
			: esc_url($src);

		$style_declarations->add('background-image', 'url(\'' . $safe . '\')');

		return $style_declarations->value();
	}

	/**
	 * Declaration: background-position (D4 underscore slugs → CSS keywords).
	 *
	 * @param array<string, mixed> $params Params.
	 * @return string
	 */
	public static function mask_background_image_position_func(array $params): string
	{
		$pos = $params['attrValue'] ?? '';
		$pos = is_string($pos) ? $pos : '';

		$style_declarations = new StyleDeclarations(
			array(
				'returnType' => 'string',
				'important' => array(
					'background-position' => true,
				),
			)
		);

		$style_declarations->add('background-position', str_replace('_', ' ', $pos));

		return $style_declarations->value();
	}

	/**
	 * Render module style.
	 *
	 * @param array<string, mixed> $args Arguments.
	 */
	public static function module_styles(array $args): void
	{
		$attrs = $args['attrs'] ?? array();
		$elements = $args['elements'];

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

					TextStyle::style(
						array(
							'selector' => $args['orderClass'],
							'attr' => $attrs['module']['advanced']['text'] ?? array(),
						)
					),

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

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

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-mask-text",
							'attr' => $attrs['image']['innerContent'] ?? array(),
							'declarationFunction' => array(static::class, 'mask_background_image_func'),
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-mask-text",
							'attr' => $attrs['image_background_position']['innerContent'] ?? array(),
							'declarationFunction' => array(static::class, 'mask_background_image_position_func'),
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-mask-text",
							'attr' => $attrs['image_background_size']['innerContent'] ?? array(),
							'property' => 'background-size',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-mask-text",
							'attr' => $attrs['image_background_repeat']['innerContent'] ?? array(),
							'property' => 'background-repeat',
						)
					),
				),
			)
		);
	}

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

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

		$elements->script_data(
			array(
				'attrName' => 'mask_text',
			)
		);
	}

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

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

		$text_color = $attrs['module']['advanced']['text']['text']['desktop']['value']['color'] ?? 'light';
		$classnames_instance->add('et_pb_bg_layout_' . $text_color);
	}

	/**
	 * Render module HTML output.
	 *
	 * @param array<string, mixed> $attrs    Module attrs.
	 * @param string               $content  Block content.
	 * @param \WP_Block            $block    Block instance.
	 * @param mixed                $elements Elements API.
	 * @return string
	 */
	public static function render_callback($attrs, $content, $block, $elements): string
	{
		$allowed = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span', 'p');
		$heading_raw = $attrs['heading_html_tag']['innerContent']['desktop']['value'] ?? 'h2';
		$heading_tag = is_string($heading_raw) ? strtolower($heading_raw) : 'h2';
		if (! in_array($heading_tag, $allowed, true)) {
			$heading_tag = 'h2';
		}

		$mask_inner = $elements->render(
			array(
				'attrName' => 'mask_text',
			)
		);

		$heading = sprintf(
			'<%1$s class="dsm-mask-text et_pb_module_header">%2$s</%1$s>',
			esc_attr($heading_tag),
			et_core_esc_previously($mask_inner)
		);

		$module_inner = HTMLUtility::render(
			array(
				'tag' => 'div',
				'attributes' => array(
					'class' => 'et_pb_module_inner',
				),
				'childrenSanitizer' => 'et_core_esc_previously',
				'children' => $heading,
			)
		);

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

		$module_container_children = $module_elements . $module_inner;

		return Module::render(
			array(
				'orderIndex' => $block->parsed_block['orderIndex'],
				'storeInstance' => $block->parsed_block['storeInstance'],
				'attrs' => $attrs,
				'elements' => $elements,
				'id' => $block->parsed_block['id'],
				'moduleClassName' => 'dsm_mask_text',
				'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,
			)
		);
	}
}
