//! `cargo run --example combo`
//!
//! Showcases the `combo` widget — a select / dropdown with editable
//! query, multi-select chips and a scrollable popup.
//!
//! The trigger lives in the main `view()` tree; the popup is returned
//! from [`App::overlays`] as a real Wayland **xdg-popup** child of the
//! main window, so it can extend outside the parent surface (the
//! canonical select / dropdown behaviour). The compositor positions the
//! popup adjacent to the trigger pill and dismisses it via
//! `popup_done` when the user clicks outside, which fires the spec's
//! `on_dismiss` message.
//!
//! Tap on an item to add it to the selection; tap on the `×` next to a
//! chip to remove it; tap outside the popup to dismiss. Esc exits.

use ltk::
{
	combo, column, row, separator, spacer, text,
	App, Color, ComboState, Element, Keysym, OverlaySpec, WidgetId,
};

// Distinct anchor ids so each combo's popup can find its own trigger
// pill in the previous-frame layout snapshot.
const FRUIT_ANCHOR:  WidgetId = WidgetId( "demo-fruit-trigger" );
const REGION_ANCHOR: WidgetId = WidgetId( "demo-region-trigger" );

#[ derive( Clone, Debug ) ]
enum Msg
{
	// Multi-select fruit picker.
	FruitToggle,
	FruitQuery( String ),
	FruitSelect( usize ),
	FruitUnselect( usize ),
	FruitDismiss,
	// Single-select region picker (non-searchable).
	RegionToggle,
	RegionSelect( usize ),
	RegionDismiss,
}

struct Demo
{
	fruits:        ComboState,
	fruit_items:   Vec<String>,
	region:        ComboState,
	region_items:  Vec<String>,
}

impl Demo
{
	fn new() -> Self
	{
		Self
		{
			fruits: ComboState::new(),
			fruit_items: [
				"Apple", "Apricot", "Avocado", "Banana", "Blackberry",
				"Blueberry", "Cherry", "Date", "Fig", "Grape", "Kiwi",
				"Lemon", "Lime", "Mango", "Orange", "Papaya", "Peach",
				"Pear", "Pineapple", "Plum", "Raspberry", "Strawberry",
			].iter().map( |s| s.to_string() ).collect(),

			region: ComboState::new(),
			region_items: [
				"Galicia", "Asturias", "Cantabria", "País Vasco",
				"Navarra", "La Rioja", "Aragón", "Cataluña",
			].iter().map( |s| s.to_string() ).collect(),
		}
	}

	fn fruit_combo( &self ) -> ltk::Combo<Msg>
	{
		combo( self.fruits.clone(), self.fruit_items.clone() )
			.label( "Fruits" )
			.description( "Pick the ones you want in the smoothie." )
			.placeholder( "Type to filter…" )
			.helper( "Selected fruits show up as chips above the field." )
			.multi_select( true )
			.searchable( true )
			.anchor_id( FRUIT_ANCHOR )
			.popup_max_height( 280.0 )
			.on_query_change( Msg::FruitQuery )
			.on_toggle_open( Msg::FruitToggle )
			.on_select_idx( Msg::FruitSelect )
			.on_unselect_idx( Msg::FruitUnselect )
			.on_dismiss( Msg::FruitDismiss )
	}

	fn region_combo( &self ) -> ltk::Combo<Msg>
	{
		combo( self.region.clone(), self.region_items.clone() )
			.label( "Region" )
			.description( "Single-select, non-searchable." )
			.placeholder( "Choose a region…" )
			.anchor_id( REGION_ANCHOR )
			.popup_max_height( 240.0 )
			.on_toggle_open( Msg::RegionToggle )
			.on_select_idx( Msg::RegionSelect )
			.on_dismiss( Msg::RegionDismiss )
	}

	fn body( &self ) -> Element<Msg>
	{
		let palette = ltk::theme_palette();

		column::<Msg>()
			.padding( 32.0 )
			.spacing( 24.0 )
			.center_y( false )
			.push(
				text( "ltk — combo / select demo" )
					.size( 24.0 )
					.color( palette.text_primary )
					.align_center(),
			)
			.push( separator() )
			.push( self.fruit_combo().trigger() )
			.push( separator() )
			.push( self.region_combo().trigger() )
			.push( spacer() )
			.push(
				row::<Msg>()
					.padding( 0.0 )
					.spacing( 8.0 )
					.push(
						text( format!( "Fruits selected: {}", self.fruits.selected.len() ) )
							.size( 14.0 )
							.color( palette.text_secondary ),
					)
					.push( spacer() )
					.push(
						text(
							self.region.selected.first()
								.and_then( |&i| self.region_items.get( i ) )
								.map( |s| format!( "Region: {s}" ) )
								.unwrap_or_else( || "Region: —".to_string() ),
						)
						.size( 14.0 )
						.color( palette.text_secondary ),
					),
			)
			.push(
				text( "Esc = quit" )
					.size( 12.0 )
					.color( palette.text_secondary )
					.align_center(),
			)
			.into()
	}
}

impl App for Demo
{
	type Message = Msg;

	fn view( &self ) -> Element<Msg>
	{
		self.body()
	}

	fn overlays( &self ) -> Vec<OverlaySpec<Msg>>
	{
		// Each open combo contributes one xdg-popup overlay anchored
		// to its trigger pill; closed combos contribute nothing.
		let mut out = Vec::new();
		if let Some( o ) = self.fruit_combo().overlay()  { out.push( o ); }
		if let Some( o ) = self.region_combo().overlay() { out.push( o ); }
		out
	}

	fn update( &mut self, msg: Msg )
	{
		match msg
		{
			Msg::FruitToggle => self.fruits.toggle_open(),
			Msg::FruitQuery( q ) => self.fruits.query = q,
			Msg::FruitSelect( i ) =>
			{
				if self.fruits.selected.contains( &i )
				{
					self.fruits.unselect( i );
				}
				else
				{
					self.fruits.select( i );
				}
			}
			Msg::FruitUnselect( i ) => self.fruits.unselect( i ),
			Msg::FruitDismiss =>
			{
				self.fruits.is_open = false;
				self.fruits.query.clear();
			}

			Msg::RegionToggle => self.region.toggle_open(),
			Msg::RegionSelect( i ) =>
			{
				// Single-select: replace the whole `selected` vector
				// with just this index, then close.
				self.region.selected = vec![ i ];
				self.region.is_open  = false;
			}
			Msg::RegionDismiss => self.region.is_open = false,
		}
	}

	fn on_key( &mut self, keysym: Keysym ) -> Option<Msg>
	{
		if keysym == Keysym::Escape
		{
			std::process::exit( 0 );
		}
		None
	}

	fn background_color( &self ) -> Color
	{
		ltk::theme_palette().bg
	}
}

fn main()
{
	ltk::run( Demo::new() );
}
