// Shared visual vocabulary: list-item wrapper, theme icons, text macros,
// screen header and the small composite widgets views reuse (toggle
// rows, refresh buttons, segmented choices, scanning indicator).

mod icons;

use std::sync::Arc;
use ltk::{
	Element, Color, Length, ButtonVariant,
	button, icon_button, column, row, spacer, separator, container, spinner, toggle,
};
use crate::app::Msg;
use crate::i18n::tr;

/// Horizontal inset between a list row's edge and its content. Rows paint a
/// surface when hovered or pressed, and at zero it hugs the icon and the
/// chevron.
pub( crate ) const LIST_PAD_H: f32 = 8.0;

pub( crate ) fn list_item<M: Clone>( label: impl Into<String> ) -> ltk::ListItem<M>
{
	ltk::list_item( label ).pad_h( LIST_PAD_H )
}

pub( crate ) fn icon( name: &str ) -> Option<( Arc<Vec<u8>>, u32, u32 )>
{
	let ( rgba, w, h ) = ltk::theme_icon_rgba( name, 24 )?;
	let tinted = ltk::tint_symbolic( &rgba, ltk::theme_palette().icon );
	Some( ( Arc::new( tinted ), w, h ) )
}

pub( crate ) fn chevron_icon() -> Option<( Arc<Vec<u8>>, u32, u32 )>
{
	let ( rgba, w, h ) = ltk::theme_icon_rgba( "general/right", 21 )?;
	let tinted = ltk::tint_symbolic( &rgba, ltk::theme_palette().text_secondary );
	Some( ( Arc::new( tinted ), w, h ) )
}

/// Attach a leading theme icon to a list item, when the theme has it.
pub( crate ) fn with_icon<M: Clone>( it: ltk::ListItem<M>, path: &str ) -> ltk::ListItem<M>
{
	match icon( path )
	{
		Some( ( rgba, w, h ) ) => it.icon( rgba, w, h ),
		None                   => it,
	}
}

/// Attach the disclosure chevron to a list item.
pub( crate ) fn with_chevron<M: Clone>( it: ltk::ListItem<M> ) -> ltk::ListItem<M>
{
	match chevron_icon()
	{
		Some( ( rgba, w, h ) ) => it.trailing_icon( rgba, w, h ),
		None                   => it,
	}
}

macro_rules! t {
	( $s:expr ) => {
		ltk::text( $s ).color( ltk::theme_palette().text_primary )
	};
}
pub( crate ) use t;

macro_rules! t_sec {
	( $s:expr ) => {
		ltk::text( $s ).color( ltk::theme_palette().text_secondary )
	};
}
pub( crate ) use t_sec;

macro_rules! row_link {
	( $label:expr, $icon_path:expr, $screen:expr ) => {{
		let it = crate::ui::list_item( $label )
			.on_press( crate::app::Msg::Open( $screen ) );
		let it = crate::ui::with_icon( it, $icon_path );
		crate::ui::with_chevron( it )
	}};
}
pub( crate ) use row_link;

pub( crate ) fn header( title: &str ) -> Element<Msg>
{
	let back = match icon( "general/left" )
	{
		Some( ( rgba, w, h ) ) => icon_button( rgba, w, h ).icon_size( Length::widget( 21.0 ) ),
		None                   => button( "←" ),
	};
	column::<Msg>()
		.padding( 0.0 )
		.spacing( 4.0 )
		.push(
			row::<Msg>()
				.spacing( 8.0 )
				.push( back.variant( ButtonVariant::Tertiary ).on_press( Msg::Back ) )
				.push( t!( title ).size( 20.0 ).weight( 700 ) )
				.push( spacer() )
		)
		.push( separator() )
		.into()
}

pub( crate ) fn section_sep() -> Element<Msg> { separator().into() }

/// Full-width switch row: label on the left, toggle flush right.
pub( crate ) fn toggle_row( label: impl Into<String>, on: bool, msg: Msg ) -> Element<Msg>
{
	row::<Msg>()
		.push( t!( label ) )
		.push( spacer() )
		.push( toggle( on ).on_toggle( msg ) )
		.into()
}

/// Section refresh icon button, disabled while a scan is in flight.
pub( crate ) fn refresh_button( scanning: bool, msg: Msg ) -> Element<Msg>
{
	let mut btn = match icon( "session/restart" )
	{
		Some( ( rgba, w, h ) ) => icon_button( rgba, w, h ).icon_size( Length::widget( 18.0 ) ),
		None                   => button( "↻" ),
	};
	btn = btn.variant( ButtonVariant::Tertiary );
	if !scanning
	{
		btn = btn.on_press( msg );
	}
	btn.into()
}

/// Centred spinner + "Scanning…" occupying the spot where results land.
pub( crate ) fn scanning_row( phase: f32 ) -> Element<Msg>
{
	row::<Msg>()
		.spacing( 8.0 )
		.push( spinner().phase( phase ) )
		.push( t_sec!( tr!( "common.scanning" ) ).size( 13.0 ) )
		.into()
}

/// Segmented-choice button: Primary when active, Secondary otherwise.
pub( crate ) fn seg_btn( label: &str, active: bool, msg: Msg ) -> Element<Msg>
{
	button( label )
		.variant( if active { ButtonVariant::Primary } else { ButtonVariant::Secondary } )
		.on_press( msg )
		.into()
}

pub( crate ) fn fmt_uptime( secs: u64 ) -> String
{
	let days  = secs / 86400;
	let hours = ( secs % 86400 ) / 3600;
	let mins  = ( secs % 3600 ) / 60;
	if days > 0      { format!( "{}d {}h {}m", days, hours, mins ) }
	else if hours > 0 { format!( "{}h {}m", hours, mins ) }
	else             { format!( "{}m", mins ) }
}

pub( crate ) fn seg( width_vw: f32, height_px: f32, color: Color ) -> Element<Msg>
{
	container(
		spacer()
			.width(  Length::vw( width_vw ) )
			.height( Length::px( height_px ) )
	)
	.background( color )
	.radius( 4.0 )
	.into()
}

pub( crate ) fn legend_row( label: &str, value: &str, color: Color ) -> Element<Msg>
{
	row::<Msg>()
		.spacing( 8.0 )
		.push( ltk::text( "●" ).color( color ).size( 18.0 ) )
		.push( t!( label ).size( 14.0 ) )
		.push( spacer() )
		.push( t_sec!( value ).size( 14.0 ) )
		.into()
}

// Glob-imported by the view modules so each does not repeat the same
// ltk/app/ui import lists (and unused glob imports never warn).
pub( crate ) mod prelude
{
	pub( crate ) use ltk::{
		Element, Color, ThemeMode, ThemePreference,
		column, row, spacer, separator, slider, stack, combo,
		toggle, scroll, button, ButtonVariant, progress_bar, container, text_edit,
	};
	pub( crate ) use crate::app::{ Msg, Screen, State };
	pub( crate ) use crate::i18n::tr;
	pub( crate ) use crate::ui::{
		list_item, with_icon, with_chevron, header, section_sep,
		toggle_row, refresh_button, scanning_row, seg_btn, fmt_uptime,
		seg, legend_row, t, t_sec, row_link,
	};
	pub( crate ) use crate::ui::icons::{ wifi_icon, status_dot, StatusDot };
}
