<?php
/**
 * A reusable Elementor trait for adding a comprehensive set of post query controls.
 *
 * @package Sifency\Traits
 */

namespace Sifency\Traits;

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

use Elementor\Controls_Manager;

if (!trait_exists('Sifency\Traits\Sifency_Arg_Controls')) {
    trait Sifency_Arg_Controls
    {
        /**
         * Get all public post types. Caches the result for performance.
         * @return array
         */
        protected static function get_post_types()
        {
            static $post_types = null;
            if (is_null($post_types)) {
                $post_type_args = [ 'public' => true, 'show_in_nav_menus' => true ];
                $post_types_obj = get_post_types($post_type_args, 'objects');
                $post_types = [];
                foreach ($post_types_obj as $obj) {
                    $post_types[$obj->name] = $obj->label;
                }
            }
            return $post_types;
        }

        /**
         * Get all public taxonomies. Caches the result for performance.
         * @return array
         */
        protected static function get_taxonomies()
        {
            static $taxonomies = null;
            if (is_null($taxonomies)) {
                $taxonomies_obj = get_taxonomies(['show_in_nav_menus' => true], 'objects');
                $taxonomies = [];
                foreach ($taxonomies_obj as $obj) {
                    $taxonomies[$obj->name] = $obj->label;
                }
            }
            return $taxonomies;
        }

        /**
         * Get all authors who can publish posts. Caches the result for performance.
         * @return array
         */
        protected static function get_authors()
        {
            static $authors = null;
            if (is_null($authors)) {
                $users = get_users([ 'capability' => ['publish_posts'], 'has_published_posts' => true, 'fields' => ['ID', 'display_name'] ]);
                $authors = [];
                if ($users) {
                    foreach ($users as $user) {
                        $authors[$user->ID] = $user->display_name;
                    }
                }
            }
            return $authors;
        }

        /**
         * Get all posts for select controls.
         * For a public plugin, it's highly recommended to replace this with an AJAX-based
         * search control. For now, we've added a hard limit to prevent timeouts.
         * @return array
         */
        protected static function get_posts_for_select()
        {
            static $posts = null;
            if (is_null($posts)) {
                $post_list = get_posts([
                    'post_type' => 'any',
                    'posts_per_page' => 500,
                    'post_status' => 'publish',
                    'orderby' => 'title',
                    'order' => 'ASC'
                ]);
                $posts = [];
                if ($post_list) {
                    foreach ($post_list as $post) {
                        $posts[$post->ID] = $post->post_title;
                    }
                }
            }
            return $posts;
        }
        
        /**
         * Get terms for a given taxonomy. Caches results per taxonomy for performance.
         * @param string $taxonomy_slug
         * @return array
         */
        protected static function get_terms_by_taxonomy($taxonomy_slug)
        {
            static $terms_cache = [];
            if (isset($terms_cache[$taxonomy_slug])) {
                return $terms_cache[$taxonomy_slug];
            }
            $terms = get_terms([ 'taxonomy' => $taxonomy_slug, 'hide_empty' => true ]);
            $options = [];
            if (!is_wp_error($terms) && !empty($terms)) {
                foreach ($terms as $term) {
                    $options[$term->term_id] = $term->name;
                }
            }
            $terms_cache[$taxonomy_slug] = $options;
            return $options;
        }

        /**
         * Adds the full set of query controls to an Elementor widget.
         */
        public function add_sifency_arg_controls()
        {
            $this->start_controls_section( 'section_query', [ 'label' => 'Query', 'tab' => Controls_Manager::TAB_CONTENT ] );
            
            $this->add_control(
                'query_source',
                [ 'label' => 'Source', 'type' => Controls_Manager::SELECT, 'options' => [ 'custom_query' => 'Custom Query', 'manual_selection' => 'Manual Selection', 'related' => 'Related Posts', 'current_query' => 'Current Query' ], 'default' => 'custom_query' ]
            );

            // TABS: Include / Exclude
            $this->start_controls_tabs( 'query_tabs', [ 'condition' => [ 'query_source!' => 'current_query' ] ] );
            
            $this->start_controls_tab('tab_query_include', ['label' => 'Include By']);
            $this->add_control( 'query_post_type', [ 'label' => 'Post Type', 'type' => Controls_Manager::SELECT, 'options' => self::get_post_types(), 'default' => 'post', 'condition' => ['query_source' => 'custom_query'] ]);
            $this->add_control('include_categories', ['label' => 'Category', 'type' => Controls_Manager::SELECT2, 'options' => self::get_terms_by_taxonomy('category'), 'multiple' => true, 'label_block' => true, 'condition' => ['query_source' => ['custom_query', 'related']]]);
            $this->add_control('include_authors', ['label' => 'Author', 'type' => Controls_Manager::SELECT2, 'options' => self::get_authors(), 'multiple' => true, 'label_block' => true, 'condition' => ['query_source' => 'custom_query']]);
            $this->add_control('query_posts_ids', ['label' => 'Search & Select Posts', 'type' => Controls_Manager::SELECT2, 'options' => self::get_posts_for_select(), 'label_block' => true, 'multiple' => true, 'description' => __('NOTE: Shows a maximum of 500 posts for performance reasons.', 'sifency-addons'), 'condition' => ['query_source' => 'manual_selection']]);
            $this->add_control('query_related_by', ['label' => 'Related By', 'type' => Controls_Manager::SELECT, 'options' => self::get_taxonomies(), 'default' => 'category', 'condition' => ['query_source' => 'related']]);
            $this->end_controls_tab();
            
            $this->start_controls_tab('tab_query_exclude', ['label' => 'Exclude']);
            $this->add_control('exclude_current_post', ['label' => 'Exclude Current Post', 'type' => Controls_Manager::SWITCHER, 'default' => 'yes', 'condition' => ['query_source!' => ['custom_query', 'related']]]);
            $this->add_control('exclude_posts_ids', ['label' => 'Exclude Posts', 'type' => Controls_Manager::SELECT2, 'options' => self::get_posts_for_select(), 'label_block' => true, 'multiple' => true, 'description' => __('NOTE: Shows a maximum of 500 posts for performance reasons.', 'sifency-addons'), 'condition' => ['query_source!' => ['custom_query', 'related']]]);
            $this->end_controls_tab();

            $this->end_controls_tabs();

            $this->add_control('hr_query_settings', ['type' => Controls_Manager::DIVIDER, 'style' => 'thick']);
            $this->add_control('posts_per_page', ['label' => 'Posts Per Page', 'type' => Controls_Manager::NUMBER, 'default' => 6, 'condition' => ['query_source!' => 'current_query']]);
            $this->add_control('orderby', ['label' => 'Order By', 'type' => Controls_Manager::SELECT, 'options' => ['date' => 'Date', 'title' => 'Title', 'rand' => 'Random', 'comment_count' => 'Comment Count', 'menu_order' => 'Menu Order'], 'default' => 'date', 'condition' => ['query_source!' => ['custom_query', 'related']]]);
            $this->add_control('order', ['label' => 'Order', 'type' => Controls_Manager::SELECT, 'options' => ['DESC' => 'Descending', 'ASC' => 'Ascending'], 'default' => 'DESC', 'condition' => ['query_source!' => ['custom_query', 'related']]]);

            $this->end_controls_section();
        }

        /**
         * Builds and returns the arguments for a WP_Query based on the widget settings.
         * @return array|null An array of query arguments, or null to use the global query.
         */
        public function get_sifency_query_args()
        {
            $settings = $this->get_settings_for_display();
            $source = $settings['query_source'] ?? 'custom_query';

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

            $query_args = [];
            
            // --- Build query based on source ---
            switch ($source) {
                case 'manual_selection':
                    $query_args = [
                        'post_type'      => 'any',
                        'post__in'       => !empty($settings['query_posts_ids']) ? $settings['query_posts_ids'] : [0],
                        'posts_per_page' => -1,
                        'orderby'        => 'post__in',
                    ];
                    break;

                case 'related':
                    if (!is_singular()) return [];
                    $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 [];

                    $query_args = [
                        'post_type' => get_post_type($post_id),
                        'tax_query' => [['taxonomy' => $related_by, 'field' => 'term_id', 'terms' => wp_list_pluck($terms, 'term_id')]],
                        'post__not_in' => [$post_id],
                    ];
                    break;

                case 'custom_query':
                default:
                    $query_args['post_type'] = $settings['query_post_type'] ?? 'post';
                    $tax_query = [];
                    if (!empty($settings['include_categories'])) {
                        $tax_query[] = ['taxonomy' => 'category', 'field' => 'term_id', 'terms' => $settings['include_categories']];
                    }
                    if (!empty($tax_query)) {
                        $query_args['tax_query'] = $tax_query;
                    }
                    if (!empty($settings['include_authors'])) {
                        $query_args['author__in'] = $settings['include_authors'];
                    }
                    break;
            }
            
            
            if ($source !== 'manual_selection') {
                 if (!empty($settings['posts_per_page'])) {
                     $query_args['posts_per_page'] = $settings['posts_per_page'];
                 }
            }

            if (!empty($settings['orderby']) && $source !== 'manual_selection') {
                $query_args['orderby'] = $settings['orderby'];
            }
            if (!empty($settings['order']) && $source !== 'manual_selection') {
                $query_args['order'] = $settings['order'];
            }

            // --- Exclusion Logic ---
            $post__not_in = $query_args['post__not_in'] ?? [];

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

            if (!empty($settings['exclude_posts_ids'])) {
                $post__not_in = array_merge($post__not_in, $settings['exclude_posts_ids']);
            }

            if (!empty($post__not_in)) {
                $query_args['post__not_in'] = array_unique($post__not_in);
            }
            
            return $query_args;
        }
    }
}