// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use crate::widget::Element;

/// A flexible, invisible spacer that expands to fill available space.
///
/// The optional `weight` controls how much of the remaining space this spacer
/// claims relative to other spacers in the same layout. A spacer with `weight = 2`
/// takes twice as much space as one with `weight = 1`.
///
/// Place a `Spacer` between two widgets inside a [`Column`](crate::layout::column::Column)
/// or [`Row`](crate::layout::row::Row) to push them apart:
///
/// ```rust,no_run
/// # use ltk::{ column, spacer, text, Element };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex() -> Element<Msg> {
/// column()
///     .push( text( "Top" ) )
///     .push( spacer() )    // pushes "Bottom" to the bottom
///     .push( text( "Bottom" ) )
/// .into()
/// # }
/// ```
///
/// Use [`.weight(n)`](Spacer::weight) to replace several consecutive spacers:
///
/// ```rust,no_run
/// # use ltk::{ column, spacer, Column };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex() {
/// // These two are equivalent:
/// let _: Column<Msg> = column().push( spacer().weight( 3 ) );
/// let _: Column<Msg> = column().push( spacer() ).push( spacer() ).push( spacer() );
/// # }
/// ```
///
/// Use [`.height(px)`](Spacer::height) to create a fixed-size vertical spacer:
///
/// ```rust,no_run
/// # use ltk::{ column, spacer, text, Element };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex() -> Element<Msg> {
/// column()
///     .push( text( "Header" ) )
///     .push( spacer().height( 20.0 ) )  // Exactly 20px gap
///     .push( text( "Content" ) )
/// .into()
/// # }
/// ```
pub struct Spacer
{
	/// Relative weight of this spacer (default 1).
	pub weight: u32,
	/// Fixed height in pixels (overrides flexible behavior in a column).
	pub fixed_height: Option<f32>,
	/// Fixed width in pixels (overrides flexible behavior in a row).
	pub fixed_width:  Option<f32>,
}

impl Spacer
{
	/// Set the relative weight of this spacer (default 1).
	pub fn weight( mut self, w: u32 ) -> Self
	{
		self.weight = w;
		self
	}

	/// Set a fixed height for this spacer in pixels.
	/// When set, the spacer will occupy exactly this much vertical space
	/// instead of expanding flexibly.
	pub fn height( mut self, h: f32 ) -> Self
	{
		self.fixed_height = Some( h );
		self
	}

	/// Set a fixed width for this spacer in pixels.
	/// When set, the spacer occupies exactly this much horizontal space
	/// inside a [`Row`](crate::layout::row::Row) instead of expanding
	/// flexibly. Mirrors [`Self::height`] for the horizontal axis — useful
	/// to reserve a precise visual margin while a sibling
	/// [`Flex`](crate::Flex) claims the remaining width.
	pub fn width( mut self, w: f32 ) -> Self
	{
		self.fixed_width = Some( w );
		self
	}

	/// Returns `( fixed_width, fixed_height )`, falling back to `0.0` on the
	/// axes that were not pinned. The parent layout distributes leftover
	/// along its main axis among the still-flexible spacers and `Flex`
	/// wrappers, weighted by `weight`.
	pub fn preferred_size( &self ) -> (f32, f32)
	{
		( self.fixed_width.unwrap_or( 0.0 ), self.fixed_height.unwrap_or( 0.0 ) )
	}

	/// No-op — spacers are invisible.
	pub fn draw( &self ) {}
}

impl<Msg: Clone + 'static> From<Spacer> for Element<Msg>
{
	fn from( s: Spacer ) -> Self
	{
		Element::Spacer( s )
	}
}

/// Create a flexible spacer with weight 1.
///
/// Call [`.weight(n)`](Spacer::weight) to set a relative weight greater than 1:
///
/// ```rust,no_run
/// # use ltk::{ column, spacer, Column };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex() {
/// // These two are equivalent:
/// let _: Column<Msg> = column().push( spacer().weight( 3 ) );
/// let _: Column<Msg> = column().push( spacer() ).push( spacer() ).push( spacer() );
/// # }
/// ```
///
/// Call [`.height(px)`](Spacer::height) to create a fixed-size vertical gap:
///
/// ```rust,no_run
/// # use ltk::{ column, spacer, text, Element };
/// # #[ derive( Clone ) ] enum Msg {}
/// # fn _ex() -> Element<Msg> {
/// column()
///     .push( text( "First" ) )
///     .push( spacer().height( 24.0 ) )  // Fixed 24px gap
///     .push( text( "Second" ) )
/// .into()
/// # }
/// ```
pub fn spacer() -> Spacer
{
	Spacer { weight: 1, fixed_height: None, fixed_width: None }
}
