<?php
/**
 * Menu Walker Class
 *
 * @package ResponsiveMobileSelect\Core
 * @since 2.0.0
 */

namespace ResponsiveMobileSelect\Core;

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Custom menu walker for responsive select menu.
 *
 * @since 2.0.0
 */
class Menu_Walker extends \Walker_Nav_Menu {

	/**
	 * Settings instance.
	 *
	 * @since 2.0.0
	 * @var \ResponsiveMobileSelect\Core\Settings
	 */
	private $settings;

	/**
	 * Current depth.
	 *
	 * @since 2.0.0
	 * @var int
	 */
	private $current_depth = 0;

	/**
	 * Select options for mobile menu.
	 *
	 * @since 2.0.0
	 * @var array
	 */
	private $select_options = array();

	/**
	 * Constructor.
	 *
	 * @since 2.0.0
	 * @param \ResponsiveMobileSelect\Core\Settings $settings Settings instance.
	 */
	public function __construct( Settings $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Start the element output.
	 *
	 * @since 2.0.0
	 * @param string $output Used to append additional content (passed by reference).
	 * @param object $item   Menu item data object.
	 * @param int    $depth  Depth of menu item. Used for padding.
	 * @param array  $args   An array of arguments. @see wp_nav_menu().
	 * @param int    $id     Current item ID.
	 */
	public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
		$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

		$classes   = empty( $item->classes ) ? array() : (array) $item->classes;
		$classes[] = 'menu-item-' . $item->ID;

		/**
		 * Filter the CSS class(es) applied to a menu item's list item element.
		 *
		 * @since 2.0.0
		 * @param array  $classes The CSS classes that are applied to the menu item's `<li>` element.
		 * @param object $item    The current menu item.
		 * @param array  $args    An array of wp_nav_menu() arguments.
		 * @param int    $depth   Depth of menu item. Used for padding.
		 */
		$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
		$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

		/**
		 * Filter the ID applied to a menu item's list item element.
		 *
		 * @since 2.0.0
		 * @param string $menu_id The ID that is applied to the menu item's `<li>` element.
		 * @param object $item    The current menu item.
		 * @param array  $args    An array of wp_nav_menu() arguments.
		 * @param int    $depth   Depth of menu item. Used for padding.
		 */
		$id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth );
		$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';

		$output .= $indent . '<li' . $id . $class_names . '>';

		$atts           = array();
		$atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
		$atts['target'] = ! empty( $item->target ) ? $item->target : '';
		$atts['rel']    = ! empty( $item->xfn ) ? $item->xfn : '';
		$atts['href']   = ! empty( $item->url ) ? $item->url : '';

		/**
		 * Filter the HTML attributes applied to a menu item's anchor element.
		 *
		 * @since 2.0.0
		 * @param array  $atts   {
		 *     The HTML attributes applied to the menu item's `<a>` element, empty strings are ignored.
		 *
		 *     @type string $title  Title attribute.
		 *     @type string $target Target attribute.
		 *     @type string $rel    The rel attribute.
		 *     @type string $href   The href attribute.
		 * }
		 * @param object $item   The current menu item.
		 * @param array  $args   An array of wp_nav_menu() arguments.
		 * @param int    $depth  Depth of menu item. Used for padding.
		 */
		$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

		$attributes = '';
		foreach ( $atts as $attr => $value ) {
			if ( ! empty( $value ) ) {
				$value       = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
				$attributes .= ' ' . $attr . '="' . $value . '"';
			}
		}

		/** This filter is documented in wp-includes/post-template.php */
		$title = apply_filters( 'the_title', $item->title, $item->ID );

		/**
		 * Filter a menu item's title.
		 *
		 * @since 2.0.0
		 * @param string $title The menu item's title.
		 * @param object $item  The current menu item.
		 * @param array  $args  An array of wp_nav_menu() arguments.
		 * @param int    $depth Depth of menu item. Used for padding.
		 */
		$title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );

		$item_output  = $args->before;
		$item_output .= '<a' . $attributes . '>';
		$item_output .= $args->link_before . $title . $args->link_after;
		$item_output .= '</a>';
		$item_output .= $args->after;

		/**
		 * Filter a menu item's starting output.
		 *
		 * @since 2.0.0
		 * @param string $item_output The menu item's starting HTML output.
		 * @param object $item        Menu item data object.
		 * @param int    $depth       Depth of menu item. Used for padding.
		 * @param array  $args        An array of wp_nav_menu() arguments.
		 */
		$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );

		// Collect select option for mobile (but don't output it yet).
		$this->collect_select_option( $item, $depth );
	}

	/**
	 * End the element output.
	 *
	 * @since 2.0.0
	 * @param string $output Used to append additional content (passed by reference).
	 * @param object $item   Page data object. Not used.
	 * @param int    $depth  Depth of page. Not Used.
	 * @param array  $args   An array of arguments. @see wp_nav_menu().
	 */
	public function end_el( &$output, $item, $depth = 0, $args = null ) {
		$output .= "</li>\n";
	}

	/**
	 * Start the element output.
	 *
	 * @since 2.0.0
	 * @param string $output Used to append additional content (passed by reference).
	 * @param int    $depth  Depth of menu item. Used for padding.
	 * @param array  $args   An array of arguments. @see wp_nav_menu().
	 */
	public function start_lvl( &$output, $depth = 0, $args = null ) {
		$indent = str_repeat( "\t", $depth );
		$output .= "\n$indent<ul class=\"sub-menu\">\n";
	}

	/**
	 * End the element output.
	 *
	 * @since 2.0.0
	 * @param string $output Used to append additional content (passed by reference).
	 * @param int    $depth  Depth of menu item. Used for padding.
	 * @param array  $args   An array of arguments. @see wp_nav_menu().
	 */
	public function end_lvl( &$output, $depth = 0, $args = null ) {
		$indent = str_repeat( "\t", $depth );
		$output .= "$indent</ul>\n";
	}

	/**
	 * Get all collected select options.
	 *
	 * @since 2.0.0
	 * @return array Array of select options.
	 */
	public function get_select_options() {
		return $this->select_options;
	}

	/**
	 * Reset select options (call before rendering a new menu).
	 *
	 * @since 2.0.0
	 */
	public function reset_select_options() {
		$this->select_options = array();
	}

	/**
	 * Collect select option for mobile menu (but don't output it).
	 *
	 * @since 2.0.0
	 * @param object $item  Menu item object.
	 * @param int    $depth Current depth.
	 */
	private function collect_select_option( $item, $depth ) {
		// Check if we should exclude this item.
		if ( $this->should_exclude_item( $item ) ) {
			return;
		}

		// Check depth limit.
		$max_depth = $this->settings->get( 'max_depth', 0 );
		if ( $max_depth > 0 && $depth >= $max_depth ) {
			return;
		}

		// Get indent character.
		$indent_char = $this->settings->get( 'indent_character', '— ' );
		$indent      = str_repeat( $indent_char, $depth );

		// Check if this is the current page.
		$selected = '';
		if ( $this->settings->get( 'highlight_current', false ) && $this->is_current_page( $item ) ) {
			$selected = ' selected';
		}

		// Build option HTML.
		$option = sprintf(
			'<option value="%s"%s>%s%s</option>',
			esc_url( $item->url ),
			$selected,
			esc_html( $indent ),
			esc_html( $item->title )
		);

		// Store option for later use (don't output it yet).
		$this->select_options[] = $option;
	}

	/**
	 * Check if item should be excluded.
	 *
	 * @since 2.0.0
	 * @param object $item Menu item object.
	 * @return bool Whether to exclude the item.
	 */
	private function should_exclude_item( $item ) {
		// Check if we should exclude empty links.
		if ( $this->settings->get( 'exclude_empty_links', false ) ) {
			if ( empty( $item->url ) || in_array( $item->url, array( '#', '' ), true ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Check if item is current page.
	 *
	 * @since 2.0.0
	 * @param object $item Menu item object.
	 * @return bool Whether item is current page.
	 */
	private function is_current_page( $item ) {
		// Check if this is a page or post.
		if ( in_array( $item->object, array( 'page', 'post' ), true ) ) {
			return is_page( $item->object_id ) || is_single( $item->object_id );
		}

		// Check if this is a custom post type.
		if ( 'post_type' === $item->type && ! empty( $item->object ) ) {
			return is_singular( $item->object ) && get_queried_object_id() === $item->object_id;
		}

		// Check if this is a taxonomy.
		if ( 'taxonomy' === $item->type && ! empty( $item->object ) ) {
			return is_tax( $item->object ) && get_queried_object_id() === $item->object_id;
		}

		// Check if this is the current URL.
		$http_host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		$request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
		
		if ( ! empty( $http_host ) && ! empty( $request_uri ) ) {
			$current_url = ( is_ssl() ? 'https://' : 'http://' ) . $http_host . $request_uri;
			return $item->url === $current_url;
		}

		return false;
	}
}
