use crate::ui::prelude::*;
use crate::system;

pub( crate ) fn view_bluetooth( state: &State ) -> Element<Msg>
{
	let mut col = column::<Msg>()
		.padding( 24.0 )
		.spacing( 4.0 )
		.push( header( &tr!( "home.bluetooth" ) ) )
		.push( toggle_row( tr!( "home.bluetooth" ), state.bt_on, Msg::ToggleBluetooth ) );

	if state.bt_on
	{
		col = col.push( separator() );

		let mut known: Vec<&system::BluetoothDevice> =
			state.bt_devices.iter().filter( |d| d.paired ).collect();
		known.sort_by_key( |d| !d.connected );
		for dev in known
		{
			col = col.push( bt_device_row( state, dev ) );
			if state.bt_selected.as_deref() == Some( dev.addr.as_str() )
			{
				col = col.push( bt_device_actions( state, dev ) );
			}
		}

		col = col.push(
			row::<Msg>()
				.push( t_sec!( tr!( "bt.available" ) ).size( 13.0 ) )
				.push( spacer() )
				.push( refresh_button( state.bt_scanning, Msg::BtScan ) )
		);
		col = col.push( spacer().height( 8.0 ) );

		// Discovery delivers results in bursts, so the spinner stays up
		// while devices are already appearing underneath it.
		if state.bt_scanning
		{
			col = col.push( scanning_row( state.started_at.elapsed().as_secs_f32() ) );
		}

		let discovered: Vec<&system::BluetoothDevice> =
			state.bt_devices.iter().filter( |d| !d.paired ).collect();

		if discovered.is_empty()
		{
			if !state.bt_scanning
			{
				col = col.push( t_sec!( tr!( "bt.none_found" ) ).size( 13.0 ) );
			}
		} else {
			let mut dev_col = column::<Msg>().padding( 0.0 ).spacing( 0.0 );
			for dev in discovered
			{
				dev_col = dev_col.push( bt_device_row( state, dev ) );
				if state.bt_selected.as_deref() == Some( dev.addr.as_str() )
				{
					dev_col = dev_col.push( bt_device_actions( state, dev ) );
				}
			}
			return col.push( scroll( dev_col ) ).into();
		}
	}

	col.push( spacer() ).into()
}

// BlueZ derives a freedesktop icon name from each device's Class of
// Device; map the common ones onto the theme catalogue and fall back
// to the plain Bluetooth glyph (also for categories the catalogue has
// no icon for yet: computers, watches, gamepads).
fn bt_device_icon( bluez_icon: &str ) -> &'static str
{
	match bluez_icon
	{
		"input-mouse"                        => "hardware/mouse",
		"input-keyboard"                     => "hardware/keyboard",
		"audio-headset" | "audio-headphones" => "hardware/headphones-bluetooth",
		"audio-card" | "audio-speakers"      => "hardware/speaker-high",
		"phone"                              => "communication/phone",
		"camera-photo" | "camera-video"      => "features/camera-app",
		"printer"                            => "hardware/printer",
		"video-display"                      => "hardware/external-monitor",
		_                                    => "system/bluetooth-connected",
	}
}

fn bt_device_row( state: &State, dev: &system::BluetoothDevice ) -> Element<Msg>
{
	let mut it = list_item( &dev.name )
		.on_press( Msg::SelectBt( dev.addr.clone() ) );
	it = with_icon( it, bt_device_icon( &dev.icon ) );
	if dev.connected || dev.paired
	{
		let kind = if dev.connected { StatusDot::Active } else { StatusDot::Known };
		let ( rgba, w, h ) = status_dot( kind );
		it = it.trailing_icon( rgba, w, h );
	}
	if state.bt_connecting.as_deref() == Some( dev.addr.as_str() )
	{
		it = it.subtitle( tr!( "common.connecting" ) );
	} else if dev.connected {
		it = it.subtitle( tr!( "common.connected" ) );
	} else if dev.paired {
		it = it.subtitle( tr!( "bt.paired" ) );
	}
	it.into()
}

fn bt_device_actions( state: &State, dev: &system::BluetoothDevice ) -> Element<Msg>
{
	let mut col = column::<Msg>().spacing( 8.0 ).padding( 8.0 );

	if let Some( ( addr, err ) ) = &state.bt_error
	{
		if addr == &dev.addr
		{
			let key = match err
			{
				system::BtConnectError::PairingFailed => "bt.pairing_failed",
				system::BtConnectError::ConnectFailed => "bt.could_not_connect",
			};
			col = col.push( t_sec!( tr!( key ) ).size( 13.0 ) );
		}
	}

	let mut buttons = row::<Msg>().spacing( 8.0 );
	if dev.connected
	{
		buttons = buttons.push(
			button( tr!( "common.disconnect" ) )
				.on_press( Msg::BtDisconnect( dev.addr.clone() ) )
		);
	} else {
		let mut connect = button( tr!( "common.connect" ) );
		if state.bt_connecting.is_none()
		{
			connect = connect.on_press( Msg::BtConnect( dev.addr.clone() ) );
		}
		buttons = buttons.push( connect );
	}
	if dev.paired
	{
		buttons = buttons.push(
			button( tr!( "common.forget" ) )
				.variant( ButtonVariant::Tertiary )
				.on_press( Msg::BtForget( dev.addr.clone() ) )
		);
	}

	col.push( buttons ).into()
}
