<?php

/**
 * Podcast Categories.
 *
 * @link    https://aiopodcasting.com
 * @since   1.0.0
 *
 * @package AiO_Podcast_Studio
 */

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

/**
 * AIOPOD_Public_Categories class.
 *
 * @since 1.0.0
 */
class AIOPOD_Public_Categories {

	/**
	 * The only instance of the class.
	 *
	 * @since  1.0.0
	 * @access private
	 * @static
	 * @var    AIOPOD_Public_Categories|null
	 */
	private static $instance = null;

	/**
	 * The default shortcode attribute values.
	 *
	 * @since  1.0.0
	 * @access private
	 * @var    array
	 */
	private $defaults = array();

	/**
	 * Create a new instance of the main class.
	 *
	 * @since  1.0.0
	 * @static
	 * @return AIOPOD_Public_Categories
	 */
	public static function get_instance() {
		if ( self::$instance === null ) {
            self::$instance = new self();
        }

		return self::$instance;
	}

	/**
	 * Prevent cloning of the singleton instance.
	 *
	 * @since  1.0.0
	 * @access private
	 */
	private function __clone() {}

	/**
	 * Prevent unserializing of the singleton instance.
	 *
	 * @since 1.0.0
	 */
	public function __wakeup() {}
	
	/**
	 * Get things started.
	 *
	 * @since  1.0.0
	 * @access private
	 */
	private function __construct() {
		// Register shortcodes
		add_shortcode( 'aiopod_category', array( $this, 'render_shortcode_category' ) );
		add_shortcode( 'aiopod_categories', array( $this, 'render_shortcode_categories' ) );
	}	
	
	/**
	 * Render the shortcode [aiopod_category].
	 *
	 * @since 1.0.0
	 * @param array $atts An associative array of attributes.
	 */
	public function render_shortcode_category( $atts ) {
		$categories_settings = aiopod_get_option( 'aiopod_categories_settings' );
		$category_settings   = aiopod_get_option( 'aiopod_category_settings' );
		$pages_settings      = aiopod_get_option( 'aiopod_pages_settings' );

		$term_slug = get_query_var( 'aiopod_category' );
		$content   = '';

		if ( ! empty( $term_slug ) ) {
			$term = get_term_by( 'slug', sanitize_title( $term_slug ), 'aiopod_categories' );
		} elseif ( ! empty( $atts['id'] ) ) {			
			$term = get_term_by( 'id', (int) $atts['id'], 'aiopod_categories' );
		}

		if ( isset( $term ) && ! empty( $term ) ) {
			$defaults = array(
				'show_breadcrumbs'       => $category_settings['show_breadcrumbs'],
				'current_page_id'        => ! empty( $pages_settings['category'] ) ? (int) $pages_settings['category'] : 0,
				'show_subcategories'     => $category_settings['show_subcategories'],
				'subcategories_title'    => $category_settings['subcategories_title'],
				'subcategories_position' => $category_settings['subcategories_position'],
				'show_podcasts'          => $category_settings['show_podcasts'],
				'podcasts_title'         => $category_settings['podcasts_title']
			);

			$attributes = shortcode_atts( $defaults, $atts, 'aiopod_category' );

			// Enqueue dependencies
			wp_enqueue_style( AIOPOD_PLUGIN_SLUG . '-public' );
			wp_enqueue_script( AIOPOD_PLUGIN_SLUG . '-public' );

			// Process output
			ob_start();
			include apply_filters( 'aiopod_load_template', AIOPOD_PLUGIN_DIR . 'public/templates/single-category.php', $attributes );
			$content = ob_get_clean();
		} else {
			$content = do_shortcode( '[aiopod_categories]' );
		}			
		
		return $content;
	}

	/**
	 * Render the shortcode [aiopod_categories].
	 *
	 * @since 1.0.0
	 * @param array $atts An associative array of attributes.
	 */
	public function render_shortcode_categories( $atts ) {	
		// Vars
		$attributes = shortcode_atts( $this->get_defaults(), $atts, 'aiopod_categories' );		
		$attributes = $this->resolve_attributes( $attributes );		
		
		// Enqueue dependencies
		wp_enqueue_style( AIOPOD_PLUGIN_SLUG . '-public' );
		wp_enqueue_script( AIOPOD_PLUGIN_SLUG . '-public' );

		// Process output
		$content = $this->get_content( $attributes );
		
		return $content;	
	}	

	/**
	 * Load categories using Ajax.
	 *
	 * @since 1.0.0
	 */
	public function ajax_callback_load_categories() {
		check_ajax_referer( 'aiopod_ajax_nonce', 'security' );

		$attributes = $this->sanitize_ajax_attributes();
		$content    = $this->get_content( $attributes );

		wp_send_json_success( array( 'html' => $content ) );
	}

	/**
	 * Return the allowed $_POST keys and their sanitization types for AJAX requests.
	 *
	 * Derived from aiopod_get_shortcode_fields() so premium-added fields are
	 * automatically included. Internal/pagination state fields are appended below.
	 *
	 * @since  1.0.0
	 * @return array Map of attribute key to sanitization type string.
	 */
	private function get_allowed_attributes() {
		$type_map = array(
			'checkbox'     => 'bool',
			'number'       => 'int',
			'select'       => 'key',
			'text'         => 'text',
			'podcasts'     => 'int',
			'categories'   => 'array_int',
			'participants' => 'array_int',
			'tags'         => 'array_int',
		);

		$fields  = aiopod_get_shortcode_fields();
		$allowed = array();

		foreach ( $fields['categories']['sections'] as $section ) {
			foreach ( $section['fields'] as $field ) {
				if ( ! isset( $type_map[ $field['type'] ] ) ) {
					continue;
				}

				$allowed[ $field['name'] ] = $type_map[ $field['type'] ];
			}
		}

		// Internal / pagination state — not defined in aiopod_get_shortcode_fields()
		$allowed['source']        = 'key';
		$allowed['id']            = 'int';
		$allowed['title']         = 'text';
		$allowed['count']         = 'int';
		$allowed['paged']         = 'int';
		$allowed['max_num_pages'] = 'int';
		$allowed['include']       = 'text';
		$allowed['exclude']       = 'text';
		$allowed['hide_if_empty'] = 'int';

		return $allowed;
	}

	/**
	 * Sanitize AJAX $_POST attributes against the allowed list.
	 *
	 * @since  1.0.0
	 * @return array Sanitized attributes.
	 */
	private function sanitize_ajax_attributes() {
		$attributes = array();

		foreach ( $this->get_allowed_attributes() as $key => $type ) {
			if ( ! isset( $_POST[ $key ] ) ) {
				continue;
			}

			switch ( $type ) {
				case 'int':
					$attributes[ $key ] = (int) wp_unslash( $_POST[ $key ] );
					break;

				case 'bool':
					$raw = wp_unslash( $_POST[ $key ] );
					
					if ( 'false' === $raw ) {
						$attributes[ $key ] = 0;
					} elseif ( 'true' === $raw ) {
						$attributes[ $key ] = 1;
					} else {
						$attributes[ $key ] = (int) $raw;
					}
					break;

				case 'key':
					$attributes[ $key ] = sanitize_key( wp_unslash( $_POST[ $key ] ) );
					break;

				case 'text':
					$attributes[ $key ] = sanitize_text_field( wp_unslash( $_POST[ $key ] ) );
					break;

				case 'array_int':
					$attributes[ $key ] = array_map( 'intval', wp_unslash( (array) $_POST[ $key ] ) );
					break;
			}
		}

		return $attributes;
	}

	/**
	 * Get the html output.
	 *
	 * @since  1.0.0
	 * @param  array  $attributes An associative array of attributes.
	 * @return string $content    HTML output.
	 */
	public function get_content( $attributes ) {
		ob_start();
		include apply_filters( 'aiopod_load_template', AIOPOD_PLUGIN_DIR . 'public/templates/categories/categories-' . sanitize_file_name( $attributes['layout'] ) . '.php', $attributes );
		return ob_get_clean();	
		
		return $content;	
	}

	/**
	 * 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 ) {
		// Layout
		if ( ! in_array( $attributes['layout'], array( 'grid', 'list', 'dropdown' ) ) ) {
			$attributes['layout'] = 'grid';
		}

		// Pagination
		if ( empty( $attributes['pagination'] ) ) {
			$attributes['pagination'] = $this->defaults['pagination'];
		}

		// Return resolved array
		return $attributes;
	}

	/**
	 * Get the default shortcode attribute values.
	 *
	 * @since  1.0.0
	 * @return array $atts An associative array of attributes.
	 */
	public function get_defaults() {	
		if ( empty( $this->defaults ) ) {
			$categories_settings = aiopod_get_option( 'aiopod_categories_settings' ); 	
			$pagination_settings = aiopod_get_option( 'aiopod_pagination_settings' ); 

			$fields = aiopod_get_shortcode_fields();

			foreach ( $fields['categories']['sections'] as $section ) {
				foreach ( $section['fields'] as $field ) {
					$this->defaults[ $field['name'] ] = $field['value'];
				}
			}
			
			$this->defaults['source']        = 'categories';
			$this->defaults['id']            = 0;
			$this->defaults['title']         = '';
			$this->defaults['count']         = 0;
			$this->defaults['paged']         = aiopod_get_page_number();
			$this->defaults['max_num_pages'] = 1;	
			$this->defaults['include']       = '';	
			$this->defaults['exclude']       = '';
			$this->defaults['pagination']    = ! empty( $categories_settings['pagination'] ) ? $categories_settings['pagination'] : $pagination_settings['layout'];
			$this->defaults['hide_if_empty'] = 0;
		}

		return $this->defaults;
	}
	
}
