<?php

/**
 * Episodes Widget.
 *
 * @link    https://aiopodcasting.com
 * @since   1.0.0
 *
 * @package AiO_Podcast_Studio
 */

// Exit if accessed directly
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * AIOPOD_Widget_Episodes class.
 *
 * @since 1.0.0
 */
class AIOPOD_Widget_Episodes extends WP_Widget {
	
	/**
     * Unique identifier for the widget.
     *
     * @since  1.0.0
	 * @access protected
     * @var    string
     */
    protected $widget_slug;
	
	/**
     * Widget fields.
     *
     * @since  1.0.0
	 * @access private
     * @var    array
     */
	private $fields;
	
	/**
     * Default settings.
     *
     * @since  1.0.0
	 * @access private
     * @var    array
     */
    private $defaults;
	
	/**
	 * Get things started.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {		
		$this->widget_slug = 'aiopod-widget-episodes';		
		$this->fields      = $this->get_fields();
		$this->defaults    = $this->get_defaults();
		
		parent::__construct(
			$this->widget_slug,
			__( 'AIOPOD - Episodes', 'aio-podcast-studio' ),
			array(
				'classname'   => $this->widget_slug,
				'description' => __( 'Display a list of your episodes.', 'aio-podcast-studio' )
			)
		);		
	}

	/**
	 * Outputs the content of the widget.
	 *
	 * @since 1.0.0
	 * @param array	$args	  The array of form elements.
	 * @param array $instance The current instance of the widget.
	 */
	public function widget( $args, $instance ) {
		// Merge incoming $instance array with $defaults
		if ( count( $instance ) ) {
			$attributes = array_merge( $this->defaults, $instance );
		} else {
			$attributes = $this->defaults;
		}

		$attributes = $this->resolve_attributes( $attributes );		
			
		$widget_args = $args;
		
		// Enqueue dependencies
		wp_enqueue_style( AIOPOD_PLUGIN_SLUG . '-public' );
		wp_enqueue_script( AIOPOD_PLUGIN_SLUG . '-public' );
		
		// Define the query
		$args = array(				
			'post_type'      => 'aiopod_episodes',
			'posts_per_page' => ! empty( $attributes['limit'] ) ? (int) $attributes['limit'] : 100,
			'post_status'    => array( 'publish' )
		);

		if ( ! empty( $attributes['podcast'] ) ) { // Podcast ID
			$args['post_parent'] = (int) $attributes['podcast'];			
		}	

		if ( 'none' !== $attributes['pagination'] ) { // Pagination
			$args['paged'] = (int) $attributes['paged'];
		}

		// Taxonomy Parameters
		$tax_queries = array();

		if ( ! empty( $attributes['tags'] ) ) { // Tags
			$tags = array_map( 'intval', ( is_array( $attributes['tags'] ) ? $attributes['tags'] : explode( ',', $attributes['tags'] ) ) );
			$tags = array_filter( $tags );

			if ( ! empty( $tags ) ) {
				$tax_queries[] = array(
					'taxonomy'         => 'aiopod_tags',
					'field'            => 'term_id',
					'terms'            => $tags,
					'include_children' => false
				);
			}
		}

		if ( ! empty( $attributes['participants'] ) ) { // Participants
			$participants = array_map( 'intval', ( is_array( $attributes['participants'] ) ? $attributes['participants'] : explode( ',', $attributes['participants'] ) ) );
			$participants = array_filter( $participants );

			if ( ! empty( $participants ) ) {
				$tax_queries[] = array(
					'taxonomy'         => 'aiopod_participants',
					'field'            => 'term_id',
					'terms'            => $participants,
					'include_children' => false
				);
			}
		}
		
		$count_tax_queries = count( $tax_queries );
		if ( $count_tax_queries ) {
			$args['tax_query'] = ( $count_tax_queries > 1 ) ? array_merge( array( 'relation' => 'AND' ), $tax_queries ) : $tax_queries;
		}

		// Custom Field (post meta) Parameters
		$meta_queries = array();

		if ( ! empty( $attributes['type'] ) ) { // Episode Type
			$allowed_types = aiopod_get_episode_types();
			$allowed_types = array_keys( $allowed_types );

			$types = is_array( $attributes['type'] ) ? $attributes['type'] : explode( ',', $attributes['type'] );
			$types = array_map( 'sanitize_key', array_map( 'trim', $types ) );
			$types = array_intersect( $types, $allowed_types );

			if ( ! empty( $types ) && count( $types ) !== count( $allowed_types ) ) {
				$meta_queries[] = array(
					'key'     => 'episode_type',
					'value'   => $types,
					'compare' => 'IN'
				);

				$is_singular = false;
			}
		}

		if ( ! empty( $attributes['featured'] ) ) { // Featured			
			$meta_queries[] = array(
				'key'     => 'is_featured',
				'value'   => 1,
				'compare' => '='
			);
		}
		
		if ( ! empty( $attributes['season'] ) ) { // Season Number
			$season = absint( $attributes['season'] );
			
			if ( $season > 0 ) {
				$meta_queries[] = array(
					'key'     => 'season_number',
					'value'   => $season,
					'compare' => '=',
					'type'    => 'NUMERIC'
				);
			}
		}

		$count_meta_queries = count( $meta_queries );
		if ( $count_meta_queries ) {
			$args['meta_query'] = ( $count_meta_queries > 1 ) ? array_merge( array( 'relation' => 'AND' ), $meta_queries ) : $meta_queries;
		}
		
		// Order & Orderby Parameters
		$orderby = sanitize_text_field( $attributes['orderby'] );
		$order   = sanitize_text_field( $attributes['order'] );

		switch ( $orderby ) {
			case 'popularity':
				$args['orderby']  = 'meta_value_num';
				$args['meta_key'] = 'total_downloads_plays';
				$args['order']    = $order;
				break;

			case 'downloads':
				$args['orderby']  = 'meta_value_num';
				$args['meta_key'] = 'total_downloads';
				$args['order']    = $order;
				break;

			case 'plays':
				$args['orderby']  = 'meta_value_num';
				$args['meta_key'] = 'total_plays';
				$args['order']    = $order;
				break;

			case 'rand':
				$seed = aiopod_get_orderby_rand_seed();
				$args['orderby']  = 'RAND(' . $seed . ')';
				break;

			default:
				$args['orderby']  = $orderby;
				$args['order']    = $order;
		}
	
		$args = apply_filters( 'aiopod_query_args', $args, $attributes );
		$aiopod_query = new WP_Query( $args );
		
		// Process output
		echo wp_kses_post( $widget_args['before_widget'] );

		if ( ! empty( $instance['title'] ) ) {
			echo wp_kses_post( $widget_args['before_title'] . apply_filters( 'widget_title', $instance['title'] ) . $widget_args['after_title'] );
		}
		
		if ( $aiopod_query->have_posts() ) {		
			if ( ( is_front_page() && is_home() ) || 'none' === $attributes['pagination'] ) {
				$attributes['count'] = $aiopod_query->post_count;
			} else {
				$attributes['count'] = $aiopod_query->found_posts;
			}

			if ( 'none' !== $attributes['pagination'] ) {
				$attributes['max_num_pages'] = $aiopod_query->max_num_pages;
			}
		}
			
		include apply_filters( 'aiopod_load_template', AIOPOD_PLUGIN_DIR . 'public/templates/episodes/episodes-' . sanitize_file_name( $attributes['layout'] ) . '.php', $attributes );

		echo wp_kses_post( $widget_args['after_widget'] );
	}
	
	/**
	 * Processes the widget's options to be saved.
	 *
	 * @since 1.0.0
	 * @param array	$new_instance The new instance of values to be generated via the update.
	 * @param array $old_instance The previous instance of values before the update.
	 */
	public function update( $new_instance, $old_instance ) {
		$instance = $old_instance;		

		$instance['title'] = isset( $new_instance['title'] ) ? strip_tags( $new_instance['title'] ) : '';
		
		foreach ( $this->fields['episodes']['sections'] as $section ) {
			foreach ( $section['fields'] as $field ) {
				$field_name = $field['name'];

				if ( 'number' === $field['type'] ) {
					if ( ! empty( $new_instance[ $field_name ] ) ) {
						$instance[ $field_name ] = ( false === strpos( $new_instance[ $field_name ], '.' ) ) ? (int) $new_instance[ $field_name ] : (float) $new_instance[ $field_name ];
					} else {
						$instance[ $field_name ] = 0;
					}
				} elseif ( 'url' === $field['type'] ) {
					$instance[ $field_name ] = ! empty( $new_instance[ $field_name ] ) ? aiopod_sanitize_url( $new_instance[ $field_name ] ) : '';
				} elseif ( 'checkbox' === $field['type'] ) {
					$instance[ $field_name ] = isset( $new_instance[ $field_name ] ) ? (int) $new_instance[ $field_name ] : 0;
				} elseif ( 'tags' === $field['type'] ) {
					$instance['tags'] = isset( $new_instance['tags'] ) ? array_map( 'intval', $new_instance['tags'] ) : array();
				} elseif ( 'participants' === $field['type'] ) {
					$instance['participants'] = isset( $new_instance['participants'] ) ? array_map( 'intval', $new_instance['participants'] ) : array();
				} else {
					$instance[ $field_name ] = ! empty( $new_instance[ $field_name ] ) ? sanitize_text_field( $new_instance[ $field_name ] ) : '';
				}
			}
		}
		
		return $instance;
	}
	
	/**
	 * Generates the administration form for the widget.
	 *
	 * @since 1.0.0
	 * @param array $instance The array of keys and values for the widget.
	 */
	public function form( $instance ) {
		// Parse incoming $instance into an array and merge it with $defaults
		$instance = wp_parse_args(
			(array) $instance,
			$this->defaults
		);
			
		// Display the admin form
		if ( ! class_exists( 'Walker_Category_Checklist' ) ) {
			require_once ABSPATH . 'wp-admin/includes/template.php';
		}

		require_once AIOPOD_PLUGIN_DIR . 'includes/walker-terms-checklist.php';
		
		include AIOPOD_PLUGIN_DIR . 'widgets/forms/episodes.php';
	}

	/**
	 * Resolves attributes into a valid, final configuration.
	 * 
	 * This method guarantees that the returned attributes array is safe,
	 * consistent, and ready for query building and rendering.
	 *
	 * @since  1.0.0
	 * @param  array $attributes Raw attributes merged from defaults and user input.
	 * @return array             Fully resolved attributes array.
	 */
	private function resolve_attributes( $attributes ) {
		// Title
		$attributes['title'] = '';

		// Layout
		if ( ! in_array( $attributes['layout'], array( 'grid', 'list', 'compact', 'slider' ) ) ) {
			$attributes['layout'] = 'grid';
		}

		// Player
		if ( 'compact' === $attributes['layout'] ) {
			$attributes['enable_player'] = 1;
		}

		if ( ! empty( $attributes['enable_player'] ) ) {
			$attributes['interactive_mode'] = 1;
		}

		// Pagination
		if ( 'loadmore' !== $attributes['pagination'] ) {
			$attributes['pagination'] = 'none';
		}

		// Filters
		if (
			empty( $attributes['filters_keyword'] ) &&
			empty( $attributes['filters_tags'] ) &&
			empty( $attributes['filters_season'] ) &&
			empty( $attributes['filters_sort'] )
		) {
			$attributes['enable_filters'] = 0;
		}

		if ( ! empty( $attributes['enable_filters'] ) ) {
			// Search
			if ( ! empty( $attributes['filters_keyword'] ) ) {
				$search_query = isset( $_GET['q'] ) ? sanitize_text_field( wp_unslash( $_GET['q'] ) ) : '';
				if ( ! empty( $search_query ) ) {
					$attributes['search_query'] = $search_query;
				}
			}

			// Tags
			if ( ! empty( $attributes['filters_tags'] ) ) {
				$tags = isset( $_GET['topic'] ) ? sanitize_text_field( wp_unslash( $_GET['topic'] ) ) : '';
				if ( ! empty( $tags ) ) {
					$attributes['tags'] = $tags;
				}
			}

			// Season
			if ( ! empty( $attributes['filters_season'] ) ) {
				$season = isset( $_GET['season'] ) ? absint( wp_unslash( $_GET['season'] ) ) : 0;
				if ( $season > 0 ) {
					$attributes['season'] = $season;
				}
			}

			// Sort
			if ( ! empty( $attributes['filters_sort'] ) ) {
				$sort = isset( $_GET['sort'] ) ? sanitize_key( wp_unslash( $_GET['sort'] ) ) : '';
				if ( ! empty( $sort ) ) {
					$sort = array_filter( array_map( 'trim', explode( '-', $sort ) ) );
		
					if ( ! empty( $sort ) ) {
						$attributes['orderby'] = $sort[0];
						
						if ( count( $sort ) > 1 ) {
							$attributes['order'] = $sort[1];
						}
					}
				}
			}

			// Pagination
			if ( 'ajax' === $attributes['filters_mode'] ) {
				if ( ! empty( $attributes['pagination'] ) ) {
					$attributes['pagination'] = 'loadmore';
				}
			}
		}

		// Return resolved array
		return $attributes;
	}

	/**
	 * Get the form fields.
	 *
	 * @since  1.0.0
	 * @access private
	 * @return array   An associative array of fields.
	 */
	private function get_fields() {
		if ( empty( $this->fields ) ) {
			$this->fields = aiopod_get_shortcode_fields();

			foreach ( $this->fields['episodes']['sections']['display']['fields'] as $index => $field ) {
				if ( 'pagination' === $field['name'] ) {
					$this->fields['episodes']['sections']['display']['fields'][ $index ] = array(
						'name'        => 'pagination',
						'label'       => __( 'More Button', 'aio-podcast-studio' ),
						'description' => __( 'Show or hide the "Load More" button.', 'aio-podcast-studio' ),
						'type'        => 'select',
						'options'     => array(							
							'loadmore' => __( 'Show', 'aio-podcast-studio' ),
							'none'     => __( 'Hide', 'aio-podcast-studio' )
						),
						'value'       => 'loadmore'
					);
				}
			}
		}

		return $this->fields;
	}

	/**
	 * Get the default attribute values.
	 *
	 * @since  1.0.0
	 * @access private
	 * @return array   An associative array of attributes.
	 */
	private function get_defaults() {
		if ( empty( $this->defaults ) ) {	
			$player_settings = aiopod_get_option( 'aiopod_player_settings' ); 

			foreach ( $this->fields['episodes']['sections'] as $section ) {
				foreach ( $section['fields'] as $field ) {
					$this->defaults[ $field['name'] ] = $field['value'];
				}
			}
		
			$this->defaults['source']             = 'episodes';
			$this->defaults['title']              = __( 'Episodes', 'aio-podcast-studio' );				
			$this->defaults['count']              = 0;
			$this->defaults['columns']            = 1;
			$this->defaults['limit']              = 4;
			$this->defaults['slides_per_view']    = 1;
			$this->defaults['paged']              = 1;
			$this->defaults['max_num_pages']      = 1;			
			$this->defaults['include']            = '';	
			$this->defaults['exclude']            = '';			
			$this->defaults['type']               = '';
			$this->defaults['season']             = '';
			$this->defaults['interactive_mode']   = 0;
			$this->defaults['enable_player']      = 0;
			$this->defaults['player_autoadvance'] = $player_settings['autoadvance'];
			$this->defaults['player_loop']        = $player_settings['loop'];
			$this->defaults['player_hotkeys']     = $player_settings['hotkeys'];
			$this->defaults['pagination']         = 'loadmore';
			$this->defaults['hide_if_empty']      = 0;
		}
	
		return $this->defaults;
	}
	
}