<?php

declare(strict_types=1);

/**
 * Content Toggle  Module.
 *
 * @package DiviSupreme.
 */

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\IconLibrary\IconFont\Utils;
use ET\Builder\Packages\Module\Options\Text\TextStyle;
use ET\Builder\Packages\StyleLibrary\Utils\StyleDeclarations;
use ET\Builder\Packages\Module\Options\Css\CssStyle;
use DiviSupreme\Includes\DiviLibraryLayoutRenderer;

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

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

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

	/**
	 * Register module.
	 */
	public static function register_module()
	{

		$module_json_path = DSM_DIR_PATH . 'divi-5/public/packages/module-library/content-toggle';

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

	public static function dsm_alignment_declaration($params)
	{
		$attr = $params['attrValue'] ?? array();

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

		$attr_value = '';

		switch ($attr) {
			case 'left':
				$attr_value = 'flex-start';
				break;
			case 'center':
				$attr_value = 'center';
				break;
			case 'right':
				$attr_value = 'flex-end';
				break;
			default:
				$attr_value = 'center';
		}

		$style_declarations->add('justify-content', $attr_value);

		return $style_declarations->value();
	}

	/**
	 * Render module style.
	 *
	 * @param array $args - Arguments.
	 */
	public static function module_styles($args)
	{
		$attrs = $args['attrs'] ?? array();
		$elements = $args['elements'];

		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' => $args['orderClass'],
							'attr' => $attrs['css'] ?? array(),
						)
					),

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

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

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

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

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

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

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

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

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

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

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-switch-inner",
							'attr' => $attrs['switcher_bg_primary']['innerContent'] ?? array(),
							'property' => 'background-color',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-toggle-switch:checked+.dsm-switch-inner",
							'attr' => $attrs['switcher_bg_secondary']['innerContent'] ?? array(),
							'property' => 'background-color',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-toggle-btn",
							'attr' => $attrs['switcher_size']['innerContent'] ?? array(),
							'property' => 'font-size',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-switch-inner::before",
							'attr' => $attrs['switcher_inner_bg']['innerContent'] ?? array(),
							'property' => 'background-color',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-content-toggle-front",
							'attr' => $attrs['content_bg_one']['innerContent'] ?? array(),
							'property' => 'background-color',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-content-toggle-back",
							'attr' => $attrs['content_bg_two']['innerContent'] ?? array(),
							'property' => 'background-color',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-content-toggle-front",
							'attr' => $attrs['content_spacing_top_one']['innerContent'] ?? array(),
							'property' => 'margin-top',
						)
					),

					CommonStyle::style(
						array(
							'selector' => "{$args['orderClass']} .dsm-content-toggle-back",
							'attr' => $attrs['content_spacing_top_two']['innerContent'] ?? array(),
							'property' => 'margin-top',
						)
					),
				),
			)
		);
	}

	/**
	 * Render module script data.
	 *
	 * @param array $args - Arguments.
	 */
	public static function module_script_data($args)
	{
		$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($args)
	{
		$classnames_instance = $args['classnamesInstance'];
		$attrs = $args['attrs'];

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


	public static function process_custom_path($content, $order_class)
	{

		if ('' === trim($content)) {
			return '';
		}

		$document = new \DOMDocument();

		libxml_use_internal_errors(true);

		$document->loadXML($content);

		libxml_clear_errors();

		$svg = $document->getElementsByTagName('svg')->item(0);

		$svg_width = $svg->getAttribute('width');
		$svg_height = $svg->getAttribute('height');

		$inner_html = static::get_inner_html($svg);

		return array(
			$svg_width,
			$svg_height,
			str_replace('<path', sprintf('<path id="%1$s"', $order_class), $inner_html),
		);
	}

	public static function get_inner_html($node)
	{
		$innerHTML = '';
		$children = $node->childNodes;
		foreach ($children as $child) {
			$innerHTML .= $child->ownerDocument->saveXML($child);
		}

		return $innerHTML;
	}

	/**
	 * Resolves a Divi Library layout post ID from module attrs (string or int from VB).
	 *
	 * @param array<string, mixed> $attrs         Module attributes.
	 * @param string               $content_index "one" or "two".
	 *
	 * @return int Post ID or 0.
	 */
	private static function get_library_layout_post_id(array $attrs, string $content_index): int
	{
		$raw = $attrs['library_id_' . $content_index]['innerContent']['desktop']['value'] ?? 0;

		return DiviLibraryLayoutRenderer::normalize_post_id($raw);
	}

	/**
	 * Renders the content one based on the content type.
	 *
	 * @param array<string, mixed> $attrs          Module attributes.
	 * @param string               $content_index Index of content, can either be "one" or "two".
	 *
	 * @return string Rendered content.
	 */
	public static function render_content($attrs, $content_index)
	{
		$content_type = $attrs['content_type_' . $content_index]['innerContent']['desktop']['value'] ?? 'content';

		switch ($content_type) {
			case 'content':
				$raw = $attrs['custom_content_' . $content_index]['innerContent']['desktop']['value'] ?? '';
				if (is_array($raw) && isset($raw['text'])) {
					return is_string($raw['text']) ? $raw['text'] : '';
				}

				return is_string($raw) ? $raw : '';
			case 'shortcode':
				$shortcode_content = $attrs['shortcode_content_' . $content_index]['innerContent']['desktop']['value'] ?? '';

				return DiviLibraryLayoutRenderer::render_shortcode_field_content(
					is_string( $shortcode_content ) ? $shortcode_content : '',
					'dsm_content_toggle_shortcode_styles'
				);
			case 'library':
				return DiviLibraryLayoutRenderer::render_layout(
					self::get_library_layout_post_id($attrs, $content_index),
					'dsm_content_toggle_styles'
				);
		}
	}

	/**
	 * 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)
	{

		$heading_one = $attrs['heading_one']['innerContent']['desktop']['value']['text'] ?? '';
		if (is_string($heading_one) === false && is_array($attrs['heading_one']['innerContent']['desktop']['value'] ?? null)) {
			$heading_one = (string) ($attrs['heading_one']['innerContent']['desktop']['value']['text'] ?? '');
		}
		if (! is_string($heading_one)) {
			$heading_one = '';
		}

		$heading_two = $attrs['heading_two']['innerContent']['desktop']['value']['text'] ?? '';
		if (is_string($heading_two) === false && is_array($attrs['heading_two']['innerContent']['desktop']['value'] ?? null)) {
			$heading_two = (string) ($attrs['heading_two']['innerContent']['desktop']['value']['text'] ?? '');
		}
		if (! is_string($heading_two)) {
			$heading_two = '';
		}

		$heading_level_one = $attrs['heading_one']['decoration']['font']['font']['desktop']['value']['headingLevel'] ?? 'h5';
		$heading_level_two = $attrs['heading_two']['decoration']['font']['font']['desktop']['value']['headingLevel'] ?? 'h5';

		if (! is_string($heading_level_one) || ! preg_match('/^h[1-6]$/i', $heading_level_one)) {
			$heading_level_one = 'h5';
		}
		if (! is_string($heading_level_two) || ! preg_match('/^h[1-6]$/i', $heading_level_two)) {
			$heading_level_two = 'h5';
		}

		$active_switcher = $attrs['active_switcher']['innerContent']['desktop']['value'] ?? '';
		$content_fullwidth_one = $attrs['content_fullwidth_one']['innerContent']['desktop']['value'] ?? 'off';
		$content_fullwidth_two = $attrs['content_fullwidth_two']['innerContent']['desktop']['value'] ?? 'off';

		wp_enqueue_script('dsm-content-toggle');

		$front_class = 'dsm-content-toggle-front' . ('on' === $content_fullwidth_one ? ' dsm-content-force-fullwidth' : '');
		$back_class  = 'dsm-content-toggle-back' . ('on' === $content_fullwidth_two ? ' dsm-content-force-fullwidth' : '');

		$container = sprintf(
			'<div class="dsm-content-toggle">
				<div class="dsm-content-toggle-header">
					<div class="dsm-toggle">
						<div class="dsm-toggle-left">
							%1$s
						</div>
						<div class="dsm-toggle-btn">
							<label class="dsm-switch-label" for="dsm-input-%4$s">
								<input id="dsm-input-%4$s" class="dsm-input dsm-toggle-switch" type="checkbox" %3$s />
								<span class="dsm-switch-inner"></span>
							</label>
						</div>
						<div class="dsm-toggle-right">
							%2$s
						</div>
					</div>
				</div>
				<div class="dsm-content-toggle-body">
					%5$s %6$s
				</div>
			</div>',
			$heading_one ? sprintf('<%2$s class="dsm-toggle-head-one"><label for="dsm-input-%3$s">%1$s</label></%2$s>', esc_html($heading_one), esc_attr(strtolower($heading_level_one)), $block->parsed_block['orderIndex']) : '',
			$heading_two ? sprintf('<%2$s class="dsm-toggle-head-two"><label for="dsm-input-%3$s">%1$s</label></%2$s>', esc_html($heading_two), esc_attr(strtolower($heading_level_two)), $block->parsed_block['orderIndex']) : '',
			'switcher_two' === $active_switcher ? esc_attr('checked=true') : '',
			$block->parsed_block['orderIndex'],
			sprintf('<div class="%1$s">%2$s</div>', esc_attr($front_class), static::render_content($attrs, 'one')),
			sprintf('<div class="%1$s">%2$s</div>', esc_attr($back_class), static::render_content($attrs, 'two')),
		);

		// 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 . $module_inner;

		return Module::render(
			array(
				// FE only.
				'orderIndex' => $block->parsed_block['orderIndex'],
				'storeInstance' => $block->parsed_block['storeInstance'],
				// VB equivalent.
				'attrs' => $attrs,
				'elements' => $elements,
				'id' => $block->parsed_block['id'],
				'moduleClassName' => 'dsm_content_toggle',
				'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,
			)
		);
	}
}
