<?php
namespace Sifency\Traits;

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

use Elementor\Controls_Manager;

if ( ! trait_exists( 'Sifency\Traits\Sifency_Addons_Query_Arg_Controls' ) ) {
	trait Sifency_Addons_Query_Arg_Controls {

		use Sifency_Addons_Numeric_Pagination;

		// =====================================================================
		// STATIC HELPERS — control option builders
		// =====================================================================

		protected static function get_post_types() {
			static $post_types = null;
			if ( is_null( $post_types ) ) {
				$args       = array(
					'public'            => true,
					'show_in_nav_menus' => true,
				);
				$pt_objects = get_post_types( $args, 'objects' );
				$post_types = array();
				foreach ( $pt_objects as $pt ) {
					$post_types[ $pt->name ] = $pt->label;
				}
			}
			return $post_types;
		}

		protected static function get_taxonomies_objects() {
			static $tax_objects = null;
			if ( is_null( $tax_objects ) ) {
				$tax_objects = get_taxonomies( array( 'public' => true ), 'objects' );
			}
			return $tax_objects;
		}

		protected static function get_taxonomies() {
			$objects    = self::get_taxonomies_objects();
			$taxonomies = array();
			foreach ( $objects as $obj ) {
				$taxonomies[ $obj->name ] = $obj->label;
			}
			return $taxonomies;
		}

		protected static function get_authors() {
			static $authors = null;
			if ( is_null( $authors ) ) {
				$users   = get_users(
					array(
						'capability' => array( 'publish_posts' ),
						'fields'     => array( 'ID', 'display_name', 'user_login' ),
					)
				);
				$authors = array();
				foreach ( $users as $user ) {
					// key = user_login (slug-based, portable across imports)
					$authors[ $user->user_login ] = $user->display_name;
				}
			}
			return $authors;
		}

		protected static function get_posts_for_select() {
			static $posts = null;
			if ( is_null( $posts ) ) {
				$post_list = get_posts(
					array(
						'post_type'      => 'any',
						'posts_per_page' => 100,
						'post_status'    => 'publish',
					)
				);
				$posts     = array();
				foreach ( $post_list as $post ) {
					// key = post_name (slug, portable across imports)
					$posts[ $post->post_name ] = $post->post_title;
				}
			}
			return $posts;
		}

		protected static function get_terms_by_taxonomy( $taxonomy_slug ) {
			static $terms_cache = array();
			if ( isset( $terms_cache[ $taxonomy_slug ] ) ) {
				return $terms_cache[ $taxonomy_slug ];
			}
			$terms   = get_terms(
				array(
					'taxonomy'   => $taxonomy_slug,
					'hide_empty' => false,
				)
			);
			$options = array();
			if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
				foreach ( $terms as $term ) {
					// key = slug (portable across imports)
					$options[ $term->slug ] = $term->name . ' (' . $term->slug . ')';
				}
			}
			$terms_cache[ $taxonomy_slug ] = $options;
			return $options;
		}

		// =====================================================================
		// PRIVATE RUNTIME HELPERS
		// =====================================================================

		/**
		 * Resolves an array of post slugs (or legacy numeric IDs) to post IDs.
		 *
		 * WHY NOT get_page_by_path():
		 *   get_page_by_path() only works for hierarchical post types (page, portfolio…).
		 *   For flat types like 'post', 'product', etc. it always returns null.
		 *   We use WP_Query with name= instead, which works for ALL post types.
		 *
		 * @param  string[] $slugs  Array of post slugs or legacy numeric IDs.
		 * @return int[]            Array of resolved post IDs (empty slugs skipped).
		 */
		private function resolve_post_slugs_to_ids( array $slugs ): array {
			$ids = array();

			foreach ( $slugs as $slug ) {
				$slug = trim( (string) $slug );
				if ( empty( $slug ) ) {
					continue;
				}

				// Legacy: value stored as numeric ID (before slug-based refactor).
				if ( is_numeric( $slug ) ) {
					$ids[] = (int) $slug;
					continue;
				}

				// Slug lookup — works for ALL post types (hierarchical and flat).
				$found = get_posts(
					array(
						'name'           => $slug,
						'post_type'      => 'any',
						'post_status'    => 'publish',
						'posts_per_page' => 1,
						'fields'         => 'ids',
						'no_found_rows'  => true,
					)
				);

				if ( ! empty( $found ) ) {
					$ids[] = (int) $found[0];
				}
			}

			return $ids;
		}

		// =====================================================================
		// CONTROLS REGISTRATION
		// =====================================================================

		public function add_sifency_arg_controls( $args = array() ) {
			$args = wp_parse_args(
				$args,
				array(
					'default_post' => 'post',
					'condition'    => array(),
				)
			);

			$this->start_controls_section(
				'section_query',
				array(
					'label'     => esc_html__( 'Query', 'sifency-addons' ),
					'tab'       => Controls_Manager::TAB_CONTENT,
					'condition' => $args['condition'],
				)
			);

			$this->add_control(
				'query_source',
				array(
					'label'   => esc_html__( 'Source', 'sifency-addons' ),
					'type'    => Controls_Manager::SELECT,
					'default' => 'custom_query',
					'options' => array(
						'custom_query'     => 'Custom Query',
						'manual_selection' => 'Manual Selection',
						'related'          => 'Related Posts',
						'current_query'    => 'Current Query',
					),
				)
			);

			$tabs_condition = array_merge( $args['condition'], array( 'query_source!' => 'current_query' ) );
			$this->start_controls_tabs( 'query_tabs', array( 'condition' => $tabs_condition ) );

			// ── Include tab ───────────────────────────────────────────────────
			$this->start_controls_tab( 'tab_query_include', array( 'label' => 'Include' ) );

			$this->add_control(
				'query_post_type',
				array(
					'label'     => 'Post Type',
					'type'      => Controls_Manager::SELECT,
					'options'   => self::get_post_types(),
					'default'   => $args['default_post'],
					'condition' => array( 'query_source' => 'custom_query' ),
				)
			);

			foreach ( self::get_taxonomies_objects() as $slug => $taxonomy ) {
				if ( in_array( $slug, array( 'post_format', 'nav_menu', 'link_category' ), true ) ) {
					continue;
				}

				$this->add_control(
					'include_term_' . $slug,
					array(
						'label'       => $taxonomy->label,
						'type'        => Controls_Manager::SELECT2,
						'options'     => self::get_terms_by_taxonomy( $slug ),
						'multiple'    => true,
						'label_block' => true,
						'condition'   => array(
							'query_source'    => 'custom_query',
							'query_post_type' => $taxonomy->object_type,
						),
					)
				);
			}

			$this->add_control(
				'include_authors',
				array(
					'label'       => 'Author',
					'type'        => Controls_Manager::SELECT2,
					'options'     => self::get_authors(),
					'multiple'    => true,
					'label_block' => true,
					'condition'   => array( 'query_source' => 'custom_query' ),
				)
			);

			$this->add_control(
				'query_posts_ids',
				array(
					'label'       => 'Search & Select',
					'type'        => Controls_Manager::SELECT2,
					'options'     => self::get_posts_for_select(),
					'label_block' => true,
					'multiple'    => true,
					'condition'   => array( 'query_source' => 'manual_selection' ),
				)
			);

			$this->add_control(
				'query_related_by',
				array(
					'label'     => 'Related By',
					'type'      => Controls_Manager::SELECT,
					'options'   => self::get_taxonomies(),
					'default'   => 'category',
					'condition' => array( 'query_source' => 'related' ),
				)
			);

			$this->end_controls_tab();

			// ── Exclude tab ───────────────────────────────────────────────────
			$this->start_controls_tab( 'tab_query_exclude', array( 'label' => 'Exclude' ) );

			$this->add_control(
				'exclude_current_post',
				array(
					'label'     => 'Exclude Current Post',
					'type'      => Controls_Manager::SWITCHER,
					'default'   => 'yes',
					'condition' => array( 'query_source!' => 'manual_selection' ),
				)
			);

			$this->add_control(
				'exclude_posts_ids',
				array(
					'label'       => 'Exclude Posts',
					'type'        => Controls_Manager::SELECT2,
					'options'     => self::get_posts_for_select(),
					'label_block' => true,
					'multiple'    => true,
					'condition'   => array( 'query_source!' => 'manual_selection' ),
				)
			);

			$this->end_controls_tab();

			$this->end_controls_tabs();

			$this->add_control(
				'hr_query_settings',
				array(
					'type'  => Controls_Manager::DIVIDER,
					'style' => 'thick',
				)
			);

			$this->add_control(
				'posts_per_page',
				array(
					'label'     => 'Posts Per Page',
					'type'      => Controls_Manager::NUMBER,
					'default'   => 6,
					'condition' => array( 'query_source!' => array( 'current_query', 'manual_selection' ) ),
				)
			);

			$this->add_control(
				'orderby',
				array(
					'label'     => 'Order By',
					'type'      => Controls_Manager::SELECT,
					'options'   => array(
						'date'          => 'Date',
						'title'         => 'Title',
						'rand'          => 'Random',
						'comment_count' => 'Comments',
						'menu_order'    => 'Menu Order',
					),
					'default'   => 'date',
					'condition' => array( 'query_source!' => array( 'current_query', 'manual_selection' ) ),
				)
			);

			$this->add_control(
				'order',
				array(
					'label'     => 'Order',
					'type'      => Controls_Manager::SELECT,
					'options'   => array(
						'DESC' => 'Descending',
						'ASC'  => 'Ascending',
					),
					'default'   => 'DESC',
					'condition' => array( 'query_source!' => array( 'current_query', 'manual_selection' ) ),
				)
			);

			$this->end_controls_section();

			$this->add_sifency_addons_numeric_pagination_controls(
				array(
					'prefix'    => 'query_pagination_',
					'condition' => array_merge( $args['condition'], array( 'query_source!' => 'manual_selection' ) ),
				)
			);
		}

		// =====================================================================
		// QUERY ARGS BUILDER
		// =====================================================================

		public function get_sifency_addons_query_args() {
			$settings = $this->get_settings_for_display();
			$source   = $settings['query_source'] ?? 'custom_query';

			if ( 'current_query' === $source ) {
				return null;
			}

			$query_args          = array();
			$paged               = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : ( ( get_query_var( 'page' ) ) ? get_query_var( 'page' ) : 1 );
			$query_args['paged'] = $paged;

			switch ( $source ) {

				case 'manual_selection':
					// Resolve slugs → IDs using WP_Query (works for all post types).
					$slugs    = ! empty( $settings['query_posts_ids'] ) ? (array) $settings['query_posts_ids'] : array();
					$post_ids = $this->resolve_post_slugs_to_ids( $slugs );

					$query_args['post_type']      = 'any';
					$query_args['post__in']       = ! empty( $post_ids ) ? $post_ids : array( 0 );
					$query_args['orderby']        = 'post__in';
					$query_args['posts_per_page'] = -1;
					break;

				case 'related':
					if ( ! is_singular() ) {
						return array();
					}
					$related_by = $settings['query_related_by'] ?? 'category';
					$post_id    = get_the_ID();
					$terms      = get_the_terms( $post_id, $related_by );
					if ( empty( $terms ) || is_wp_error( $terms ) ) {
						return array();
					}
					$query_args['post_type']    = get_post_type( $post_id );
					$query_args['tax_query']    = array(
						array(
							'taxonomy' => $related_by,
							'field'    => 'term_id',
							'terms'    => wp_list_pluck( $terms, 'term_id' ),
						),
					);
					$query_args['post__not_in'] = array( $post_id );
					break;

				case 'custom_query':
				default:
					$query_args['post_type'] = $settings['query_post_type'] ?? 'post';

					// Tax query — terms stored as slugs (portable across imports).
					$tax_query = array();
					foreach ( self::get_taxonomies_objects() as $slug => $taxonomy ) {
						$ctrl_id = 'include_term_' . $slug;
						if ( ! empty( $settings[ $ctrl_id ] ) && in_array( $query_args['post_type'], (array) $taxonomy->object_type, true ) ) {
							$tax_query[] = array(
								'taxonomy' => $slug,
								'field'    => 'slug', // slug-based: survives import
								'terms'    => (array) $settings[ $ctrl_id ],
							);
						}
					}
					if ( ! empty( $tax_query ) ) {
						$query_args['tax_query'] = array_merge( array( 'relation' => 'AND' ), $tax_query );
					}

					// Authors stored as user_login (portable across imports).
					if ( ! empty( $settings['include_authors'] ) ) {
						$author_ids = array();
						foreach ( (array) $settings['include_authors'] as $val ) {
							if ( is_numeric( $val ) ) {
								// Legacy: stored as ID.
								$author_ids[] = (int) $val;
							} else {
								$u = get_user_by( 'login', $val );
								if ( $u ) {
									$author_ids[] = $u->ID;
								}
							}
						}
						if ( ! empty( $author_ids ) ) {
							$query_args['author__in'] = $author_ids;
						}
					}
					break;
			}

			// Pagination / ordering (not applicable to manual_selection).
			if ( 'manual_selection' !== $source ) {
				$query_args['posts_per_page'] = $settings['posts_per_page'] ?? 6;
				$query_args['orderby']        = $settings['orderby'] ?? 'date';
				$query_args['order']          = $settings['order'] ?? 'DESC';
			}

			// ── Exclude posts ─────────────────────────────────────────────────
			$post_not_in = array();

			if ( 'yes' === ( $settings['exclude_current_post'] ?? '' ) && is_singular() ) {
				$post_not_in[] = get_the_ID();
			}

			if ( ! empty( $settings['exclude_posts_ids'] ) ) {
				// Resolve slugs → IDs using WP_Query (works for all post types).
				$excluded_ids = $this->resolve_post_slugs_to_ids( (array) $settings['exclude_posts_ids'] );
				$post_not_in  = array_merge( $post_not_in, $excluded_ids );
			}

			if ( ! empty( $post_not_in ) ) {
				// Merge with any post__not_in already set (e.g. related posts).
				$existing                   = $query_args['post__not_in'] ?? array();
				$query_args['post__not_in'] = array_unique( array_merge( $existing, $post_not_in ) );
			}

			return $query_args;
		}
	}
}
