use ltk::theme::typography;
use ltk::{ button, column, icon_button, img_widget, row, stack, text, text_edit, ButtonVariant, Color, Element };

use crate::message::Msg;
use crate::state::{ Mode, State };

pub fn view( state: &State ) -> Element<Msg>
{
	let greeter = state.mode == Mode::Greeter;
	let button_label = if greeter
	{
		rust_i18n::t!( "login_button" )
	} else {
		rust_i18n::t!( "unlock_button" )
	};

	let mut form = column::<Msg>()
		.padding( 60.0 )
		.spacing( 25.0 )
		.max_width( 400.0 )
		.center_y( true )
		.push( ltk::spacer().weight( 2 ) );

	if let Some( l ) = logo( state )
	{
		form = form.push( l );
	}

	// The form renders behind the idle panel and is only interactive once the
	// panel has slid away; until then every control is inert so input falling
	// through the input-transparent idle subsurface does nothing.
	let active = state.revealed;

	form = form
		.push( username_field( state, active && greeter ) )
		.push( password_field( state, active ) )
		.push( submit_button( state, &button_label, active ) );

	if let Some( err ) = &state.error
	{
		form = form.push( error_text( err ) );
	}

	form = form.push( ltk::spacer().weight( 3 ) );

	let mut st = stack::<Msg>().push( form );
	if let Some( power ) = power_row( state, active )
	{
		st = st.push( power );
	}
	st.into()
}

fn username_field( state: &State, editable: bool ) -> Element<Msg>
{
	let field = text_edit( rust_i18n::t!( "username_placeholder" ).to_string(), state.username.clone() )
		.id( ltk::WidgetId( "username" ) );
	if editable
	{
		field.on_change( Msg::UsernameChanged ).on_submit( Msg::Submit ).into()
	} else {
		field.read_only( true ).into()
	}
}

fn password_field( state: &State, editable: bool ) -> Element<Msg>
{
	let field = text_edit( rust_i18n::t!( "password_placeholder" ).to_string(), state.secret.clone() )
		.id( ltk::WidgetId( "password" ) )
		.secure( true );
	if editable
	{
		field.on_change( Msg::SecretChanged ).on_submit( Msg::Submit ).into()
	} else {
		field.read_only( true ).into()
	}
}

fn submit_button( state: &State, label: &str, active: bool ) -> Element<Msg>
{
	let text = if state.authenticating { "…".to_string() } else { label.to_string() };
	button::<Msg>( text )
		.variant( ButtonVariant::Primary )
		.on_press_maybe( if active && !state.authenticating { Some( Msg::Submit ) } else { None } )
		.into()
}

fn logo( state: &State ) -> Option<Element<Msg>>
{
	state.logo.as_ref().map( |( rgba, w, h )|
		ltk::column::<Msg>()
			.max_width( 260.0 )
			.padding( 24.0 )
			.push( img_widget( rgba.clone(), *w, *h ) )
			.into()
	)
}

fn error_text( err: &str ) -> Element<Msg>
{
	text( err.to_string() )
		.size( typography::BODY )
		.color( Color::rgb( 0.9, 0.2, 0.2 ) )
		.align_center()
		.wrap( true )
		.into()
}

fn power_row( state: &State, active: bool ) -> Option<Element<Msg>>
{
	if !state.allow_shutdown && !state.allow_reboot
	{
		return None;
	}

	let mut controls = row::<Msg>().spacing( 32.0 ).align_right();

	if state.allow_shutdown
	{
		if let Some( ( rgba, w, h ) ) = &state.shutdown_icon
		{
			controls = controls.push(
				icon_button::<Msg>( rgba.clone(), *w, *h )
					.icon_size( 48.0 )
					.on_press_maybe( active.then_some( Msg::ShutdownPressed ) )
			);
		}
	}

	if state.allow_reboot
	{
		if let Some( ( rgba, w, h ) ) = &state.reboot_icon
		{
			controls = controls.push(
				icon_button::<Msg>( rgba.clone(), *w, *h )
					.icon_size( 48.0 )
					.on_press_maybe( active.then_some( Msg::RebootPressed ) )
			);
		}
	}

	Some(
		column::<Msg>()
			.padding( 32.0 )
			.push( ltk::spacer() )
			.push( controls )
			.into()
	)
}
