/**
 * CaptWiki Search Filter — Frontend Handler
 *
 * Features:
 *  - Text Search (debounced)
 *  - Checkbox / Radio / Select (taxonomy filter)
 *  - Results Count  → updates {visible} and {total} after every AJAX call
 *  - Reset Button   → clears all filters, resets count, removes active tags
 *  - Active Filter Tags → shown beside reset button
 *
 * Connection model:
 *  All widgets (filter, reset, count) sharing the same connection_id
 *  are automatically linked — they can be in separate Elementor widgets.
 *
 * @since   1.2.0
 * @package captain-widgets-kit
 */

( function ( $ ) {
	'use strict';

	/* ====================================================================
	   Utility: debounce
	   ==================================================================== */
	function debounce( fn, wait ) {
		var timer;
		return function () {
			var ctx = this, args = arguments;
			clearTimeout( timer );
			timer = setTimeout( function () { fn.apply( ctx, args ); }, wait );
		};
	}

	/* ====================================================================
	   Config: get filter widget settings for a connection_id
	   ==================================================================== */
	function getFilterConfig( connectionId ) {
		var config = {
			ajax_url:      '',
			nonce:         '',
			post_type:     'post',
			delay:         300,
			connection_id: connectionId,
		};

		$( '.cw-search-filter' ).each( function () {
			var raw = $( this ).data( 'filter-settings' );
			if ( typeof raw === 'string' ) { try { raw = JSON.parse( raw ); } catch(e) { raw = null; } }
			if ( raw && raw.connection_id === connectionId ) {
				$.extend( config, raw );
				return false; // break
			}
		} );

		return config;
	}

	/* ====================================================================
	   Collect: gather all active filter values for a connection_id
	   Looks across ALL .cw-search-filter widgets sharing that id.
	   ==================================================================== */
	function collectFilterState( connectionId ) {
		var state = { search: '', taxonomies: [] };

		$( '.cw-search-filter' ).filter( function () {
			var raw = $( this ).data( 'filter-settings' );
			if ( typeof raw === 'string' ) { try { raw = JSON.parse( raw ); } catch(e) { raw = null; } }
			return raw && raw.connection_id === connectionId;
		} ).each( function () {
			var $w = $( this );

			// Text search
			$w.find( '.cw-filter-search-input' ).each( function () {
				var v = $( this ).val().trim();
				if ( v ) { state.search = v; }
			} );

			// Checkbox
			$w.find( '.cw-filter-checkbox-wrap' ).each( function () {
				var $box  = $( this );
				var tax   = $box.data( 'taxonomy' );
				var terms = [];
				$box.find( 'input[type="checkbox"]:checked' ).each( function () {
					terms.push( $( this ).val() );
				} );
				if ( tax && terms.length ) {
					state.taxonomies.push( { taxonomy: tax, terms: terms } );
				}
			} );

			// Radio
			$w.find( '.cw-filter-radio-wrap' ).each( function () {
				var $box = $( this );
				var tax  = $box.data( 'taxonomy' );
				var val  = $box.find( 'input[type="radio"]:checked' ).val();
				if ( tax && val ) {
					state.taxonomies.push( { taxonomy: tax, terms: [ val ] } );
				}
			} );

			// Select
			$w.find( '.cw-filter-select-wrap select' ).each( function () {
				var $sel = $( this );
				var tax  = $sel.closest( '.cw-filter-select-wrap' ).data( 'taxonomy' );
				var val  = $sel.val();
				if ( tax && val ) {
					state.taxonomies.push( { taxonomy: tax, terms: [ val ] } );
				}
			} );
		} );

		return state;
	}

	/* ====================================================================
	   Listing: get data-widget-settings from the connected listing widget
	   ==================================================================== */
	function getListingSettings( connectionId ) {
		var $listing = $( '#' + connectionId );
		if ( ! $listing.length ) { return {}; }
		var raw = $listing.data( 'widget-settings' );
		if ( typeof raw === 'string' ) { try { raw = JSON.parse( raw ); } catch(e) { raw = {}; } }
		return raw || {};
	}

	/* ====================================================================
	   Loading state on the listing widget
	   ==================================================================== */
	function setLoading( connectionId, isLoading ) {
		var $listing = $( '#' + connectionId );
		if ( ! $listing.length ) { return; }

		if ( isLoading ) {
			$listing.addClass( 'cwk-filter-loading' );
			if ( ! $listing.find( '.cwk-filter-spinner' ).length ) {
				$listing.prepend(
					'<div class="cwk-filter-spinner" aria-hidden="true">' +
					'<span></span><span></span><span></span>' +
					'</div>'
				);
			}
		} else {
			$listing.removeClass( 'cwk-filter-loading' );
			$listing.find( '.cwk-filter-spinner' ).remove();
		}
	}

	/* ====================================================================
	   Results Count: update all count bars for this connection_id
	   Looks across the WHOLE document — count widget can be anywhere.
	   ==================================================================== */
	function updateResultsCount( connectionId, visible, total ) {
		$( '.cw-filter-results-count[data-connection="' + connectionId + '"]' ).each( function () {
			var $el       = $( this );
			var template  = $el.data( 'template' ) || 'Showing {visible} of {total} results';

			var html = esc( template )
				.replace(
					esc( '{visible}' ),
					'<span class="cw-count-num cw-count-visible">' + parseInt( visible, 10 ) + '</span>'
				)
				.replace(
					esc( '{total}' ),
					'<span class="cw-count-num cw-count-total">' + parseInt( total, 10 ) + '</span>'
				);

			$el.html( html );
		} );
	}

	/* Minimal HTML escape for the template string before injection */
	function esc( str ) {
		return str
			.replace( /&/g,  '&amp;' )
			.replace( /</g,  '&lt;' )
			.replace( />/g,  '&gt;' )
			.replace( /"/g,  '&quot;' )
			.replace( /'/g,  '&#039;' );
	}

	/* ====================================================================
	   Active Filter Tags: build tag list beside reset button
	   ==================================================================== */
	function updateActiveTags( connectionId ) {
		var $tagContainers = $( '.cw-filter-active-tags[data-connection="' + connectionId + '"]' );
		if ( ! $tagContainers.length ) { return; }

		var tags = [];

		// Search tag
		$( '.cw-filter-search-input[data-connection="' + connectionId + '"]' ).each( function () {
			var v = $( this ).val().trim();
			if ( v ) { tags.push( { label: v, type: 'search' } ); }
		} );

		// Taxonomy tags — checkboxes
		$( '.cw-filter-checkbox-wrap[data-connection="' + connectionId + '"] input:checked' ).each( function () {
			tags.push( { label: $( this ).next( 'label' ).find( '.cw-filter-item-name' ).text().trim(), type: 'tax' } );
		} );

		// Taxonomy tags — radio (not "All")
		$( '.cw-filter-radio-wrap[data-connection="' + connectionId + '"] input:checked' ).each( function () {
			var val = $( this ).val();
			if ( val ) {
				tags.push( { label: $( this ).next( 'label' ).find( '.cw-filter-item-name' ).text().trim(), type: 'tax' } );
			}
		} );

		// Taxonomy tags — select
		$( '.cw-filter-select-wrap select[data-connection="' + connectionId + '"]' ).each( function () {
			var val = $( this ).val();
			if ( val ) {
				tags.push( { label: $( this ).find( 'option:selected' ).text().trim(), type: 'tax' } );
			}
		} );

		// Render tags HTML
		var html = '';
		$.each( tags, function ( i, tag ) {
			html += '<span class="cw-filter-active-tag">' + $( '<span>' ).text( tag.label ).html() + '</span>';
		} );

		$tagContainers.html( html );
	}

	/* ====================================================================
	   Core: fire AJAX filter request
	   ==================================================================== */
	function doFilter( connectionId ) {
		var config          = getFilterConfig( connectionId );
		var filterState     = collectFilterState( connectionId );
		var listingSettings = getListingSettings( connectionId );

		if ( ! config.ajax_url || ! config.nonce ) { return; }

		setLoading( connectionId, true );
		updateActiveTags( connectionId );

		$.ajax( {
			url:  config.ajax_url,
			type: 'POST',
			data: {
				action:          'captwiki_search_filter',
				nonce:           config.nonce,
				post_type:       listingSettings.post_type  || config.post_type,
				search:          filterState.search,
				taxonomies:      filterState.taxonomies,
				posts_per_page:  listingSettings.display_number || 8,
				orderby:         listingSettings.orderby || 'date',
				order:           listingSettings.order   || 'DESC',
				offset:          listingSettings.offset  || 0,
				widget_settings: listingSettings,
			},
			success: function ( response ) {
				setLoading( connectionId, false );
				if ( ! response.success ) { return; }

				var data     = response.data;
				var $listing = $( '#' + connectionId );
				var $row     = $listing.find( '.dp-row' );

				// Replace post grid content
				if ( $row.length ) {
					$row.html( data.html );
				} else {
					$listing.html( data.html );
				}

				// Update results count bar(s)
				updateResultsCount( connectionId, data.found, data.total );

				// Fire custom event for other scripts (text-limit, isotope, etc.)
				$listing.trigger( 'cwk:filter:done', [ data ] );

				// Re-trigger Elementor frontend handlers on newly injected HTML
				if ( typeof elementorFrontend !== 'undefined' ) {
					elementorFrontend.elementsHandler.runReadyTrigger( $listing );
				}
			},
			error: function () {
				setLoading( connectionId, false );
			},
		} );
	}

	/* ====================================================================
	   Reset: clear all filter inputs for a connection_id
	   Works across ALL widgets sharing the same connection_id.
	   ==================================================================== */
	function doReset( connectionId ) {
		// Clear search inputs
		$( '.cw-filter-search-input[data-connection="' + connectionId + '"]' ).val( '' );

		// Uncheck all checkboxes in filter widgets
		$( '.cw-filter-checkbox-wrap[data-connection="' + connectionId + '"] input[type="checkbox"]' ).prop( 'checked', false );

		// Reset radios — check the first one (usually "All")
		$( '.cw-filter-radio-wrap[data-connection="' + connectionId + '"] input[type="radio"]' ).each( function () {
			$( this ).prop( 'checked', $( this ).val() === '' );
		} );

		// Reset selects
		$( '.cw-filter-select-wrap select[data-connection="' + connectionId + '"]' ).val( '' );

		// Clear active tags immediately
		$( '.cw-filter-active-tags[data-connection="' + connectionId + '"]' ).html( '' );

		// Reset count display to dashes
		$( '.cw-filter-results-count[data-connection="' + connectionId + '"]' ).each( function () {
			var $el      = $( this );
			var template = $el.data( 'template' ) || 'Showing {visible} of {total} results';
			var html = esc( template )
				.replace( esc( '{visible}' ), '<span class="cw-count-num cw-count-visible">–</span>' )
				.replace( esc( '{total}' ),   '<span class="cw-count-num cw-count-total">–</span>' );
			$el.html( html );
		} );

		// Fire filter with empty state → returns all posts
		doFilter( connectionId );
	}

	/* ====================================================================
	   Bind: attach events to a single .cw-search-filter widget scope
	   ==================================================================== */
	function bindFilterWidget( $scope ) {
		var $widget = $scope.find( '.cw-search-filter' );
		if ( ! $widget.length ) { return; }

		var raw = $widget.data( 'filter-settings' );
		if ( typeof raw === 'string' ) { try { raw = JSON.parse( raw ); } catch(e) { raw = null; } }
		if ( ! raw || ! raw.connection_id ) { return; }

		var connectionId    = raw.connection_id;
		var delay           = raw.delay || 300;
		var debouncedFilter = debounce( function () { doFilter( connectionId ); }, delay );

		// Text search — debounced
		$widget.on( 'input', '.cw-filter-search-input', function () {
			debouncedFilter();
		} );

		// Checkbox — immediate
		$widget.on( 'change', '.cw-filter-checkbox-wrap input[type="checkbox"]', function () {
			doFilter( connectionId );
		} );

		// Radio — immediate
		$widget.on( 'change', '.cw-filter-radio-wrap input[type="radio"]', function () {
			doFilter( connectionId );
		} );

		// Select — immediate
		$widget.on( 'change', '.cw-filter-select-wrap select', function () {
			doFilter( connectionId );
		} );

		// Reset button — inside same widget
		$widget.on( 'click', '.cw-filter-reset-btn', function () {
			doReset( connectionId );
		} );
	}

	/* ====================================================================
	   Global delegation for reset buttons placed in SEPARATE widgets
	   (outside .cw-search-filter scope — e.g. a standalone reset widget)
	   ==================================================================== */
	$( document ).on( 'click', '.cw-filter-reset-btn', function () {
		var connectionId = $( this ).data( 'connection' );
		if ( connectionId ) { doReset( connectionId ); }
	} );

	/* ====================================================================
	   Elementor frontend init — bind each widget on ready
	   ==================================================================== */
	window.addEventListener( 'elementor/frontend/init', function () {
		elementorFrontend.hooks.addAction(
			'frontend/element_ready/captwiki-search-filter.default',
			bindFilterWidget
		);
	} );

} )( jQuery );
