<?php

namespace MyListing\Elementor\Widgets;

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

class Listing_Feed extends \Elementor\Widget_Base {

	public function get_name() {
		return 'case27-listing-feed-widget';
	}

	public function get_title() {
		return __( '<strong>27</strong> > Listing Feed', 'my-listing' );
	}

	public function get_icon() {
		return 'eicon-posts-grid';
	}

	protected function _register_controls() {
		$this->start_controls_section( 'the_listing_feed', [
			'label' => __( 'Listing Feed', 'my-listing' ),
		] );

		$this->add_control( 'the_template', [
			'label' => __( 'Template', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT,
			'default' => 'grid',
			'options' => [
				'grid' => __( 'Grid', 'my-listing' ),
				'carousel' => __( 'Carousel', 'my-listing' ),
			],
		] );

		$this->add_control( 'posts_per_page', [
			'label'   => __( 'Number of items to show', 'my-listing' ),
			'type'    => \Elementor\Controls_Manager::NUMBER,
			'default' => 6,
		] );

		$this->add_control( 'query_method', [
			'label' => _x( 'Find listings using:', 'Elementor > Listing Feed > Widget Settings', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT,
			'default' => 'filters',
			'options' => [
				'filters' => _x( 'Filters', 'Elementor > Listing Feed > Widget Settings', 'my-listing' ),
				'query_string' => _x( 'Explore page query URL', 'Elementor > Listing Feed > Widget Settings', 'my-listing' ),
			],
		] );

		$this->add_control( 'select_categories', [
			'label' => __( 'Filter by Categories', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT2,
			'options' => c27()->get_terms_dropdown_array( [
				'taxonomy' => 'job_listing_category',
				'hide_empty' => false,
			] ),
			'multiple' => true,
			'label_block' => true,
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'select_regions', [
			'label' => __( 'Filter by Regions', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT2,
			'options' => c27()->get_terms_dropdown_array( [
				'taxonomy' => 'region',
				'hide_empty' => false,
			] ),
			'multiple' => true,
			'label_block' => true,
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'select_tags', [
			'label' => __( 'Filter by Tags', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT2,
			'options' => c27()->get_terms_dropdown_array( [
				'taxonomy' => 'case27_job_listing_tags',
				'hide_empty' => false,
			] ),
			'multiple' => true,
			'label_block' => true,
			'condition' => ['query_method' => 'filters'],
		] );

		$taxonomy_list = mylisting_custom_taxonomies();

		foreach ( $taxonomy_list as $slug => $label ) {
			$this->add_control( 'select_'.$slug, [
				'label' => sprintf( '%s %s', __( 'Filter by', 'my-listing' ), $label ),
				'type' => \Elementor\Controls_Manager::SELECT2,
				'options' => c27()->get_terms_dropdown_array( [
					'taxonomy' => $slug,
					'hide_empty' => false,
				] ),
				'multiple' => true,
				'label_block' => true,
				'condition' => ['query_method' => 'filters'],
			] );
		}

		$this->add_control( 'select_listing_types', [
			'label' => __( 'Filter by Listing Type(s).', 'my-listing' ),
			'type' => 'mylisting-posts-dropdown',
			'multiple' => true,
			'label_block' => true,
			'post_type' => 'case27_listing_type',
			'post_key' => 'slug',
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'priority_levels', [
			'label' => __( 'Filter by Priority', 'my-listing' ),
			'description' => __( 'Leave blank to include all priority levels', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT2,
			'options' => [
				'normal' => 'Normal',
				'featured' => 'Featured',
				'promoted' => 'Promoted',
				'custom' => 'Custom',
			],
			'multiple' => true,
			'label_block' => true,
			'condition' => ['query_method' => 'filters'],
		] );

		$listings = \MyListing\get_posts_dropdown( 'job_listing' );
		$this->add_control( 'select_listings', [
			'label' => __( 'Or select a list of listings.', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::REPEATER,
			'fields' => [[
				'name' => 'listing_id',
				'label' => is_array( $listings )
					? __( 'Select listing', 'my-listing' )
					: _x( 'Enter listing ID', 'Elementor/Listing Feed: Select a listing', 'my-listing' ),
				'type' => is_array( $listings )
					? \Elementor\Controls_Manager::SELECT2
					: \Elementor\Controls_Manager::TEXT,
				'options' => $listings,
				'default' => '',
				'label_block' => true,
			]],
			'title_field' => 'Listing ID: {{{ listing_id }}}',
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'order_by', [
			'label' => __( 'Order by', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT,
			'default' => 'date',
			'options' => [
				'date' => __( 'Date', 'my-listing' ),
				'post__in' => __( 'Included order', 'my-listing' ),
				'_case27_average_rating' => __( 'Rating', 'my-listing' ),
				'rand' => __( 'Random', 'my-listing' ),
				'modified' => __( 'Last modified date', 'my-listing' ),
			],
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'order', [
			'label' => __( 'Order', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SELECT,
			'default' => 'DESC',
			'options' => [
				'ASC' => __( 'Ascending', 'my-listing' ),
				'DESC' => __( 'Descending', 'my-listing' ),
			],
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'behavior', [
			'label' => __( 'Order by priority first?', 'my-listing' ),
			'description' => __( 'If selected, listings will first be ordered based on their priority, then based on the "Order By" setting above.', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SWITCHER,
			'default' => 'yes',
			'label_on' => __( 'Yes', 'my-listing' ),
			'label_off' => __( 'No', 'my-listing' ),
			'return_value' => 'yes',
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'query_string', [
			'label' => __( 'Paste the URL here', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::TEXT,
			'default' => '',
			'label_block' => true,
			'placeholder' => home_url( '/explore?type=events&sort=latest' ),
			'description' => 'In Explore page, you can filter results the way you want, grab the generated URL from the address bar, and paste it here, to get that exact list of listings.',
			'condition' => ['query_method' => 'query_string'],
		] );

		$this->add_control( 'show_promoted_badge', [
			'label' => __( 'Show badge for featured/promoted listings?', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SWITCHER,
			'default' => 'yes',
			'label_on' => __( 'Yes', 'my-listing' ),
			'label_off' => __( 'No', 'my-listing' ),
			'return_value' => 'yes',
			'condition' => ['query_method' => 'filters'],
		] );

		$this->add_control( 'invert_nav_color', [
			'label' => __( 'Invert nav color?', 'my-listing' ),
			'description' => __( 'Use this option on dark section backgrounds for better visibility.', 'my-listing' ),
			'type' => \Elementor\Controls_Manager::SWITCHER,
			'default' => '',
			'label_on' => __( 'Yes', 'my-listing' ),
			'label_off' => __( 'No', 'my-listing' ),
			'return_value' => 'yes',
			'condition' => ['the_template' => 'carousel'],
		] );

		$this->add_control( 'cache_for', [
			'label' => __( 'Cache results for (in minutes)', 'my-listing' ),
			'description' => 'Set how long the listing feed results cache should be used before it is regenerated. Set to "0" to disable.',
			'type' => \Elementor\Controls_Manager::NUMBER,
			'min' => 0,
			'default' => 720, // 12 hours
		] );

		\MyListing\Elementor\apply_column_count_controls(
			$this,
			'column_count',
			__( 'Column count', 'my-listing' ),
			[
				'heading' => ['condition' => ['the_template' => ['grid', 'fluid-grid']]],
				'general' => [
					'condition' => ['the_template' => ['grid', 'fluid-grid']],
					'min' => 1,
					'max' => 4,
				],
				'lg' => ['default' => 3], 'md' => ['default' => 3],
				'sm' => ['default' => 2], 'xs' => ['default' => 1],
			]
		);

		$this->end_controls_section();
	}

	protected function render( $instance = [] ) {
		// $this->get_id() can be the same for widgets in different pages,
		// usually when pages are duplicated; to avoid them also sharing the
		// same cache key, the current page ID is appended to the key.
		$cache_key = sprintf(
			'mylisting_feed_cache_%s_%s',
			$this->get_id(),
			get_queried_object_id()
		);
		$cache_for = $this->get_settings( 'cache_for' );
		$cached_value = get_transient( $cache_key );
		$listing_ids = [];

		if ( \MyListing\Elementor\is_edit_mode() ) {
			if ( $cache_for > 0 ) {
				delete_transient( $cache_key );
			}

			$query = $this->get_listings_query();
			if ( $query instanceof \WP_Query ) {
				$listing_ids = $query->posts;
			}
		} elseif ( is_array( $cached_value ) && $cache_for > 0 ) {
			$listing_ids = $cached_value;
		} else {
			$query = $this->get_listings_query();
			if ( $query instanceof \WP_Query ) {
				$listing_ids = $query->posts;

				if ( $cache_for > 0 ) {
					set_transient( $cache_key, $listing_ids, $cache_for * 60 );
				}
			}
		}

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

		$template = $this->get_settings('the_template');
		$invert_nav = $this->get_settings('invert_nav_color') === 'yes';
		$hide_priority = $this->get_settings('show_promoted_badge') !== 'yes';
		$listing_wrap = sprintf(
			'col-lg-%1$d col-md-%2$d col-sm-%3$d col-xs-%4$d grid-item',
			12 / absint( $this->get_settings('column_count__lg') ),
			12 / absint( $this->get_settings('column_count__md') ),
			12 / absint( $this->get_settings('column_count__sm') ),
			12 / $this->get_settings('column_count__xs')
		);

		require locate_template( 'templates/widgets/listing-feed.php' );

		if ( \MyListing\Elementor\is_edit_mode() ) {
			printf(
				'<script type="text/javascript">%s</script>',
				'case27_ready_script(jQuery);'
			);
		}
	}

	protected function content_template() {}
	public function render_plain_content() {}

	protected function get_listings_query() {
		// handle find listings using explore page query url
		if ( $this->get_settings('query_method') === 'query_string' ) {
			if ( ! ( $query_string = parse_url( $this->get_settings('query_string'), PHP_URL_QUERY ) ) ) {
				return false;
			}

			if ( ! ( $query_args = wp_parse_args( $query_string ) ) ) {
				return false;
			}

			// 'pg' param must be converted to 'page'
			if ( ! empty( $query_args['pg'] ) ) {
				$query_args['page'] = max( 0, absint( $query_args['pg'] ) - 1 );
			}

			$query = \MyListing\Src\Queries\Explore_Listings::instance()->run( [
				'listing_type' => ! empty( $query_args['type'] ) ? $query_args['type'] : false,
				'form_data' => c27()->merge_options( [
					'per_page' => $this->get_settings('posts_per_page'),
				], (array) $query_args ),
				'return_query' => true,
			] );

			if ( ! $query instanceof \WP_Query ) {
				return false;
			}

			return $query;
		}

		// handle regular filter query
		$args = [
			'post_type' => 'job_listing',
			'post_status' => 'publish',
			'posts_per_page' => $this->get_settings('posts_per_page'),
			'ignore_sticky_posts' => false,
			'meta_query' => [],
			'tax_query' => [],
			'fields' => 'ids',
		];

		// filter by selected categories
		if ( $this->get_settings('select_categories') ) {
			$args['tax_query'][] = [
				'taxonomy' => 'job_listing_category',
				'terms' => $this->get_settings('select_categories'),
				'field' => 'term_id',
			];
		}

		// filter by selected regions
		if ( $this->get_settings('select_regions') ) {
			$args['tax_query'][] = [
				'taxonomy' => 'region',
				'terms' => $this->get_settings('select_regions'),
				'field' => 'term_id',
			];
		}

		// filter by selected tags
		if ( $this->get_settings('select_tags') ) {
			$args['tax_query'][] = [
				'taxonomy' => 'case27_job_listing_tags',
				'terms' => $this->get_settings('select_tags'),
				'field' => 'term_id',
			];
		}

		// filter by selected custom taxonomies
		$taxonomy_list = mylisting_custom_taxonomies();
		foreach ( $taxonomy_list as $slug => $label ) {
			if ( ! empty( $this->get_settings( 'select_'.$slug ) ) ) {
				$args['tax_query'][] = [
					'taxonomy' => $slug,
					'terms' => $this->get_settings( 'select_'.$slug ),
					'field' => 'term_id',
				];
			}
		}

		// handle "select a list of listings" setting
		$include_ids = array_filter( array_map( 'absint', array_column(
			(array) $this->get_settings('select_listings'),
			'listing_id'
		) ) );

		if ( ! empty( $include_ids ) ) {
			$args['post__in'] = $include_ids;
		}

		// filter by the listing type
		if ( $this->get_settings('select_listing_types') ) {
			$args['meta_query']['c27_listing_type_clause'] = [
				'key' => '_case27_listing_type',
				'value' => $this->get_settings('select_listing_types'),
				'compare' => 'IN',
			];
		}

		$orderby = $this->get_settings('order_by');
		$explore_query = \MyListing\Src\Queries\Explore_Listings::instance();
		if ( $orderby ) {
			if ( $orderby === '_case27_average_rating' ) {
				add_filter( 'posts_join', [ $explore_query, 'rating_field_join' ], 35, 2 );
				add_filter( 'posts_orderby', [ $explore_query, 'rating_field_orderby' ], 35, 2 );
				$args['orderby'] = [];
			} else {
				$args['orderby'] = $orderby;
			}
		}

		$args['order'] = $this->get_settings('order') === 'ASC' ? 'ASC' : 'DESC';

		// prevent duplicates
		add_filter( 'posts_distinct', [ $explore_query, 'prevent_duplicates' ], 30, 2 );

		// join priority meta
		add_filter( 'posts_join', [ $explore_query, 'priority_field_join' ], 30, 2 );

		// set which priority levels to include
		$priority_levels = array_filter( (array) $this->get_settings( 'priority_levels' ) );
		$priority_field_where = function( $where, $query ) use ( $priority_levels ) {
			global $wpdb;

			$levels = [];
			if ( in_array( 'normal', $priority_levels ) ) { $levels[] = 0; }
			if ( in_array( 'featured', $priority_levels ) ) { $levels[] = 1; }
			if ( in_array( 'promoted', $priority_levels ) ) { $levels[] = 2; }

			// all priority levels are included
			if ( count( $priority_levels ) === 0 || count( $priority_levels ) === 4 ) {
				return $where;
			}

			// handle levels 0,1,2
			$where .= sprintf( ' AND ( priority_meta.meta_value IN (%s)', join( ',', $levels ) );

			// handle levels 3+
			if ( in_array( 'custom', $priority_levels ) ) {
				$where .= ' OR priority_meta.meta_value > 2 ';
			}
			$where .= ' ) ';

			return $where;
		};

		add_filter( 'posts_where', $priority_field_where, 30, 2 );

		// order by priority
		$order_by_priority = (bool) $this->get_settings( 'behavior' );
		if ( $order_by_priority === true ) {
			$args['suppress_filters'] = false;
			add_filter( 'posts_orderby', [ $explore_query, 'priority_field_orderby' ], 30, 2 );
		}

		$query = new \WP_Query( apply_filters( 'mylisting/sections/listing-feed/args', $args ) );

		remove_filter( 'posts_join', [ $explore_query, 'priority_field_join' ], 30 );
		remove_filter( 'posts_orderby', [ $explore_query, 'priority_field_orderby' ], 30 );
		remove_filter( 'posts_where', $priority_field_where, 30 );
		remove_filter( 'posts_join', [ $explore_query, 'rating_field_join' ], 35 );
		remove_filter( 'posts_orderby', [ $explore_query, 'rating_field_orderby' ], 35 );
		remove_filter( 'posts_distinct', [ $explore_query, 'prevent_duplicates' ], 30 );

		return $query;
	}
}
