<?php
/**
 * Navigation Menu — WordPress menus (with dropdowns) or manual Label|URL lines.
 *
 * Styles inspired by classic school headers: underline accent, clean dropdown panel.
 *
 * @package AuraBuilder
 */

declare(strict_types=1);

namespace AuraBuilder\Widgets\Basic;

use AuraBuilder\Document\Node;
use AuraBuilder\Widgets\WidgetBase;

final class NavMenuWidget extends WidgetBase {

	public function get_type(): string {
		return 'nav_menu';
	}

	public function get_title(): string {
		return 'Menu de navegação';
	}

	public function get_category(): string {
		return 'basic';
	}

	public function get_icon(): string {
		return 'list';
	}

	public function get_defaults(): array {
		return array(
			// custom = itens editáveis no painel; wp = menu do WordPress
			'source'       => 'custom',
			'menu_id'      => '0',
			'items'        => "Início|/\nSobre|#\nSegmentos|#\n> Educação Infantil|#\n> Ensino Médio|#\nContato|#",
			'layout'       => 'horizontal',
			// underline | classic | pills | buttons | minimal | bordered
			'style'        => 'underline',
			'align'        => 'center',
			'gap'          => '8',
			'accent'       => '#eab308',
			'hover_color'  => '',
			// Mobile (header_footer.txt MVP).
			'mobile_style' => 'drawer',
			'show_toggle'  => '1',
			'toggle_label' => 'Menu',
		);
	}

	/**
	 * Accept #hex, #rrggbbaa, rgb()/rgba(), or named transparent.
	 */
	private static function sanitize_css_color( string $raw, string $fallback = '' ): string {
		$raw = trim( $raw );
		if ( $raw === '' ) {
			return $fallback;
		}
		if ( strtolower( $raw ) === 'transparent' ) {
			return 'transparent';
		}
		if ( preg_match( '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/', $raw ) ) {
			return strtolower( $raw );
		}
		// rgb/rgba — keep safe subset of characters.
		if ( preg_match( '/^rgba?\(\s*[\d.%\s,\/]+\s*\)$/i', $raw ) ) {
			return $raw;
		}
		$hex = sanitize_hex_color( $raw );
		return $hex ? $hex : $fallback;
	}

	public function sanitize_settings( array $settings ): array {
		$source = sanitize_key( (string) ( $settings['source'] ?? 'wp' ) );
		if ( ! in_array( $source, array( 'wp', 'custom' ), true ) ) {
			$source = 'wp';
		}
		$layout = sanitize_key( (string) ( $settings['layout'] ?? 'horizontal' ) );
		if ( ! in_array( $layout, array( 'horizontal', 'vertical' ), true ) ) {
			$layout = 'horizontal';
		}
		$style = sanitize_key( (string) ( $settings['style'] ?? 'underline' ) );
		if ( ! in_array( $style, array( 'underline', 'classic', 'pills', 'buttons', 'minimal', 'bordered' ), true ) ) {
			$style = 'underline';
		}
		$align = in_array( ( $settings['align'] ?? '' ), array( 'left', 'center', 'right' ), true )
			? (string) $settings['align']
			: 'center';
		$mobile = sanitize_key( (string) ( $settings['mobile_style'] ?? 'drawer' ) );
		if ( ! in_array( $mobile, array( 'drawer', 'stack', 'none' ), true ) ) {
			$mobile = 'drawer';
		}
		$flag = static function ( $v, string $d = '1' ): string {
			if ( $v === null || $v === '' ) {
				return $d;
			}
			return ( $v === true || $v === 1 || $v === '1' || $v === 'true' || $v === 'yes' ) ? '1' : '0';
		};
		$accent = self::sanitize_css_color( (string) ( $settings['accent'] ?? '' ), '#eab308' );
		if ( $accent === '' ) {
			$accent = '#eab308';
		}
		$hover = self::sanitize_css_color( (string) ( $settings['hover_color'] ?? '' ), '' );
		return array(
			'source'       => $source,
			'menu_id'      => (string) max( 0, (int) ( $settings['menu_id'] ?? 0 ) ),
			'items'        => sanitize_textarea_field( (string) ( $settings['items'] ?? '' ) ),
			'layout'       => $layout,
			'style'        => $style,
			'align'        => $align,
			'gap'          => (string) max( 0, min( 40, (int) ( $settings['gap'] ?? 8 ) ) ),
			'accent'       => $accent,
			'hover_color'  => $hover,
			'mobile_style' => $mobile,
			'show_toggle'  => $flag( $settings['show_toggle'] ?? null, '1' ),
			'toggle_label' => sanitize_text_field( (string) ( $settings['toggle_label'] ?? 'Menu' ) ),
		);
	}

	/**
	 * Flat parse for legacy callers. Nested lines: prefix with ">" or two spaces.
	 *
	 * @return list<array{label:string,url:string,children?:list<array{label:string,url:string}>}>
	 */
	public static function parse_items( string $raw ): array {
		$tree   = array();
		$lines  = preg_split( '/\r\n|\r|\n/', $raw ) ?: array();
		$last   = null;
		foreach ( $lines as $line ) {
			if ( trim( $line ) === '' ) {
				continue;
			}
			$child = false;
			if ( preg_match( '/^\s*>\s*/', $line ) || preg_match( '/^\s{2,}/', $line ) ) {
				$child = true;
				$line  = preg_replace( '/^\s*>\s*/', '', $line ) ?? $line;
				$line  = preg_replace( '/^\s+/', '', $line ) ?? $line;
			}
			$line = trim( $line );
			$p     = explode( '|', $line, 2 );
			$label = sanitize_text_field( trim( (string) ( $p[0] ?? '' ) ) );
			if ( $label === '' ) {
				continue;
			}
			$url = trim( (string) ( $p[1] ?? '#' ) );
			if ( $url === '' ) {
				$url = '#';
			} elseif ( str_starts_with( $url, '/' ) || str_starts_with( $url, '#' ) || str_starts_with( $url, '?' ) ) {
				$url = esc_url_raw( $url ) ?: $url;
			} else {
				$url = esc_url_raw( $url ) ?: '#';
			}
			$node = array(
				'label' => $label,
				'url'   => $url,
			);
			if ( $child && $last !== null ) {
				if ( ! isset( $tree[ $last ]['children'] ) ) {
					$tree[ $last ]['children'] = array();
				}
				$tree[ $last ]['children'][] = $node;
			} else {
				$tree[] = $node;
				$last   = count( $tree ) - 1;
			}
		}
		return $tree;
	}

	/**
	 * Build nested menu tree from a WP menu (children nested under parents).
	 * Uses db_id (WP nav hierarchy key) with depth/cycle guards.
	 *
	 * @return list<array{label:string,url:string,current?:bool,children?:list<array{label:string,url:string,current?:bool}>}>
	 */
	public static function tree_from_wp_menu( int $menu_id ): array {
		if ( $menu_id <= 0 ) {
			return array();
		}
		if ( ! function_exists( 'wp_get_nav_menu_items' ) ) {
			return array();
		}
		$items = wp_get_nav_menu_items( $menu_id );
		if ( ! is_array( $items ) || ! $items ) {
			return array();
		}

		$by_parent = array();
		foreach ( $items as $item ) {
			if ( ! is_object( $item ) ) {
				continue;
			}
			// menu_item_parent references the parent's db_id.
			$pid = (int) ( $item->menu_item_parent ?? 0 );
			if ( ! isset( $by_parent[ $pid ] ) ) {
				$by_parent[ $pid ] = array();
			}
			$by_parent[ $pid ][] = $item;
		}

		$visited = array();
		$to_node = null;
		$to_node = static function ( $item, int $depth ) use ( &$to_node, $by_parent, &$visited ): array {
			$db_id = (int) ( $item->db_id ?? $item->ID ?? 0 );
			// Cycle / depth guard (avoid fatal infinite recursion).
			if ( $db_id > 0 && isset( $visited[ $db_id ] ) ) {
				return array(
					'label' => (string) ( $item->title ?? '' ),
					'url'   => (string) ( $item->url ?? '#' ),
				);
			}
			if ( $db_id > 0 ) {
				$visited[ $db_id ] = true;
			}
			$node = array(
				'label'   => (string) ( $item->title ?? '' ),
				'url'     => (string) ( $item->url ?? '#' ),
				'current' => ! empty( $item->current ) || ! empty( $item->current_item_ancestor ) || ! empty( $item->current_item_parent ),
			);
			// Max 3 levels deep (top + sub + sub-sub).
			if ( $depth < 3 && $db_id > 0 && ! empty( $by_parent[ $db_id ] ) ) {
				$node['children'] = array();
				foreach ( $by_parent[ $db_id ] as $child ) {
					$node['children'][] = $to_node( $child, $depth + 1 );
				}
			}
			return $node;
		};

		$out = array();
		foreach ( $by_parent[0] ?? array() as $top ) {
			$out[] = $to_node( $top, 0 );
		}
		return $out;
	}

	/**
	 * @return list<array{label:string,url:string}>
	 * @deprecated Use tree_from_wp_menu.
	 */
	public static function items_from_wp_menu( int $menu_id ): array {
		$tree = self::tree_from_wp_menu( $menu_id );
		$flat = array();
		foreach ( $tree as $n ) {
			$flat[] = array(
				'label' => $n['label'],
				'url'   => $n['url'],
			);
		}
		return $flat;
	}

	/**
	 * @param list<array{label:string,url:string,current?:bool,children?:list<array{label:string,url:string,current?:bool}>}> $items
	 */
	private function render_items( array $items, bool $editor = false ): string {
		$html = '';
		foreach ( $items as $item ) {
			$label    = (string) ( $item['label'] ?? '' );
			$url      = (string) ( $item['url'] ?? '#' );
			$children = is_array( $item['children'] ?? null ) ? $item['children'] : array();
			$current  = ! empty( $item['current'] );
			$has_sub  = count( $children ) > 0;
			$cls      = 'ab-nav-menu__item' . ( $has_sub ? ' has-children' : '' ) . ( $current ? ' is-current' : '' );
			$html    .= '<li class="' . esc_attr( $cls ) . '">';
			if ( $editor ) {
				$html .= '<span class="ab-nav-menu__link' . ( $current ? ' is-active' : '' ) . '">'
					. esc_html( $label )
					. ( $has_sub ? '<span class="ab-nav-menu__caret" aria-hidden="true">▾</span>' : '' )
					. '</span>';
			} else {
				$html .= '<a class="ab-nav-menu__link' . ( $current ? ' is-active' : '' ) . '" href="' . esc_url( $url ) . '"'
					. ( $has_sub ? ' aria-haspopup="true" aria-expanded="false"' : '' ) . '>'
					. esc_html( $label )
					. ( $has_sub ? '<span class="ab-nav-menu__caret" aria-hidden="true">▾</span>' : '' )
					. '</a>';
			}
			if ( $has_sub ) {
				$html .= '<ul class="ab-nav-menu__sub" role="menu">';
				foreach ( $children as $child ) {
					$cl = (string) ( $child['label'] ?? '' );
					$cu = (string) ( $child['url'] ?? '#' );
					$cc = ! empty( $child['current'] );
					$html .= '<li class="ab-nav-menu__sub-item' . ( $cc ? ' is-current' : '' ) . '" role="none">';
					if ( $editor ) {
						$html .= '<span class="ab-nav-menu__sub-link' . ( $cc ? ' is-active' : '' ) . '">' . esc_html( $cl ) . '</span>';
					} else {
						$html .= '<a class="ab-nav-menu__sub-link' . ( $cc ? ' is-active' : '' ) . '" href="' . esc_url( $cu ) . '" role="menuitem">'
							. esc_html( $cl ) . '</a>';
					}
					$html .= '</li>';
				}
				$html .= '</ul>';
			}
			$html .= '</li>';
		}
		return $html;
	}

	public function render( Node $node, array $context = array() ): string {
		$s      = $node->settings;
		$source = (string) ( $s['source'] ?? 'wp' );
		$items  = array();
		$editor = ! empty( $context['editor'] );

		if ( $source === 'wp' ) {
			$items = self::tree_from_wp_menu( (int) ( $s['menu_id'] ?? 0 ) );
			// Fallback: first available menu.
			if ( ! $items ) {
				$menus = wp_get_nav_menus();
				if ( is_array( $menus ) && $menus ) {
					$items = self::tree_from_wp_menu( (int) $menus[0]->term_id );
				}
			}
		}
		if ( ! $items ) {
			$items = self::parse_items( (string) ( $s['items'] ?? '' ) );
		}
		if ( ! $items ) {
			return $editor
				? '<div class="ab-nav-menu ab-empty">Menu — escolha um menu do WordPress ou itens manuais</div>'
				: '';
		}

		$layout  = esc_attr( (string) ( $s['layout'] ?? 'horizontal' ) );
		$style   = esc_attr( (string) ( $s['style'] ?? 'underline' ) );
		$align   = esc_attr( (string) ( $s['align'] ?? 'center' ) );
		$gap     = (int) ( $s['gap'] ?? 8 );
		$accent = (string) ( $s['accent'] ?? '#eab308' );
		$hover  = (string) ( $s['hover_color'] ?? '' );
		if ( $hover === '' ) {
			$hover = $accent;
		}
		$mobile  = esc_attr( (string) ( $s['mobile_style'] ?? 'drawer' ) );
		$toggle  = ( $s['show_toggle'] ?? '1' ) === '1';
		$t_label = esc_html( (string) ( $s['toggle_label'] ?? 'Menu' ) );

		$html  = '<nav class="ab-nav-menu ab-nav-menu--' . $layout . ' ab-nav-menu--' . $style . ' ab-nav-menu--' . $align
			. ' ab-nav-menu--mobile-' . $mobile . '" style="--ab-nm-gap:' . esc_attr( (string) $gap )
			. 'px;--ab-nm-accent:' . esc_attr( $accent )
			. ';--ab-nm-hover:' . esc_attr( $hover )
			. '" data-ab-nav-menu="1" aria-label="Menu">';
		if ( $toggle && $layout === 'horizontal' && $mobile !== 'none' ) {
			$html .= '<button type="button" class="ab-nav-menu__toggle" data-ab-nav-toggle aria-expanded="false" aria-label="'
				. esc_attr( $t_label ) . '"><span class="ab-nav-menu__burger" aria-hidden="true"></span><span class="ab-nav-menu__toggle-text">'
				. $t_label . '</span></button>';
		}
		$html .= '<ul class="ab-nav-menu__list">';
		$html .= $this->render_items( $items, $editor );
		$html .= '</ul></nav>';
		return $html;
	}
}
