<?php
/**
 * Module: JetSmartFilters Range Filter.
 */
namespace Jet_Engine_Divi_Views\Components\Jet_Smart_Filters\Modules;

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

use ET\Builder\Framework\DependencyManagement\Interfaces\DependencyInterface;
use ET\Builder\Packages\ModuleLibrary\ModuleRegistration;
use ET\Builder\Packages\Module\Module;
use ET\Builder\FrontEnd\BlockParser\BlockParserStore;
use ET\Builder\FrontEnd\Module\Style;
use Jet_Engine_Divi_Views\Utils;

class Range_Filter implements DependencyInterface {

	private static function get_default_settings() {

		return [
			'filter_id'         => 0,
			'content_provider'  => 'not-selected',
			'apply_type'        => 'ajax',
			'apply_on'          => 'value',
			'apply_button'      => true,
			'apply_button_text' => __( 'Apply filter', 'jet-smart-filters' ),
			'show_label'        => false,
			'query_id'          => '',
		];
	}

	private static function normalize_toggle_value( $value ) {

		if ( is_bool( $value ) ) {
			return $value;
		}

		if ( is_numeric( $value ) ) {
			return (bool) absint( $value );
		}

		if ( ! is_string( $value ) ) {
			return $value;
		}

		$normalized = strtolower( trim( $value ) );

		if ( in_array( $normalized, [ 'on', 'true', 'yes' ], true ) ) {
			return true;
		}

		if ( in_array( $normalized, [ 'off', 'false', 'no', '' ], true ) ) {
			return false;
		}

		return $value;
	}

	private static function get_prepared_attrs( $attrs ) {

		$prepared_attrs = [];

		foreach ( $attrs as $key => $value ) {
			if ( isset( $value['innerContent']['desktop']['value'] ) ) {
				$prepared_attrs[ $key ] = $value['innerContent']['desktop']['value'];
			}
		}

		$prepared_attrs = wp_parse_args( $prepared_attrs, self::get_default_settings() );

		foreach ( [ 'apply_button', 'show_label' ] as $toggle_key ) {
			if ( array_key_exists( $toggle_key, $prepared_attrs ) ) {
				$prepared_attrs[ $toggle_key ] = self::normalize_toggle_value( $prepared_attrs[ $toggle_key ] );
			}
		}

		return $prepared_attrs;
	}

	/**
	 * Module's style components.
	 *
	 * This function is equivalent of JS function ModuleStyles located in
	 * module/styles.tsx.
	 *
	 * @param array $args {
	 *     An array of arguments.
	 *
	 *      @type string $id                Module ID. In VB, the ID of module is UUIDV4. In FE, the ID is order index.
	 *      @type string $name              Module name.
	 *      @type string $attrs             Module attributes.
	 *      @type string $parentAttrs       Parent attrs.
	 *      @type string $orderClass        Selector class name.
	 *      @type string $parentOrderClass  Parent selector class name.
	 *      @type string $wrapperOrderClass Wrapper selector class name.
	 *      @type string $settings          Custom settings.
	 *      @type string $state             Attributes state.
	 *      @type string $mode              Style mode.
	 *      @type ModuleElements $elements  ModuleElements instance.
	 * }
	 */
	public static function module_styles( $args ) {

		$elements                    = $args['elements'];
		$settings                    = $args['settings'] ?? [];
		$default_printed_style_attrs = $args['defaultPrintedStyleAttrs'] ?? [];
		$attrs                       = $args['attrs'] ?? [];

		$selectors = [
			'slider_track'            => "{$args['orderClass']} .jet-range__slider .jet-range__slider__track",
			'slider_range'            => "{$args['orderClass']} .jet-range__slider .jet-range__slider__track__range",
			'slider_input'            => "{$args['orderClass']} .jet-range__slider .jet-range__slider__input",
			'slider_input_thumb_wk'   => "{$args['orderClass']} .jet-range__slider .jet-range__slider__input::-webkit-slider-thumb",
			'slider_input_thumb_moz'  => "{$args['orderClass']} .jet-range__slider .jet-range__slider__input::-moz-range-thumb",
			'slider_input_thumb_ms'   => "{$args['orderClass']} .jet-range__slider .jet-range__slider__input::-ms-thumb",
			'range_values'            => "{$args['orderClass']} .jet-range__values",
			'inputs'                  => "{$args['orderClass']} .jet-range__inputs",
			'inputs_container'        => "{$args['orderClass']} .jet-range__inputs__container",
			'input_group'             => "{$args['orderClass']} .jet-range__inputs__group",
			'input_group_first'       => "{$args['orderClass']} .jet-range__inputs__group:first-child",
			'input_group_last'        => "{$args['orderClass']} .jet-range__inputs__group:last-child",
			'input_group_first_rtl'   => ".rtl {$args['orderClass']} .jet-range__inputs__group:first-child",
			'input_group_last_rtl'    => ".rtl {$args['orderClass']} .jet-range__inputs__group:last-child",
			'input'                   => "{$args['orderClass']} .jet-range__inputs__group input",
			'input_text'              => "{$args['orderClass']} .jet-range__inputs__group__text",
			'filter_label'            => "{$args['orderClass']} .jet-filter-label",
			'apply_button'            => "{$args['orderClass']} .apply-filters__button",
			'apply_button_hover'      => "{$args['orderClass']} .apply-filters__button:hover",
		];

		$slider_track_border = Utils\extract_border_attrs( $attrs['module']['decoration']['sliderTrackBorder'] ?? null );
		$slider_track_border_styles = Utils\build_border_styles(
			$selectors['slider_track'],
			$slider_track_border
		);

		$range_points_border = Utils\extract_border_attrs( $attrs['module']['decoration']['rangePointsBorder'] ?? null );
		$range_points_border_styles = array_merge(
			Utils\build_border_styles( $selectors['slider_input_thumb_wk'], $range_points_border ),
			Utils\build_border_styles( $selectors['slider_input_thumb_moz'], $range_points_border ),
			Utils\build_border_styles( $selectors['slider_input_thumb_ms'], $range_points_border )
		);

		$values_typography = Utils\extract_typography_attrs( $attrs['module']['decoration']['valuesTypography'] ?? null );
		$values_typography_styles = Utils\build_typography_styles(
			$selectors['range_values'],
			$values_typography
		);

		$values_spacing = Utils\extract_spasing_attrs( $attrs['module']['decoration']['valuesSpacing'] ?? null );
		$values_spacing_styles = Utils\build_spacing_styles(
			$selectors['range_values'],
			$values_spacing
		);

		$inputs_margin = Utils\extract_spasing_attrs( $attrs['module']['decoration']['inputsMargin'] ?? null );
		$inputs_margin_styles = Utils\build_spacing_styles(
			$selectors['inputs'],
			$inputs_margin
		);

		$input_typography = Utils\extract_typography_attrs( $attrs['module']['decoration']['inputTypography'] ?? null );
		$input_typography_styles = Utils\build_typography_styles(
			$selectors['input_group'],
			$input_typography
		);

		$input_border = Utils\extract_border_attrs( $attrs['module']['decoration']['inputBorder'] ?? null );
		$input_border_styles = Utils\build_border_styles(
			$selectors['input_group'],
			$input_border
		);

		$input_padding = Utils\extract_spasing_attrs( $attrs['module']['decoration']['inputPadding'] ?? null );
		$input_padding_styles = Utils\build_spacing_styles(
			$selectors['input'],
			$input_padding
		);

		$input_text_typography = Utils\extract_typography_attrs( $attrs['module']['decoration']['inputTextTypography'] ?? null );
		$input_text_typography_styles = Utils\build_typography_styles(
			$selectors['input_text'],
			$input_text_typography
		);

		$input_text_padding = Utils\extract_spasing_attrs( $attrs['module']['decoration']['inputTextPadding'] ?? null );
		$input_text_padding_styles = Utils\build_spacing_styles(
			$selectors['input_text'],
			$input_text_padding
		);

		$label_typography = Utils\extract_typography_attrs( $attrs['module']['decoration']['labelTypography'] ?? null );
		$label_typography_styles = Utils\build_typography_styles(
			$selectors['filter_label'],
			$label_typography
		);

		$label_spacing = Utils\extract_spasing_attrs( $attrs['module']['decoration']['labelSpacing'] ?? null );
		$label_spacing_legacy_padding = Utils\extract_spasing_attrs( $attrs['module']['decoration']['labelPadding'] ?? null );
		$label_spacing_legacy_margin = Utils\extract_spasing_attrs( $attrs['module']['decoration']['labelMargin'] ?? null );
		$label_spacing['padding'] = $label_spacing['padding'] ?? $label_spacing_legacy_padding['padding'] ?? [];
		$label_spacing['margin']  = $label_spacing['margin'] ?? $label_spacing_legacy_margin['margin'] ?? [];
		$label_spacing_styles = Utils\build_spacing_styles(
			$selectors['filter_label'],
			$label_spacing
		);

		
		$apply_spacing = Utils\extract_spasing_attrs( $attrs['module']['decoration']['applySpacing'] ?? null );
		$apply_spacing_legacy_padding = Utils\extract_spasing_attrs( $attrs['module']['decoration']['applyPadding'] ?? null );
		$apply_spacing_legacy_margin = Utils\extract_spasing_attrs( $attrs['module']['decoration']['applyMargin'] ?? null );
		$apply_spacing['padding'] = $apply_spacing['padding'] ?? $apply_spacing_legacy_padding['padding'] ?? [];
		$apply_spacing['margin']  = $apply_spacing['margin'] ?? $apply_spacing_legacy_margin['margin'] ?? [];
		$apply_spacing_styles = Utils\build_spacing_styles(
			$selectors['apply_button'],
			$apply_spacing
		);

		$apply_border = Utils\extract_border_attrs( $attrs['module']['decoration']['applyBorder'] ?? null );
		$apply_border_styles = Utils\build_border_styles(
			$selectors['apply_button'],
			$apply_border
		);

		$inputs_offset = $attrs['module']['decoration']['inputsOffset'] ?? null;
		$inputs_offset_half = self::map_responsive_value( $inputs_offset, static function( $value ) {
			return "calc({$value} / 2)";
		} );

		$inputs_alignment_left = self::map_alignment_value( $attrs['module']['decoration']['inputsAlignment'] ?? null, 'left' );
		$inputs_alignment_right = self::map_alignment_value( $attrs['module']['decoration']['inputsAlignment'] ?? null, 'right' );

		Style::add(
			[
				'id'            => $args['id'],
				'name'          => $args['name'],
				'orderIndex'    => $args['orderIndex'],
				'storeInstance' => $args['storeInstance'],
				'styles'        => [
					$elements->style(
						[
							'attrName'   => 'module',
							'styleProps' => [
								'defaultPrintedStyleAttrs' => $default_printed_style_attrs['module']['decoration'] ?? [],
								'disabledOn'               => [
									'disabledModuleVisibility' => $settings['disabledModuleVisibility'] ?? null,
								],
								'advancedStyles' => array_merge(
									$slider_track_border_styles,
									$range_points_border_styles,
									$values_typography_styles,
									$values_spacing_styles,
									$inputs_margin_styles,
									$input_typography_styles,
									$input_border_styles,
									$input_padding_styles,
									$input_text_typography_styles,
									$input_text_padding_styles,
									$label_typography_styles,
									$label_spacing_styles,
															$apply_spacing_styles,
									$apply_border_styles,
									[
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_track'],
												'attr'     => $attrs['module']['decoration']['sliderStroke'] ?? [],
												'property' => 'height',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_track'],
												'attr'     => $attrs['module']['decoration']['sliderDefaultColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_range'],
												'attr'     => $attrs['module']['decoration']['sliderRangeColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_wk'],
												'attr'     => $attrs['module']['decoration']['pointsWidth'] ?? [],
												'property' => 'width',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_moz'],
												'attr'     => $attrs['module']['decoration']['pointsWidth'] ?? [],
												'property' => 'width',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_ms'],
												'attr'     => $attrs['module']['decoration']['pointsWidth'] ?? [],
												'property' => 'width',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input'],
												'attr'     => $attrs['module']['decoration']['pointsHeight'] ?? [],
												'property' => 'height',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_wk'],
												'attr'     => $attrs['module']['decoration']['pointsHeight'] ?? [],
												'property' => 'height',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_moz'],
												'attr'     => $attrs['module']['decoration']['pointsHeight'] ?? [],
												'property' => 'height',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_ms'],
												'attr'     => $attrs['module']['decoration']['pointsHeight'] ?? [],
												'property' => 'height',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_wk'],
												'attr'     => $attrs['module']['decoration']['pointsColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_moz'],
												'attr'     => $attrs['module']['decoration']['pointsColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['slider_input_thumb_ms'],
												'attr'     => $attrs['module']['decoration']['pointsColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['range_values'],
												'attr'     => $attrs['module']['decoration']['valuesColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['range_values'],
												'attr'     => $attrs['module']['decoration']['valuesAlign'] ?? [],
												'property' => 'text-align',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['inputs_container'],
												'attr'     => $attrs['module']['decoration']['inputsWidth'] ?? [],
												'property' => 'max-width',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_group_first'],
												'attr'     => $inputs_offset_half,
												'property' => 'margin-right',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_group_last'],
												'attr'     => $inputs_offset_half,
												'property' => 'margin-left',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_group_first_rtl'],
												'attr'     => $inputs_offset_half,
												'property' => 'margin-left',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_group_last_rtl'],
												'attr'     => $inputs_offset_half,
												'property' => 'margin-right',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['inputs_container'],
												'attr'     => $inputs_alignment_left,
												'property' => 'margin-left',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['inputs_container'],
												'attr'     => $inputs_alignment_right,
												'property' => 'margin-right',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_group'],
												'attr'     => $attrs['module']['decoration']['inputColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_group'],
												'attr'     => $attrs['module']['decoration']['inputBackgroundColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_text'],
												'attr'     => $attrs['module']['decoration']['inputTextColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['input_text'],
												'attr'     => $attrs['module']['decoration']['inputTextBackgroundColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['filter_label'],
												'attr'     => $attrs['module']['decoration']['labelAlignment'] ?? [],
												'property' => 'text-align',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['filter_label'],
												'attr'     => $attrs['module']['decoration']['labelColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['apply_button'],
												'attr'     => $attrs['module']['decoration']['applyNormalColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['apply_button'],
												'attr'     => $attrs['module']['decoration']['applyNormalBgColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['apply_button_hover'],
												'attr'     => $attrs['module']['decoration']['applyHoverColor'] ?? [],
												'property' => 'color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['apply_button_hover'],
												'attr'     => $attrs['module']['decoration']['applyHoverBgColor'] ?? [],
												'property' => 'background-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['apply_button_hover'],
												'attr'     => $attrs['module']['decoration']['applyHoverBorderColor'] ?? [],
												'property' => 'border-color',
											]
										],
										[
											'componentName' => 'divi/common',
											'props'         => [
												'selector' => $selectors['apply_button'],
												'attr'     => $attrs['module']['decoration']['applyAlignment'] ?? [],
												'property' => 'align-self',
											]
										],
									]
								),
							],
						]
					),
				],
			]
		);
	}

	/**
	 * Map responsive attr values and keep breakpoint structure.
	 *
	 * @param mixed    $attr
	 * @param callable $map
	 *
	 * @return array|null
	 */
	private static function map_responsive_value( $attr, $map ) {
		if ( empty( $attr ) ) {
			return null;
		}

		$breakpoints = [ 'desktop', 'tablet', 'phone' ];
		$has_bp = false;

		foreach ( $breakpoints as $bp ) {
			if ( isset( $attr[ $bp ] ) ) {
				$has_bp = true;
				break;
			}
		}

		if ( $has_bp ) {
			$out = $attr;
			foreach ( $breakpoints as $bp ) {
				if ( ! isset( $attr[ $bp ] ) ) {
					continue;
				}

				$val = $attr[ $bp ]['value'] ?? $attr[ $bp ]['default'] ?? null;
				if ( null === $val ) {
					continue;
				}

				$mapped = $map( $val );
				$out[ $bp ]['value'] = $mapped;
				$out[ $bp ]['default'] = $mapped;
			}

			return $out;
		}

		$val = $attr['value'] ?? $attr['default'] ?? null;
		if ( null === $val ) {
			return $attr;
		}

		$mapped = $map( $val );
		$attr['value'] = $mapped;
		$attr['default'] = $mapped;

		return $attr;
	}

	/**
	 * Map alignment to margin-left/right values.
	 *
	 * @param mixed  $attr
	 * @param string $side left|right
	 *
	 * @return array|null
	 */
	private static function map_alignment_value( $attr, $side ) {
		return self::map_responsive_value( $attr, static function( $value ) use ( $side ) {
			$value = (string) $value;
			if ( 'left' === $side ) {
				if ( 'left' === $value ) {
					return '0';
				}
				if ( 'right' === $value ) {
					return 'auto';
				}
				return 'auto';
			}

			if ( 'right' === $value ) {
				return '0';
			}
			if ( 'left' === $value ) {
				return 'auto';
			}
			return 'auto';
		} );
	}

	/**
	 * Set script data of used module options.
	 *
	 * @since ??
	 *
	 * @param array $args {
	 *   Array of arguments.
	 *
	 *   @type string $id       Module id.
	 *   @type string $selector Module selector.
	 *   @type array  $attrs    Module attributes.
	 * }
	 */
	public static function module_script_data( $args ) {
	}

	/**
	 * Module classnames function for Dynamic module.
	 *
	 * This function is equivalent of JS function moduleClassnames located in
	 * src/components/dynamic-module/module-classnames.ts.
	 *
	 * @since ??
	 *
	 * @param array $args {
	 *     An array of arguments.
	 *
	 *     @type object $classnamesInstance Instance of ET\Builder\Packages\Module\Layout\Components\Classnames.
	 *     @type array  $attrs              Block attributes data that being rendered.
	 * }
	 */
	public static function module_classnames( $args ) {
	}

	/**
	 * Dynamic module render callback which outputs server side rendered HTML on the Front-End.
	 *
	 * @since ??
	 *
	 * @param array          $attrs    Block attributes that were saved by VB.
	 * @param string         $content  Block content.
	 * @param \WP_Block      $block    Parsed block object that being rendered.
	 * @param ModuleElements $elements ModuleElements instance.
	 *
	 * @return string HTML rendered of module.
	 */
	public static function render_callback( $attrs, $content, $block, $elements ) {

		$prepared_attrs = self::get_prepared_attrs( $attrs );

		$parent       = BlockParserStore::get_parent( $block->parsed_block['id'], $block->parsed_block['storeInstance'] );
		$parent_attrs = $parent->attrs ?? [];

		$filters_block_type = jet_smart_filters()->blocks->get_block_type( 'range' );
		$content = $filters_block_type->render_callback( $prepared_attrs );

		return Module::render(
			[
				// FE only.
				'orderIndex'          => $block->parsed_block['orderIndex'],
				'storeInstance'       => $block->parsed_block['storeInstance'],

				// VB equivalent.
				'id'                  => $block->parsed_block['id'],
				'name'                => $block->block_type->name,
				'moduleCategory'      => $block->block_type->category,
				'attrs'               => $attrs,
				'elements'            => $elements,
				'classnamesFunction'  => [ Range_Filter::class, 'module_classnames' ],
				'stylesComponent'     => [ Range_Filter::class, 'module_styles' ],
				'scriptDataComponent' => [ Range_Filter::class, 'module_script_data' ],
				'parentAttrs'         => $parent_attrs,
				'parentId'            => $parent->id ?? '',
				'parentName'          => $parent->blockName ?? '',
				'children'            => [ $content ],
			]
		);
	}

	/**
	 * Get JetEngine render class instance
	 */
	public static function get_jet_engine_render_instance( $attributes ) {
		return jet_engine()->listings->get_render_instance( self::get_jet_engine_render_name(), $attributes );
	}

	/**
	 * Return name of JetEngine renderer for current module
	 */
	public static function get_jet_engine_render_name() {
		return 'dynamic-field';
	}

	/**
	 * Loads `DynamicField` and registers Front-End render callback and REST API Endpoints.
	 *
	 * @since ??
	 *
	 * @return void
	 */
	public function load() {

		$module_json_folder_path = JET_ENGINE_DIVI_VIEWS_MODULES_JSON_PATH . 'range-filter/';

		add_action(
			'init',
			function() use ( $module_json_folder_path ) {
				ModuleRegistration::register_module(
					$module_json_folder_path,
					[
						'render_callback' => [ Range_Filter::class, 'render_callback' ],
					]
				);
			}
		);
	}
}
