use super::BluetoothState;
use std::process::Command;

pub fn get_bluetooth_state() -> BluetoothState
{
	let output = Command::new( "bluetoothctl" )
		.args( ["show"] )
		.output();

	match output
	{
		Ok( out ) =>
		{
			let stdout = String::from_utf8_lossy( &out.stdout );
			let enabled = stdout.contains( "Powered: yes" );

			let connected_output = Command::new( "bluetoothctl" )
				.args( ["devices", "Connected"] )
				.output();

			let connected = match connected_output
			{
				Ok( out ) =>
				{
					let connected_stdout = String::from_utf8_lossy( &out.stdout );
					let lines: Vec<&str> = connected_stdout.lines().collect();
					!lines.is_empty() && !lines[0].trim().is_empty()
				}
				Err( _ ) => false,
			};

			BluetoothState { enabled, connected }
		}
		Err( _ ) => BluetoothState::default(),
	}
}

#[derive( Clone )]
pub struct WifiNetwork
{
	pub ssid:      String,
	pub signal:    u8,
	pub connected: bool,
}

#[derive( Clone )]
pub struct BluetoothDevice
{
	pub name:      String,
	pub address:   String,
	pub connected: bool,
}

pub fn scan_wifi_networks() -> Vec<WifiNetwork>
{
	let output = Command::new( "nmcli" )
		.args( ["-t", "-f", "ACTIVE,SIGNAL,SSID", "dev", "wifi", "list", "--rescan", "yes"] )
		.output();

	let text = match output
	{
		Ok( out ) => String::from_utf8_lossy( &out.stdout ).to_string(),
		Err( _ ) => return Vec::new(),
	};

	text.lines().filter_map( |line|
	{
		let parts: Vec<&str> = line.splitn( 3, ':' ).collect();
		if parts.len() < 3 { return None; }
		let ssid = parts[2].to_string();
		if ssid.is_empty() { return None; }
		Some( WifiNetwork
		{
			connected: parts[0] == "yes",
			signal:    parts[1].parse().unwrap_or( 0 ),
			ssid,
		})
	}).collect()
}

pub fn connect_wifi( ssid: &str )
{
	if let Err( e ) = Command::new( "nmcli" )
		.args( ["device", "wifi", "connect", ssid] )
		.spawn()
	{
		tracing::error!( "Failed to connect to WiFi '{}': {}", ssid, e );
	}
}

pub fn scan_bluetooth_devices() -> Vec<BluetoothDevice>
{
	let output = Command::new( "bluetoothctl" ).arg( "devices" ).output();
	let text = match output
	{
		Ok( out ) => String::from_utf8_lossy( &out.stdout ).to_string(),
		Err( _ ) => return Vec::new(),
	};

	let connected_out = Command::new( "bluetoothctl" )
		.args( ["devices", "Connected"] ).output().ok()
		.map( |o| String::from_utf8_lossy( &o.stdout ).to_string() )
		.unwrap_or_default();

	text.lines().filter_map( |line|
	{
		let rest = line.strip_prefix( "Device " )?;
		let ( addr, name ) = rest.split_once( ' ' )?;
		Some( BluetoothDevice
		{
			name:      name.to_string(),
			address:   addr.to_string(),
			connected: connected_out.contains( addr ),
		})
	}).collect()
}

pub fn connect_bluetooth( address: &str )
{
	if let Err( e ) = Command::new( "bluetoothctl" )
		.args( ["connect", address] )
		.spawn()
	{
		tracing::error!( "Failed to connect to Bluetooth '{}': {}", address, e );
	}
}

