<?php
/**
 * Product Filter Widget - Render Methods
 *
 * Standalone functions prefixed ggmc_product_filter_ for use by the widget class.
 *
 * @package GGM_Commerce
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Main render entry point.
 *
 * @param \GGM_Commerce_Base_Widget $widget Widget instance.
 */
function ggmc_product_filter_render( $widget ) {
	$settings = $widget->get_settings_for_display();

	// Get actual price range from database
	$price_range              = ggmc_product_filter_get_price_range();
	$settings['min_price']    = $price_range['min'];
	$settings['max_price']    = $price_range['max'];

	ggmc_product_filter_render_filter( $widget, $settings );
}

/**
 * Get actual min/max prices from all products in database.
 *
 * @return array { min: float, max: float }
 */
function ggmc_product_filter_get_price_range() {
	// Use transient cache to avoid query on every page load.
	$cache_key = 'ggmc_product_price_range';
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}

	global $wpdb;

	$table_name = $wpdb->prefix . 'ggmc_products';
	// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table_name is safely constructed from $wpdb->prefix
	$result = $wpdb->get_row( "
		SELECT
			FLOOR(MIN(price)) as min_price,
			CEIL(MAX(price)) as max_price
		FROM {$table_name}
		WHERE (status = 'active' OR status IS NULL)
	" );

	$range = [
		'min' => $result && $result->min_price !== null ? floatval( $result->min_price ) : 0,
		'max' => $result && $result->max_price !== null ? floatval( $result->max_price ) : 1000,
	];

	set_transient( $cache_key, $range, HOUR_IN_SECONDS );

	return $range;
}

/**
 * Render the filter form HTML.
 *
 * @param \GGM_Commerce_Base_Widget $widget   Widget instance.
 * @param array                     $settings Widget settings (with price range injected).
 */
function ggmc_product_filter_render_filter( $widget, $settings ) {
	?>
	<div class="ggmc-product-filter" data-widget-id="<?php echo esc_attr( $widget->get_id() ); ?>" data-hide-empty-attributes="<?php echo esc_attr( $settings['hide_empty_attributes'] ?? 'yes' ); ?>">
		<?php if ( ( $settings['show_title'] ?? 'yes' ) === 'yes' && ! empty( $settings['filter_title'] ) ) :
			$title_tag = $settings['title_html_tag'] ?? 'h3';
		?>
			<<?php echo esc_attr( $title_tag ); ?> class="filter-title"><?php echo esc_html( $settings['filter_title'] ); ?></<?php echo esc_attr( $title_tag ); ?>>
		<?php endif; ?>

		<form class="filter-form" data-layout="<?php echo esc_attr( $settings['filter_layout'] ); ?>">
			<?php if ( $settings['show_search'] === 'yes' ) : ?>
				<div class="filter-group search-group">
					<label for="product-search"><?php esc_html_e( 'Search Products', 'ggm-commerce' ); ?></label>
					<input type="text" id="product-search" name="search" class="filter-input"
					       placeholder="<?php esc_attr_e( 'Enter search term...', 'ggm-commerce' ); ?>">
				</div>
			<?php endif; ?>

			<?php if ( $settings['show_categories'] === 'yes' ) : ?>
				<div class="filter-group category-group">
					<label for="product-category"><?php esc_html_e( 'Category', 'ggm-commerce' ); ?></label>
					<select id="product-category" name="category" class="filter-select">
						<option value=""><?php esc_html_e( 'All Categories', 'ggm-commerce' ); ?></option>
						<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- ggmc_product_filter_get_categories_options() returns pre-escaped HTML options ?>
						<?php echo ggmc_product_filter_get_categories_options(); ?>
					</select>
				</div>
			<?php endif; ?>

			<?php if ( $settings['show_tags'] === 'yes' ) : ?>
				<div class="filter-group tags-group">
					<label for="product-tags"><?php esc_html_e( 'Tags', 'ggm-commerce' ); ?></label>
					<select id="product-tags" name="tags" class="filter-select">
						<option value=""><?php esc_html_e( 'All Tags', 'ggm-commerce' ); ?></option>
						<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- ggmc_product_filter_get_tags_options() returns pre-escaped HTML options ?>
						<?php echo ggmc_product_filter_get_tags_options(); ?>
					</select>
				</div>
			<?php endif; ?>

			<?php if ( $settings['show_price_range'] === 'yes' ) : ?>
				<div class="filter-group price-group">
					<label><?php esc_html_e( 'Price Range', 'ggm-commerce' ); ?></label>
					<?php
					$price_display_type = $settings['price_range_display_type'] ?? 'slider';
					$currency_options   = get_option( 'ggm_commerce_currency_options', array() );
					$currency_symbol    = isset( $currency_options['symbol'] ) ? $currency_options['symbol'] : '£';

					if ( 'slider' === $price_display_type ) :
					?>
					<div class="price-slider-container">
						<div class="price-slider"
						     data-min="<?php echo esc_attr( $settings['min_price'] ); ?>"
						     data-max="<?php echo esc_attr( $settings['max_price'] ); ?>">
						</div>
						<div class="price-display">
							<span class="price-min"><?php echo esc_html( $currency_symbol . $settings['min_price'] ); ?></span>
							<span class="price-separator"> - </span>
							<span class="price-max"><?php echo esc_html( $currency_symbol . $settings['max_price'] ); ?></span>
						</div>
						<input type="hidden" name="min_price" value="<?php echo esc_attr( $settings['min_price'] ); ?>">
						<input type="hidden" name="max_price" value="<?php echo esc_attr( $settings['max_price'] ); ?>">
					</div>
					<?php else : ?>
					<div class="price-inputs">
						<input type="number"
						       name="min_price"
						       class="filter-input price-min-input"
						       placeholder="<?php esc_attr_e( 'Min', 'ggm-commerce' ); ?>"
						       min="<?php echo esc_attr( $settings['min_price'] ); ?>"
						       max="<?php echo esc_attr( $settings['max_price'] ); ?>"
						       step="any"
						       data-min="<?php echo esc_attr( $settings['min_price'] ); ?>">
						<span class="input-separator">-</span>
						<input type="number"
						       name="max_price"
						       class="filter-input price-max-input"
						       placeholder="<?php esc_attr_e( 'Max', 'ggm-commerce' ); ?>"
						       min="<?php echo esc_attr( $settings['min_price'] ); ?>"
						       max="<?php echo esc_attr( $settings['max_price'] ); ?>"
						       step="any"
						       data-max="<?php echo esc_attr( $settings['max_price'] ); ?>">
						<span class="currency-label"><?php echo esc_html( $currency_symbol ); ?></span>
					</div>
					<?php endif; ?>
				</div>
			<?php endif; ?>

			<?php if ( $settings['show_stock_filter'] === 'yes' ) : ?>
				<div class="filter-group stock-group">
					<label for="stock-status"><?php esc_html_e( 'Stock Status', 'ggm-commerce' ); ?></label>
					<select id="stock-status" name="stock" class="filter-select">
						<option value=""><?php esc_html_e( 'All Stock Status', 'ggm-commerce' ); ?></option>
						<option value="in_stock"><?php esc_html_e( 'In Stock', 'ggm-commerce' ); ?></option>
						<option value="out_of_stock"><?php esc_html_e( 'Out of Stock', 'ggm-commerce' ); ?></option>
					</select>
				</div>
			<?php endif; ?>

			<?php ggmc_product_filter_render_attribute_filters( $settings ); ?>

			<div class="filter-actions">
				<button type="submit" class="filter-apply-btn"><?php echo esc_html( $settings['apply_button_text'] ?? __( 'Apply Filters', 'ggm-commerce' ) ); ?></button>
				<button type="reset" class="filter-reset-btn"><?php echo esc_html( $settings['reset_button_text'] ?? __( 'Reset', 'ggm-commerce' ) ); ?></button>
			</div>
		</form>
	</div>

	<?php
	ggmc_product_filter_render_filter_styles( $settings );
	ggmc_product_filter_render_filter_script( $settings );
}

/**
 * Get HTML option elements for the categories dropdown.
 *
 * @return string Pre-escaped HTML <option> elements.
 */
function ggmc_product_filter_get_categories_options() {
	// Use transient cache for the HTML output
	$cache_key = 'ggmc_filter_categories_options';
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}

	// Reuse the data handler's cached query to avoid duplicate DB calls
	$categories_array = GGM_Commerce_Product_Data_Handler::get_categories_options();

	$options = '';
	foreach ( $categories_array as $id => $name ) {
		$options .= '<option value="' . esc_attr( $id ) . '">' . esc_html( $name ) . '</option>';
	}

	set_transient( $cache_key, $options, HOUR_IN_SECONDS );

	return $options;
}

/**
 * Get HTML option elements for the tags dropdown.
 *
 * @return string Pre-escaped HTML <option> elements.
 */
function ggmc_product_filter_get_tags_options() {
	// Use transient cache for the HTML output
	$cache_key = 'ggmc_filter_tags_options';
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}

	// Reuse the data handler's cached query to avoid duplicate DB calls
	$tags_array = GGM_Commerce_Product_Data_Handler::get_tags_options();

	$options = '';
	foreach ( $tags_array as $id => $name ) {
		$options .= '<option value="' . esc_attr( $id ) . '">' . esc_html( $name ) . '</option>';
	}

	set_transient( $cache_key, $options, HOUR_IN_SECONDS );

	return $options;
}

/**
 * Render dynamic layout CSS for the filter form.
 *
 * @param array $settings Widget settings.
 */
function ggmc_product_filter_render_filter_styles( $settings ) {
	?>
	<style>
	.ggmc-product-filter .filter-form {
		flex-direction: <?php echo esc_html( $settings['filter_layout'] === 'horizontal' ? 'row' : 'column' ); ?>;
		<?php if ( $settings['filter_layout'] === 'horizontal' ) : ?>
		flex-wrap: wrap;
		<?php endif; ?>
	}

	<?php if ( $settings['filter_layout'] === 'horizontal' ) :
		$gap_size   = isset( $settings['filter_group_spacing']['size'] ) ? $settings['filter_group_spacing']['size'] : 15;
		$columns    = intval( $settings['columns'] );
		// Calculate: (100% - total gaps) / number of columns
		$total_gaps = ( $columns - 1 ) * $gap_size;
	?>
	/* Horizontal layout spacing */
	.ggmc-product-filter .filter-group {
		flex: 0 1 calc((100% - <?php echo esc_html( $total_gaps ); ?>px) / <?php echo esc_html( $columns ); ?>);
		min-width: 200px;
		margin-right: <?php echo esc_html( $gap_size ); ?>px;
	}

	/* Remove right margin from last item in each row */
	.ggmc-product-filter .filter-group:nth-child(<?php echo esc_html( $columns ); ?>n) {
		margin-right: 0;
	}
	<?php else :
		// Vertical layout spacing
		$gap_size = isset( $settings['filter_group_spacing']['size'] ) ? $settings['filter_group_spacing']['size'] : 15;
	?>
	/* Vertical layout spacing */
	.ggmc-product-filter .filter-group + .filter-group {
		margin-top: <?php echo esc_html( $gap_size ); ?>px;
	}
	<?php endif; ?>

	<?php if ( $settings['filter_layout'] === 'horizontal' ) : ?>
	.ggmc-product-filter .filter-actions {
		justify-content: center;
	}
	<?php endif; ?>

	@media (max-width: 768px) {
		.ggmc-product-filter .filter-form {
			flex-direction: column;
		}

		.ggmc-product-filter .filter-group {
			flex: 1 1 auto;
		}
	}
	</style>
	<?php
}

/**
 * Render attribute filter controls (front-end HTML).
 *
 * @param array $settings Widget settings.
 */
function ggmc_product_filter_render_attribute_filters( $settings ) {
	// Check if attribute filters are enabled
	if ( empty( $settings['show_attribute_filters'] ) || $settings['show_attribute_filters'] !== 'yes' ) {
		return;
	}

	// Check if Custom Attributes premium is active
	if ( ! class_exists( 'GGM_Commerce_License' ) || ! class_exists( 'GGM_Commerce_Attributes' ) ) {
		return;
	}

	$license = GGM_Commerce_License::instance();
	if ( ! $license->is_widget_activated( 'custom-attributes' ) ) {
		return;
	}

	$attributes_manager = GGM_Commerce_Attributes::get_instance();
	$filterable_attrs   = $attributes_manager->get_filterable_attributes();

	if ( empty( $filterable_attrs ) ) {
		return;
	}

	// Filter to selected attributes if specified
	$selected_ids = ! empty( $settings['selected_attributes'] ) ? (array) $settings['selected_attributes'] : array();
	if ( ! empty( $selected_ids ) ) {
		$filterable_attrs = array_filter(
			$filterable_attrs,
			function ( $attr ) use ( $selected_ids ) {
				return in_array( (string) $attr->id, $selected_ids, true );
			}
		);
	}

	$show_units     = ! empty( $settings['show_attribute_units'] ) && $settings['show_attribute_units'] === 'yes';
	$show_counts    = ! empty( $settings['show_attribute_counts'] ) && $settings['show_attribute_counts'] === 'yes';
	$select_type    = $settings['attribute_filter_type'] ?? 'checkbox';
	$number_type    = $settings['number_attribute_type'] ?? 'slider';
	$label_display  = $settings['attribute_label_display'] ?? 'name';
	$hide_empty     = ! empty( $settings['hide_empty_attributes'] ) && $settings['hide_empty_attributes'] === 'yes';

	foreach ( $filterable_attrs as $attr ) {
		ggmc_product_filter_render_single_attribute_filter( $attr, $attributes_manager, $show_units, $show_counts, $select_type, $number_type, $label_display, $hide_empty );
	}
}

/**
 * Render a single attribute filter control.
 *
 * @param object $attr               Attribute object.
 * @param object $attributes_manager Attributes manager instance.
 * @param bool   $show_units         Whether to show units.
 * @param bool   $show_counts        Whether to show counts.
 * @param string $select_type        Display type for select attributes.
 * @param string $number_type        Display type for number attributes.
 * @param string $label_display      How to display the label: 'name', 'name_icon', or 'icon'.
 * @param bool   $hide_empty         Whether to hide options with zero products.
 */
function ggmc_product_filter_render_single_attribute_filter( $attr, $attributes_manager, $show_units, $show_counts, $select_type, $number_type, $label_display = 'name', $hide_empty = false ) {
	$unit_suffix = $show_units && ! empty( $attr->unit ) ? ' ' . esc_html( $attr->unit ) : '';

	// Parse icon data and render via Elementor's Icons_Manager to ensure icon font CSS is enqueued
	$icon_html = '';
	if ( in_array( $label_display, array( 'name_icon', 'icon' ), true ) && ! empty( $attr->icon ) ) {
		$icon_data = json_decode( $attr->icon, true );
		if ( is_array( $icon_data ) && ! empty( $icon_data['value'] ) ) {
			ob_start();
			ggmc_render_icon( $icon_data, array( 'aria-hidden' => 'true' ) );
			$icon_html = ob_get_clean();
		}
	}

	// Build label content based on display setting
	$label_content = '';
	switch ( $label_display ) {
		case 'icon':
			$label_content = ! empty( $icon_html ) ? $icon_html : esc_html( $attr->name );
			break;
		case 'name_icon':
			$label_content = ! empty( $icon_html )
				? $icon_html . ' <span class="attr-label-text">' . esc_html( $attr->name ) . '</span>'
				: esc_html( $attr->name );
			break;
		case 'name':
		default:
			$label_content = esc_html( $attr->name );
			break;
	}
	?>
	<div class="filter-group attribute-filter-group" data-attribute-id="<?php echo esc_attr( $attr->id ); ?>" data-attribute-type="<?php echo esc_attr( $attr->attribute_type ); ?>">
		<label class="attribute-filter-label">
			<?php
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $label_content is escaped above
			echo $label_content;
			?>
		</label>
		<?php
		switch ( $attr->attribute_type ) {
			case 'select':
				ggmc_product_filter_render_select_attribute_filter( $attr, $attributes_manager, $show_counts, $select_type, $hide_empty );
				break;

			case 'number':
				ggmc_product_filter_render_number_attribute_filter( $attr, $attributes_manager, $unit_suffix, $number_type );
				break;

			case 'text':
			default:
				ggmc_product_filter_render_text_attribute_filter( $attr );
				break;
		}
		?>
	</div>
	<?php
}

/**
 * Render select-type attribute filter.
 *
 * @param object $attr               Attribute object.
 * @param object $attributes_manager Attributes manager instance.
 * @param bool   $show_counts        Whether to show product counts.
 * @param string $display_type       'dropdown' or 'checkbox'.
 * @param bool   $hide_empty         Whether to hide options with zero products.
 */
function ggmc_product_filter_render_select_attribute_filter( $attr, $attributes_manager, $show_counts, $display_type, $hide_empty = false ) {
	$options = ! empty( $attr->options ) ? json_decode( $attr->options, true ) : array();
	if ( empty( $options ) ) {
		return;
	}

	$counts_map = array();
	if ( $show_counts ) {
		$counts = $attributes_manager->get_attribute_option_counts( $attr->id );
		foreach ( $counts as $c ) {
			$counts_map[ $c->attribute_value ] = $c->count;
		}
	}

	if ( 'dropdown' === $display_type ) {
		?>
		<select name="attr_<?php echo esc_attr( $attr->id ); ?>" class="filter-select attribute-select" data-attribute-id="<?php echo esc_attr( $attr->id ); ?>">
			<option value=""><?php esc_html_e( 'All', 'ggm-commerce' ); ?></option>
			<?php foreach ( $options as $option ) :
				$count      = isset( $counts_map[ $option ] ) ? intval( $counts_map[ $option ] ) : 0;
				$count_text = $show_counts ? ' (' . $count . ')' : '';
				if ( $hide_empty && $count === 0 ) {
					continue;
				}
				?>
				<option value="<?php echo esc_attr( $option ); ?>"><?php echo esc_html( $option . $count_text ); ?></option>
			<?php endforeach; ?>
		</select>
		<?php
	} else {
		?>
		<div class="attribute-checkboxes">
			<?php foreach ( $options as $option ) :
				$count      = isset( $counts_map[ $option ] ) ? intval( $counts_map[ $option ] ) : 0;
				$count_text = $show_counts ? '<span class="count">(' . $count . ')</span>' : '';
				if ( $hide_empty && $count === 0 ) {
					continue;
				}
				?>
				<label class="checkbox-label">
					<input type="checkbox" name="attr_<?php echo esc_attr( $attr->id ); ?>[]" value="<?php echo esc_attr( $option ); ?>" data-attribute-id="<?php echo esc_attr( $attr->id ); ?>">
					<span class="checkmark"></span>
					<?php echo esc_html( $option ); ?> <?php echo wp_kses_post( $count_text ); ?>
				</label>
			<?php endforeach; ?>
		</div>
		<?php
	}
}

/**
 * Render number-type attribute filter.
 *
 * @param object $attr               Attribute object.
 * @param object $attributes_manager Attributes manager instance.
 * @param string $unit_suffix        Pre-escaped unit suffix string.
 * @param string $display_type       'slider' or 'inputs'.
 */
function ggmc_product_filter_render_number_attribute_filter( $attr, $attributes_manager, $unit_suffix, $display_type ) {
	$range = $attributes_manager->get_attribute_value_range( $attr->id );
	$min   = $range['min'];
	$max   = $range['max'];

	if ( 'slider' === $display_type ) {
		?>
		<div class="attribute-slider-container">
			<div class="attribute-slider"
			     data-attribute-id="<?php echo esc_attr( $attr->id ); ?>"
			     data-min="<?php echo esc_attr( $min ); ?>"
			     data-max="<?php echo esc_attr( $max ); ?>"
			     data-unit="<?php echo esc_attr( $attr->unit ); ?>">
			</div>
			<div class="attribute-range-display">
				<span class="attr-range-min"><?php echo esc_html( $min . $unit_suffix ); ?></span>
				<span class="attr-separator"> - </span>
				<span class="attr-range-max"><?php echo esc_html( $max . $unit_suffix ); ?></span>
			</div>
			<input type="hidden" name="attr_<?php echo esc_attr( $attr->id ); ?>_min" value="<?php echo esc_attr( $min ); ?>">
			<input type="hidden" name="attr_<?php echo esc_attr( $attr->id ); ?>_max" value="<?php echo esc_attr( $max ); ?>">
		</div>
		<?php
	} else {
		?>
		<div class="attribute-inputs">
			<input type="number"
			       name="attr_<?php echo esc_attr( $attr->id ); ?>_min"
			       class="filter-input attr-min-input"
			       placeholder="<?php esc_attr_e( 'Min', 'ggm-commerce' ); ?>"
			       min="<?php echo esc_attr( $min ); ?>"
			       max="<?php echo esc_attr( $max ); ?>"
			       step="any">
			<span class="input-separator">-</span>
			<input type="number"
			       name="attr_<?php echo esc_attr( $attr->id ); ?>_max"
			       class="filter-input attr-max-input"
			       placeholder="<?php esc_attr_e( 'Max', 'ggm-commerce' ); ?>"
			       min="<?php echo esc_attr( $min ); ?>"
			       max="<?php echo esc_attr( $max ); ?>"
			       step="any">
			<?php if ( ! empty( $unit_suffix ) ) : ?>
				<span class="unit-label"><?php echo esc_html( $unit_suffix ); ?></span>
			<?php endif; ?>
		</div>
		<?php
	}
}

/**
 * Render text-type attribute filter.
 *
 * @param object $attr Attribute object.
 */
function ggmc_product_filter_render_text_attribute_filter( $attr ) {
	?>
	<input type="text"
	       name="attr_<?php echo esc_attr( $attr->id ); ?>"
	       class="filter-input attribute-text-input"
	       placeholder="<?php
			/* translators: %s: attribute name */
			echo esc_attr( sprintf( __( 'Search %s...', 'ggm-commerce' ), $attr->name ) );
		?>"
	       data-attribute-id="<?php echo esc_attr( $attr->id ); ?>">
	<?php
}

/**
 * Render filter script (currently a no-op — JS loaded via get_script_depends).
 *
 * @param array $settings Widget settings.
 */
function ggmc_product_filter_render_filter_script( $settings ) {
	// Script is now loaded via widget-product-filter.js
	// No inline script needed
}
