<?php
/**
 * Widget Name: Search Filter
 * Description: AJAX-powered search, filter, results-count and reset widget.
 *              Each item type (search, checkbox, radio, select,
 *              results_count, reset) can live in the SAME widget OR in
 *              SEPARATE widgets — connection happens via a shared Connection ID.
 *
 * @package    captain-widgets-kit
 * @since      1.2.0
 */

use Elementor\Widget_Base;
use Elementor\Controls_Manager;
use Elementor\Group_Control_Typography;
use Elementor\Group_Control_Border;

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

/**
 * Class Captwiki_Search_Filter
 *
 * @since 1.2.0
 */
class Captwiki_Search_Filter extends Widget_Base {

	public function get_name()       { return 'captwiki-search-filter'; }
	public function get_title()      { return esc_html__( 'Search Filter', 'captain-widgets-kit' ); }
	public function get_icon()       { return 'eicon-search captwiki-el-logo'; }
	public function get_categories() { return array( 'captwiki-essential' ); }
	public function get_keywords()   { return array( 'filter', 'search', 'ajax', 'listing', 'taxonomy', 'reset', 'count' ); }

	public function has_widget_inner_wrapper(): bool {
		return ! \Elementor\Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
	}

	// =========================================================================
	// CONTROLS
	// =========================================================================
	protected function register_controls() {

		// ── Connection ────────────────────────────────────────────────────────
		$this->start_controls_section( 'section_connection', array(
			'label' => esc_html__( 'Connection', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_CONTENT,
		) );

		$this->add_control( 'connection_id', array(
			'label'       => esc_html__( 'Connection ID', 'captain-widgets-kit' ),
			'type'        => Controls_Manager::TEXT,
			'default'     => 'cwk-filter-1',
			'placeholder' => 'e.g. cwk-filter-1',
			'description' => esc_html__( 'Set the same ID in the listing widget and any other filter/reset/count widget to link them all.', 'captain-widgets-kit' ),
		) );

		$this->add_control( 'post_type', array(
			'label'   => esc_html__( 'Post Type', 'captain-widgets-kit' ),
			'type'    => Controls_Manager::SELECT,
			'default' => 'post',
			'options' => $this->captwiki_get_post_types(),
		) );

		$this->add_control( 'delay_load', array(
			'label'       => esc_html__( 'Search Delay (ms)', 'captain-widgets-kit' ),
			'type'        => Controls_Manager::NUMBER,
			'min'         => 0,
			'max'         => 2000,
			'step'        => 100,
			'default'     => 300,
			'description' => esc_html__( 'Debounce delay before search fires while typing.', 'captain-widgets-kit' ),
		) );

		$this->end_controls_section();

		// ── Filter Fields (Repeater) ──────────────────────────────────────────
		$this->start_controls_section( 'section_filters', array(
			'label' => esc_html__( 'Filter Fields', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_CONTENT,
		) );

		$repeater = new \Elementor\Repeater();

		// ── Filter Type ─────────────────────────────────────────────────
		$repeater->add_control( 'filter_type', array(
			'label'   => esc_html__( 'Filter Type', 'captain-widgets-kit' ),
			'type'    => Controls_Manager::SELECT,
			'default' => 'search',
			'options' => array(
				'search'        => esc_html__( 'Text Search', 'captain-widgets-kit' ),
				'checkbox'      => esc_html__( 'Checkbox (Taxonomy)', 'captain-widgets-kit' ),
				'radio'         => esc_html__( 'Radio Button (Taxonomy)', 'captain-widgets-kit' ),
				'select'        => esc_html__( 'Dropdown (Taxonomy)', 'captain-widgets-kit' ),
				'results_count' => esc_html__( 'Results Count', 'captain-widgets-kit' ),
				'reset'         => esc_html__( 'Reset Button', 'captain-widgets-kit' ),
			),
		) );

		// ── Label (shared) ──────────────────────────────────────────────
		$repeater->add_control( 'field_label', array(
			'label'       => esc_html__( 'Field Label', 'captain-widgets-kit' ),
			'type'        => Controls_Manager::TEXT,
			'default'     => '',
			'placeholder' => esc_html__( 'e.g. Category', 'captain-widgets-kit' ),
			'condition'   => array( 'filter_type!' => array( 'results_count', 'reset' ) ),
		) );

		// ── Taxonomy ────────────────────────────────────────────────────
		$repeater->add_control( 'taxonomy', array(
			'label'     => esc_html__( 'Taxonomy', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::SELECT,
			'options'   => $this->captwiki_get_taxonomies(),
			'condition' => array( 'filter_type' => array( 'checkbox', 'radio', 'select' ) ),
		) );

		// ── Search Placeholder ──────────────────────────────────────────
		$repeater->add_control( 'search_placeholder', array(
			'label'     => esc_html__( 'Placeholder', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::TEXT,
			'default'   => esc_html__( 'Search...', 'captain-widgets-kit' ),
			'condition' => array( 'filter_type' => 'search' ),
		) );

		// ── Show Count ──────────────────────────────────────────────────
		$repeater->add_control( 'show_count', array(
			'label'        => esc_html__( 'Show Post Count', 'captain-widgets-kit' ),
			'type'         => Controls_Manager::SWITCHER,
			'return_value' => 'yes',
			'default'      => '',
			'condition'    => array( 'filter_type' => array( 'checkbox', 'radio', 'select' ) ),
		) );

		// ── Show All Option ─────────────────────────────────────────────
		$repeater->add_control( 'show_all_option', array(
			'label'        => esc_html__( 'Show "All" Option', 'captain-widgets-kit' ),
			'type'         => Controls_Manager::SWITCHER,
			'return_value' => 'yes',
			'default'      => 'yes',
			'condition'    => array( 'filter_type' => array( 'radio', 'select' ) ),
		) );

		// ── Results Count: Text Template ────────────────────────────────
		$repeater->add_control( 'results_text', array(
			'label'       => esc_html__( 'Results Text', 'captain-widgets-kit' ),
			'type'        => Controls_Manager::TEXTAREA,
			'default'     => esc_html__( 'Showing {visible} of {total} results', 'captain-widgets-kit' ),
			'description' => esc_html__( 'Use {visible} for current results count and {total} for total found posts.', 'captain-widgets-kit' ),
			'rows'        => 2,
			'condition'   => array( 'filter_type' => 'results_count' ),
		) );

		// ── Reset: Button Text ──────────────────────────────────────────
		$repeater->add_control( 'reset_text', array(
			'label'     => esc_html__( 'Button Text', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::TEXT,
			'default'   => esc_html__( 'Reset all', 'captain-widgets-kit' ),
			'condition' => array( 'filter_type' => 'reset' ),
		) );

		// ── Reset: Fix to Bottom (sticky) ───────────────────────────────
		$repeater->add_control( 'reset_fixed', array(
			'label'        => esc_html__( 'Fix Reset Button', 'captain-widgets-kit' ),
			'type'         => Controls_Manager::SWITCHER,
			'label_on'     => esc_html__( 'Yes', 'captain-widgets-kit' ),
			'label_off'    => esc_html__( 'Hide', 'captain-widgets-kit' ),
			'return_value' => 'yes',
			'default'      => '',
			'condition'    => array( 'filter_type' => 'reset' ),
		) );

		// ── Reset: Tag Position (Start / End) ───────────────────────────
		$repeater->add_control( 'reset_tag_position', array(
			'label'     => esc_html__( 'Tag Position', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::SELECT,
			'default'   => 'end',
			'options'   => array(
				'start' => esc_html__( 'Start', 'captain-widgets-kit' ),
				'end'   => esc_html__( 'End', 'captain-widgets-kit' ),
			),
			'description' => esc_html__( 'Position of the active-filter tags shown next to reset button.', 'captain-widgets-kit' ),
			'condition' => array( 'filter_type' => 'reset' ),
		) );

		$this->add_control( 'filter_fields', array(
			'label'       => esc_html__( 'Filter Fields', 'captain-widgets-kit' ),
			'type'        => Controls_Manager::REPEATER,
			'fields'      => $repeater->get_controls(),
			'default'     => array(
				array(
					'filter_type'        => 'search',
					'search_placeholder' => esc_html__( 'Search...', 'captain-widgets-kit' ),
				),
			),
			'title_field' => '{{{ field_label || filter_type }}}',
		) );

		$this->end_controls_section();

		// ── Layout ───────────────────────────────────────────────────────────
		$this->start_controls_section( 'section_layout', array(
			'label' => esc_html__( 'Layout', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_CONTENT,
		) );

		$this->add_control( 'filters_direction', array(
			'label'   => esc_html__( 'Direction', 'captain-widgets-kit' ),
			'type'    => Controls_Manager::SELECT,
			'default' => 'row',
			'options' => array(
				'row'    => esc_html__( 'Horizontal', 'captain-widgets-kit' ),
				'column' => esc_html__( 'Vertical', 'captain-widgets-kit' ),
			),
		) );

		$this->end_controls_section();

		// =====================================================================
		// STYLE SECTIONS
		// =====================================================================

		// ── Wrapper ───────────────────────────────────────────────────────────
		$this->start_controls_section( 'style_wrapper', array(
			'label' => esc_html__( 'Filter Wrapper', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_STYLE,
		) );

		$this->add_responsive_control( 'wrapper_gap', array(
			'label'      => esc_html__( 'Gap Between Fields', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::SLIDER,
			'size_units' => array( 'px', 'em' ),
			'range'      => array( 'px' => array( 'min' => 0, 'max' => 60 ) ),
			'default'    => array( 'unit' => 'px', 'size' => 12 ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-wrap' => 'gap: {{SIZE}}{{UNIT}};' ),
		) );

		$this->add_responsive_control( 'wrapper_padding', array(
			'label'      => esc_html__( 'Padding', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::DIMENSIONS,
			'size_units' => array( 'px', 'em', '%' ),
			'selectors'  => array( '{{WRAPPER}} .cw-search-filter' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ),
		) );

		$this->end_controls_section();

		// ── Labels ────────────────────────────────────────────────────────────
		$this->start_controls_section( 'style_labels', array(
			'label' => esc_html__( 'Field Labels', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_STYLE,
		) );

		$this->add_group_control( Group_Control_Typography::get_type(), array(
			'name'     => 'label_typography',
			'selector' => '{{WRAPPER}} .cw-filter-label',
		) );

		$this->add_control( 'label_color', array(
			'label'     => esc_html__( 'Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-label' => 'color: {{VALUE}};' ),
		) );

		$this->add_responsive_control( 'label_spacing', array(
			'label'      => esc_html__( 'Bottom Spacing', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::SLIDER,
			'size_units' => array( 'px' ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-label' => 'margin-bottom: {{SIZE}}{{UNIT}};' ),
		) );

		$this->end_controls_section();

		// ── Search Input ──────────────────────────────────────────────────────
		$this->start_controls_section( 'style_search_input', array(
			'label' => esc_html__( 'Search Input', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_STYLE,
		) );

		$this->add_group_control( Group_Control_Typography::get_type(), array(
			'name'     => 'input_typography',
			'selector' => '{{WRAPPER}} .cw-filter-search-input',
		) );

		$this->add_control( 'input_text_color', array(
			'label'     => esc_html__( 'Text Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-search-input' => 'color: {{VALUE}};' ),
		) );

		$this->add_control( 'input_bg_color', array(
			'label'     => esc_html__( 'Background', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-search-input' => 'background-color: {{VALUE}};' ),
		) );

		$this->add_group_control( Group_Control_Border::get_type(), array(
			'name'     => 'input_border',
			'selector' => '{{WRAPPER}} .cw-filter-search-input',
		) );

		$this->add_responsive_control( 'input_border_radius', array(
			'label'      => esc_html__( 'Border Radius', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::DIMENSIONS,
			'size_units' => array( 'px', '%' ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-search-input' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ),
		) );

		$this->add_responsive_control( 'input_padding', array(
			'label'      => esc_html__( 'Padding', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::DIMENSIONS,
			'size_units' => array( 'px', 'em' ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-search-input' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ),
		) );

		$this->end_controls_section();

		// ── Checkbox / Radio ──────────────────────────────────────────────────
		$this->start_controls_section( 'style_checkbox', array(
			'label' => esc_html__( 'Checkbox / Radio', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_STYLE,
		) );

		$this->add_group_control( Group_Control_Typography::get_type(), array(
			'name'     => 'checkbox_typography',
			'selector' => '{{WRAPPER}} .cw-filter-checkbox label, {{WRAPPER}} .cw-filter-radio label',
		) );

		$this->add_control( 'checkbox_label_color', array(
			'label'     => esc_html__( 'Label Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array(
				'{{WRAPPER}} .cw-filter-checkbox label' => 'color: {{VALUE}};',
				'{{WRAPPER}} .cw-filter-radio label'    => 'color: {{VALUE}};',
			),
		) );

		$this->add_control( 'checkbox_active_color', array(
			'label'     => esc_html__( 'Active Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array(
				'{{WRAPPER}} .cw-filter-checkbox input:checked + label .cw-check-icon' => 'background-color: {{VALUE}}; border-color: {{VALUE}};',
				'{{WRAPPER}} .cw-filter-radio input:checked + label .cw-radio-icon'    => 'border-color: {{VALUE}};',
				'{{WRAPPER}} .cw-filter-radio input:checked + label .cw-radio-dot'     => 'background-color: {{VALUE}};',
			),
		) );

		$this->end_controls_section();

		// ── Results Count ─────────────────────────────────────────────────────
		$this->start_controls_section( 'style_results_count', array(
			'label' => esc_html__( 'Results Count', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_STYLE,
		) );

		$this->add_group_control( Group_Control_Typography::get_type(), array(
			'name'     => 'results_typography',
			'selector' => '{{WRAPPER}} .cw-filter-results-count',
		) );

		$this->add_control( 'results_color', array(
			'label'     => esc_html__( 'Text Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-results-count' => 'color: {{VALUE}};' ),
		) );

		$this->add_control( 'results_numbers_color', array(
			'label'     => esc_html__( 'Numbers Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-results-count .cw-count-num' => 'color: {{VALUE}};' ),
		) );

		$this->add_responsive_control( 'results_padding', array(
			'label'      => esc_html__( 'Padding', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::DIMENSIONS,
			'size_units' => array( 'px', 'em' ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-results-count' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ),
		) );

		$this->end_controls_section();

		// ── Reset Button ──────────────────────────────────────────────────────
		$this->start_controls_section( 'style_reset_btn', array(
			'label' => esc_html__( 'Reset Button', 'captain-widgets-kit' ),
			'tab'   => Controls_Manager::TAB_STYLE,
		) );

		$this->add_group_control( Group_Control_Typography::get_type(), array(
			'name'     => 'reset_btn_typography',
			'selector' => '{{WRAPPER}} .cw-filter-reset-btn',
		) );

		$this->start_controls_tabs( 'reset_btn_tabs' );

			$this->start_controls_tab( 'reset_btn_normal', array( 'label' => esc_html__( 'Normal', 'captain-widgets-kit' ) ) );

			$this->add_control( 'reset_btn_color', array(
				'label'     => esc_html__( 'Text Color', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array( '{{WRAPPER}} .cw-filter-reset-btn' => 'color: {{VALUE}};' ),
			) );

			$this->add_control( 'reset_btn_bg', array(
				'label'     => esc_html__( 'Background', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array( '{{WRAPPER}} .cw-filter-reset-btn' => 'background-color: {{VALUE}};' ),
			) );

			$this->end_controls_tab();

			$this->start_controls_tab( 'reset_btn_hover', array( 'label' => esc_html__( 'Hover', 'captain-widgets-kit' ) ) );

			$this->add_control( 'reset_btn_hover_color', array(
				'label'     => esc_html__( 'Text Color', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array( '{{WRAPPER}} .cw-filter-reset-btn:hover' => 'color: {{VALUE}};' ),
			) );

			$this->add_control( 'reset_btn_hover_bg', array(
				'label'     => esc_html__( 'Background', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array( '{{WRAPPER}} .cw-filter-reset-btn:hover' => 'background-color: {{VALUE}};' ),
			) );

			$this->end_controls_tab();

		$this->end_controls_tabs();

		$this->add_group_control( Group_Control_Border::get_type(), array(
			'name'     => 'reset_btn_border',
			'selector' => '{{WRAPPER}} .cw-filter-reset-btn',
		) );

		$this->add_responsive_control( 'reset_btn_border_radius', array(
			'label'      => esc_html__( 'Border Radius', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::DIMENSIONS,
			'size_units' => array( 'px', '%' ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-reset-btn' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ),
		) );

		$this->add_responsive_control( 'reset_btn_padding', array(
			'label'      => esc_html__( 'Padding', 'captain-widgets-kit' ),
			'type'       => Controls_Manager::DIMENSIONS,
			'size_units' => array( 'px', 'em' ),
			'selectors'  => array( '{{WRAPPER}} .cw-filter-reset-btn' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};' ),
		) );

		// ── Active Filter Tags (shown beside reset) ──────────────────────
		$this->add_control( 'style_active_tags_heading', array(
			'label'     => esc_html__( 'Active Filter Tags', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::HEADING,
			'separator' => 'before',
		) );

		$this->add_group_control( Group_Control_Typography::get_type(), array(
			'name'     => 'active_tag_typography',
			'selector' => '{{WRAPPER}} .cw-filter-active-tag',
		) );

		$this->add_control( 'active_tag_color', array(
			'label'     => esc_html__( 'Tag Text Color', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-active-tag' => 'color: {{VALUE}};' ),
		) );

		$this->add_control( 'active_tag_bg', array(
			'label'     => esc_html__( 'Tag Background', 'captain-widgets-kit' ),
			'type'      => Controls_Manager::COLOR,
			'selectors' => array( '{{WRAPPER}} .cw-filter-active-tag' => 'background-color: {{VALUE}};' ),
		) );

		$this->end_controls_section();
	}

	// =========================================================================
	// RENDER
	// =========================================================================
	protected function render() {
		$settings = $this->get_settings_for_display();

		$connection_id = ! empty( $settings['connection_id'] ) ? sanitize_html_class( $settings['connection_id'] ) : 'cwk-filter-1';
		$post_type     = ! empty( $settings['post_type'] )     ? sanitize_text_field( $settings['post_type'] )     : 'post';
		$filter_fields = ! empty( $settings['filter_fields'] ) ? $settings['filter_fields']                        : array();
		$delay_load    = ! empty( $settings['delay_load'] )    ? intval( $settings['delay_load'] )                 : 300;
		$direction     = ! empty( $settings['filters_direction'] ) ? $settings['filters_direction']                : 'row';

		$filter_data = array(
			'connection_id' => $connection_id,
			'post_type'     => $post_type,
			'delay'         => $delay_load,
			'ajax_url'      => admin_url( 'admin-ajax.php' ),
			'nonce'         => wp_create_nonce( 'captwiki_search_filter_nonce' ),
		);

		echo '<div class="cw-search-filter cw-filter-dir-' . esc_attr( $direction ) . '" data-filter-settings=\'' . wp_json_encode( $filter_data ) . '\'>';
			echo '<div class="cw-filter-wrap cw-flex cw-flex-dir-' . esc_attr( $direction ) . '">';

				foreach ( $filter_fields as $field ) {
					$this->render_filter_field( $field, $connection_id );
				}

			echo '</div>';
		echo '</div>';
	}

	/**
	 * Dispatch render to correct sub-method by filter_type.
	 */
	protected function render_filter_field( array $field, string $connection_id ) {
		$type  = ! empty( $field['filter_type'] ) ? $field['filter_type'] : 'search';
		$label = ! empty( $field['field_label'] ) ? $field['field_label'] : '';

		echo '<div class="cw-filter-field cw-filter-field--' . esc_attr( $type ) . '">';

			if ( ! empty( $label ) && ! in_array( $type, array( 'results_count', 'reset' ), true ) ) {
				echo '<span class="cw-filter-label">' . esc_html( $label ) . '</span>';
			}

			switch ( $type ) {
				case 'search':
					$this->render_search_field( $field, $connection_id );
					break;
				case 'checkbox':
					$this->render_checkbox_field( $field, $connection_id );
					break;
				case 'radio':
					$this->render_radio_field( $field, $connection_id );
					break;
				case 'select':
					$this->render_select_field( $field, $connection_id );
					break;
				case 'results_count':
					$this->render_results_count( $field, $connection_id );
					break;
				case 'reset':
					$this->render_reset_btn( $field, $connection_id );
					break;
			}

		echo '</div>';
	}

	// ── Text Search ───────────────────────────────────────────────────────────
	protected function render_search_field( array $field, string $connection_id ) {
		$placeholder = ! empty( $field['search_placeholder'] ) ? $field['search_placeholder'] : esc_html__( 'Search...', 'captain-widgets-kit' );

		echo '<div class="cw-filter-search-wrap">';
			echo '<input type="text" class="cw-filter-search-input"'
				. ' placeholder="' . esc_attr( $placeholder ) . '"'
				. ' data-type="search"'
				. ' data-connection="' . esc_attr( $connection_id ) . '"'
				. ' autocomplete="off"'
				. ' aria-label="' . esc_attr( $placeholder ) . '" />';
			echo '<span class="cw-filter-search-icon" aria-hidden="true">'
				. '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
				. '</span>';
		echo '</div>';
	}

	// ── Checkbox ──────────────────────────────────────────────────────────────
	protected function render_checkbox_field( array $field, string $connection_id ) {
		$taxonomy   = ! empty( $field['taxonomy'] ) ? $field['taxonomy'] : '';
		$show_count = ! empty( $field['show_count'] ) && 'yes' === $field['show_count'];

		if ( empty( $taxonomy ) ) { return; }
		$terms = get_terms( array( 'taxonomy' => $taxonomy, 'hide_empty' => true ) );
		if ( is_wp_error( $terms ) || empty( $terms ) ) { return; }

		echo '<div class="cw-filter-checkbox-wrap" data-type="checkbox" data-taxonomy="' . esc_attr( $taxonomy ) . '" data-connection="' . esc_attr( $connection_id ) . '">';
		foreach ( $terms as $term ) {
			$id = 'cwk-chk-' . esc_attr( $taxonomy ) . '-' . esc_attr( $term->term_id );
			echo '<div class="cw-filter-checkbox">';
				echo '<input type="checkbox" id="' . esc_attr( $id ) . '" name="' . esc_attr( $taxonomy ) . '[]" value="' . esc_attr( $term->slug ) . '" />';
				echo '<label for="' . esc_attr( $id ) . '">';
					echo '<span class="cw-check-icon" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg></span>';
					echo '<span class="cw-filter-item-name">' . esc_html( $term->name ) . '</span>';
					if ( $show_count ) { echo '<span class="cw-filter-count">(' . absint( $term->count ) . ')</span>'; }
				echo '</label>';
			echo '</div>';
		}
		echo '</div>';
	}

	// ── Radio ─────────────────────────────────────────────────────────────────
	protected function render_radio_field( array $field, string $connection_id ) {
		$taxonomy   = ! empty( $field['taxonomy'] ) ? $field['taxonomy'] : '';
		$show_count = ! empty( $field['show_count'] ) && 'yes' === $field['show_count'];
		$show_all   = ! empty( $field['show_all_option'] ) && 'yes' === $field['show_all_option'];

		if ( empty( $taxonomy ) ) { return; }
		$terms = get_terms( array( 'taxonomy' => $taxonomy, 'hide_empty' => true ) );
		if ( is_wp_error( $terms ) || empty( $terms ) ) { return; }

		$group = 'cwk-radio-' . esc_attr( $taxonomy ) . '-' . uniqid();

		echo '<div class="cw-filter-radio-wrap" data-type="radio" data-taxonomy="' . esc_attr( $taxonomy ) . '" data-connection="' . esc_attr( $connection_id ) . '">';

		if ( $show_all ) {
			$all_id = $group . '-all';
			echo '<div class="cw-filter-radio">';
				echo '<input type="radio" id="' . esc_attr( $all_id ) . '" name="' . esc_attr( $group ) . '" value="" checked="checked" />';
				echo '<label for="' . esc_attr( $all_id ) . '"><span class="cw-radio-icon"><span class="cw-radio-dot"></span></span><span class="cw-filter-item-name">' . esc_html__( 'All', 'captain-widgets-kit' ) . '</span></label>';
			echo '</div>';
		}

		foreach ( $terms as $term ) {
			$id = $group . '-' . esc_attr( $term->term_id );
			echo '<div class="cw-filter-radio">';
				echo '<input type="radio" id="' . esc_attr( $id ) . '" name="' . esc_attr( $group ) . '" value="' . esc_attr( $term->slug ) . '" />';
				echo '<label for="' . esc_attr( $id ) . '">';
					echo '<span class="cw-radio-icon"><span class="cw-radio-dot"></span></span>';
					echo '<span class="cw-filter-item-name">' . esc_html( $term->name ) . '</span>';
					if ( $show_count ) { echo '<span class="cw-filter-count">(' . absint( $term->count ) . ')</span>'; }
				echo '</label>';
			echo '</div>';
		}
		echo '</div>';
	}

	// ── Select ────────────────────────────────────────────────────────────────
	protected function render_select_field( array $field, string $connection_id ) {
		$taxonomy   = ! empty( $field['taxonomy'] ) ? $field['taxonomy'] : '';
		$show_count = ! empty( $field['show_count'] ) && 'yes' === $field['show_count'];
		$show_all   = ! empty( $field['show_all_option'] ) && 'yes' === $field['show_all_option'];

		if ( empty( $taxonomy ) ) { return; }
		$terms = get_terms( array( 'taxonomy' => $taxonomy, 'hide_empty' => true ) );
		if ( is_wp_error( $terms ) || empty( $terms ) ) { return; }

		echo '<div class="cw-filter-select-wrap" data-type="select" data-taxonomy="' . esc_attr( $taxonomy ) . '" data-connection="' . esc_attr( $connection_id ) . '">';
			echo '<select class="cw-filter-select" data-connection="' . esc_attr( $connection_id ) . '">';
			if ( $show_all ) { echo '<option value="">' . esc_html__( 'All', 'captain-widgets-kit' ) . '</option>'; }
			foreach ( $terms as $term ) {
				$label = $show_count ? $term->name . ' (' . absint( $term->count ) . ')' : $term->name;
				echo '<option value="' . esc_attr( $term->slug ) . '">' . esc_html( $label ) . '</option>';
			}
			echo '</select>';
		echo '</div>';
	}

	// ── Results Count ─────────────────────────────────────────────────────────
	protected function render_results_count( array $field, string $connection_id ) {
		$text = ! empty( $field['results_text'] )
			? $field['results_text']
			: esc_html__( 'Showing {visible} of {total} results', 'captain-widgets-kit' );

		// Build the display template:
		// Replace {visible} and {total} with <span> placeholders JS will update.
		$display = str_replace(
			array( '{visible}', '{total}' ),
			array(
				'<span class="cw-count-num cw-count-visible">–</span>',
				'<span class="cw-count-num cw-count-total">–</span>',
			),
			esc_html( $text )
		);

		echo '<div class="cw-filter-results-count"'
			. ' data-type="results_count"'
			. ' data-connection="' . esc_attr( $connection_id ) . '"'
			. ' data-template="' . esc_attr( $text ) . '"'
			. ' aria-live="polite">';
			echo $display; // phpcs:ignore WordPress.Security.EscapeOutput — already escaped above
		echo '</div>';
	}

	// ── Reset Button ─────────────────────────────────────────────────────────
	protected function render_reset_btn( array $field, string $connection_id ) {
		$btn_text     = ! empty( $field['reset_text'] )         ? $field['reset_text']         : esc_html__( 'Reset all', 'captain-widgets-kit' );
		$is_fixed     = ! empty( $field['reset_fixed'] )        && 'yes' === $field['reset_fixed'];
		$tag_position = ! empty( $field['reset_tag_position'] ) ? $field['reset_tag_position'] : 'end';

		$wrap_class = 'cw-filter-reset-wrap';
		if ( $is_fixed ) { $wrap_class .= ' cw-filter-reset-wrap--fixed'; }

		echo '<div class="' . esc_attr( $wrap_class ) . '"'
			. ' data-type="reset"'
			. ' data-connection="' . esc_attr( $connection_id ) . '"'
			. ' data-tag-position="' . esc_attr( $tag_position ) . '">';

			if ( 'start' === $tag_position ) {
				echo '<div class="cw-filter-active-tags" data-connection="' . esc_attr( $connection_id ) . '"></div>';
			}

			echo '<button class="cw-filter-reset-btn" type="button"'
				. ' data-connection="' . esc_attr( $connection_id ) . '"'
				. ' aria-label="' . esc_attr( $btn_text ) . '">';
				echo esc_html( $btn_text );
			echo '</button>';

			if ( 'end' === $tag_position ) {
				echo '<div class="cw-filter-active-tags" data-connection="' . esc_attr( $connection_id ) . '"></div>';
			}

		echo '</div>';
	}

	// =========================================================================
	// HELPERS
	// =========================================================================
	protected function captwiki_get_post_types(): array {
		$types   = get_post_types( array( 'public' => true, 'show_ui' => true ), 'objects' );
		$exclude = array( 'elementor_library', 'attachment' );
		$options = array();
		foreach ( $types as $type ) {
			if ( ! in_array( $type->name, $exclude, true ) ) {
				$options[ $type->name ] = $type->label;
			}
		}
		return $options;
	}

	protected function captwiki_get_taxonomies(): array {
		$taxes   = get_taxonomies( array( 'public' => true ), 'objects' );
		$exclude = array( 'post_format' );
		$options = array( '' => esc_html__( '— Select Taxonomy —', 'captain-widgets-kit' ) );
		foreach ( $taxes as $tax ) {
			if ( ! in_array( $tax->name, $exclude, true ) ) {
				$options[ $tax->name ] = $tax->label;
			}
		}
		return $options;
	}
}
