// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only

use rustc_hash::FxHashMap;

use std::{
    fmt::Debug,
    hash::Hash,
    sync::{
        Arc, LazyLock,
        atomic::{AtomicBool, Ordering},
    },
    time::Duration,
};

use bluer::{
    Adapter, AdapterProperty, Address, Session, Uuid,
    agent::{Agent, AgentHandle},
};

use cosmic::{
    iced::stream,
    iced::{
        self, Subscription,
        futures::{SinkExt, StreamExt},
    },
};

use futures::{FutureExt, stream::FuturesUnordered};
use tokio::{
    spawn,
    sync::{
        Mutex, RwLock,
        mpsc::{Receiver, Sender, channel},
    },
    task::JoinHandle,
};

static TICK: LazyLock<RwLock<Duration>> = LazyLock::new(|| RwLock::new(Duration::from_secs(10)));
static DISCOVERY: AtomicBool = AtomicBool::new(false);

pub fn set_discovery(v: bool) {
    DISCOVERY.store(v, Ordering::Relaxed);
}

pub async fn set_tick(duration: Duration) {
    let mut guard = TICK.write().await;
    *guard = duration;
}

pub async fn tick(interval: &mut tokio::time::Interval) {
    let guard = TICK.read().await;
    if *guard != interval.period() {
        *interval = tokio::time::interval(*guard);
        interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
    }
    interval.tick().await;
}
// Copied from https://github.com/bluez/bluez/blob/39467578207889fd015775cbe81a3db9dd26abea/src/dbus-common.c#L53
#[inline]
fn device_type_to_icon(device_type: &str) -> &'static str {
    match device_type {
        "computer" => "laptop-symbolic",
        "phone" => "smartphone-symbolic",
        "network-wireless" => "network-wireless-symbolic",
        "audio-headset" => "audio-headset-symbolic",
        "audio-headphones" => "audio-headphones-symbolic",
        "camera-video" => "camera-video-symbolic",
        "audio-card" => "audio-card-symbolic",
        "input-gaming" => "input-gaming-symbolic",
        "input-keyboard" => "input-keyboard-symbolic",
        "input-tablet" => "input-tablet-symbolic",
        "input-mouse" => "input-mouse-symbolic",
        "printer" => "printer-network-symbolic",
        "camera-photo" => "camera-photo-symbolic",
        _ => DEFAULT_DEVICE_ICON,
    }
}

// In some distros, rfkill is only in sbin, which isn't normally in PATH
// TODO: Directly access `/dev/rfkill`
fn rfkill_path_var() -> std::ffi::OsString {
    let mut path = std::env::var_os("PATH").unwrap_or_default();
    path.push(":/usr/sbin");
    path
}

#[inline]
pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
    id: I,
) -> iced::Subscription<BluerEvent> {
    Subscription::run_with(id, |_| {
        stream::channel(
            50,
            move |mut output: futures::channel::mpsc::Sender<BluerEvent>| async move {
                let mut retry_count = 0u32;

                // Initialize connection.
                let mut session_state = loop {
                    if let Ok(session) = Session::new().await {
                        if let Ok(state) = BluerSessionState::new(session).await {
                            break state;
                        }
                    }

                    retry_count = retry_count.saturating_add(1);
                    () = tokio::time::sleep(Duration::from_millis(
                        2_u64.saturating_pow(retry_count).min(68719476734),
                    ))
                    .await;
                };

                let state = bluer_state(&session_state.adapter).await;

                // reconnect to paired and trusted devices
                if state.bluetooth_enabled {
                    for d in &state.devices {
                        if d.paired_and_trusted()
                            && !matches!(d.status, BluerDeviceStatus::Connected)
                        {
                            _ = session_state
                                .req_tx
                                .send(BluerRequest::ConnectDevice(d.address))
                                .await;
                        }
                    }
                }
                _ = output
                    .send(BluerEvent::Init {
                        sender: session_state.req_tx.clone(),
                        state: state.clone(),
                    })
                    .await;

                let mut event_handler = async |event| {
                    let message = match event {
                        BluerSessionEvent::ChangesProcessed(state) => {
                            BluerEvent::DevicesChanged { state }
                        }

                        BluerSessionEvent::RequestResponse {
                            req,
                            state,
                            err_msg,
                        } => BluerEvent::RequestResponse {
                            req,
                            state,
                            err_msg,
                        },

                        BluerSessionEvent::AgentEvent(e) => BluerEvent::AgentEvent(e),

                        _ => return,
                    };

                    _ = output.send(message).await;
                };

                let mut interval = tokio::time::interval(Duration::from_secs(10));
                interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
                loop {
                    let Some(mut session_rx) = session_state.rx.take() else {
                        break;
                    };

                    if let Some(event) = session_rx.recv().await {
                        event_handler(event).await;
                        // Consume any additional available events.
                        let mut count = 0;
                        while let Ok(event) = session_rx.try_recv() {
                            event_handler(event).await;
                            count += 1;
                            if count == 100 {
                                break;
                            }
                        }
                    } else {
                        break;
                    }

                    session_state.rx = Some(session_rx);
                    interval.tick().await;
                }

                _ = output.send(BluerEvent::Finished).await;
                futures::future::pending().await
            },
        )
    })
}

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum BluerRequest {
    SetBluetoothEnabled(bool),
    PairDevice(Address),
    ConnectDevice(Address),
    DisconnectDevice(Address),
    CancelConnect(Address),
}

#[derive(Debug, Clone)]
pub enum BluerEvent {
    RequestResponse {
        req: BluerRequest,
        state: BluerState,
        err_msg: Option<String>,
    },
    Init {
        sender: Sender<BluerRequest>,
        state: BluerState,
    },
    DevicesChanged {
        state: BluerState,
    },
    AgentEvent(BluerAgentEvent),
    Finished,
}

#[derive(Debug, Clone, Default)]
pub struct BluerState {
    pub devices: Vec<BluerDevice>,
    pub bluetooth_enabled: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum BluerDeviceStatus {
    Connected,
    Connecting,
    Paired,
    /// Pairing is in progress, maybe with a passkey or pincode
    /// passkey or pincode will be 000000 - 999999
    Pairing,
    Disconnected,
    Disconnecting,
}

#[derive(Debug, Clone)]
pub struct BluerDevice {
    pub name: String,
    pub icon: &'static str,
    pub address: Address,
    pub status: BluerDeviceStatus,
    pub battery_percent: Option<u8>,
    pub is_paired: bool,
    pub is_trusted: bool,
}

impl Eq for BluerDevice {}

impl Ord for BluerDevice {
    #[inline]
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        match self.status.cmp(&other.status) {
            std::cmp::Ordering::Equal => self.name.to_lowercase().cmp(&other.name.to_lowercase()),
            o => o,
        }
    }
}

impl PartialOrd for BluerDevice {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for BluerDevice {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name && self.address == other.address
    }
}

const DEFAULT_DEVICE_ICON: &str = "bluetooth-symbolic";

impl BluerDevice {
    #[inline(never)]
    pub async fn from_device(device: &bluer::Device) -> Self {
        let (mut name, is_paired, is_trusted, is_connected, battery_percent, icon) = futures::join!(
            device
                .name()
                .map(|res| res.ok().flatten().unwrap_or(device.address().to_string())),
            device.is_paired().map(Result::unwrap_or_default),
            device.is_trusted().map(Result::unwrap_or_default),
            device.is_connected().map(Result::unwrap_or_default),
            device.battery_percentage().map(|res| res.ok().flatten()),
            device
                .icon()
                .map(|res| device_type_to_icon(&res.ok().flatten().unwrap_or_default()))
        );

        if name.is_empty() {
            name = device.address().to_string();
        }

        let status = if is_connected {
            BluerDeviceStatus::Connected
        } else if is_paired {
            BluerDeviceStatus::Paired
        } else {
            BluerDeviceStatus::Disconnected
        };

        Self {
            name,
            icon,
            address: device.address(),
            status,
            battery_percent,
            is_paired,
            is_trusted,
        }
    }

    #[inline]
    fn paired_and_trusted(&self) -> bool {
        self.is_paired && self.is_trusted
    }

    #[inline]
    #[must_use]
    pub fn is_known_device_type(&self) -> bool {
        self.icon != DEFAULT_DEVICE_ICON
    }

    #[inline]
    #[must_use]
    pub fn has_name(&self) -> bool {
        self.name != self.address.to_string()
    }
}

#[derive(Debug, Clone)]
pub enum BluerSessionEvent {
    RequestResponse {
        req: BluerRequest,
        state: BluerState,
        err_msg: Option<String>,
    },
    ChangesProcessed(BluerState),
    AgentEvent(BluerAgentEvent),
}

#[derive(Debug, Clone)]
pub enum BluerAgentEvent {
    DisplayPinCode(BluerDevice, String),
    DisplayPasskey(BluerDevice, String),
    RequestPinCode(BluerDevice),
    RequestPasskey(BluerDevice),
    RequestConfirmation(BluerDevice, String, Sender<bool>), // Note mpsc channel is used bc the sender must be cloned in the iced Message machinery
    RequestDeviceAuthorization(BluerDevice, Sender<bool>),
    RequestServiceAuthorization(BluerDevice, Uuid, Sender<bool>),
}

pub struct BluerSessionState {
    _session: Session,
    _agent_handle: AgentHandle,
    pub adapter: Adapter,
    pub rx: Option<Receiver<BluerSessionEvent>>,
    pub req_tx: Sender<BluerRequest>,
    wake_up_discover_tx: Sender<()>,
    wake_up_discover_rx: Option<Receiver<()>>,
    tx: Sender<BluerSessionEvent>,
    active_requests: Arc<Mutex<FxHashMap<BluerRequest, JoinHandle<anyhow::Result<()>>>>>,
}

impl BluerSessionState {
    async fn new(session: Session) -> anyhow::Result<Self> {
        let adapter = session.default_adapter().await?;
        let (tx, rx) = tokio::sync::mpsc::channel(100);
        let (req_tx, req_rx) = channel(100);
        let tx_clone_1 = tx.clone();
        let tx_clone_2 = tx.clone();
        let tx_clone_3 = tx.clone();
        let tx_clone_4 = tx.clone();
        let tx_clone_5 = tx.clone();
        let tx_clone_6 = tx.clone();
        let tx_clone_7 = tx.clone();
        let adapter_clone_1 = adapter.clone();
        let adapter_clone_2 = adapter.clone();
        let adapter_clone_3 = adapter.clone();
        let adapter_clone_4 = adapter.clone();
        let adapter_clone_5 = adapter.clone();
        let adapter_clone_6 = adapter.clone();
        let adapter_clone_7 = adapter.clone();

        let _agent = Agent {
            request_default: false, // TODO which agent should eventually become the default? Maybe the one in the settings app?
            request_pin_code: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_1.clone();
                let tx_clone = tx_clone_1.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::RequestPinCode(
                                BluerDevice::from_device(&device).await,
                            ),
                        ))
                        .await;
                    let pin_code = fastrand::u32(0..999999);
                    Ok(format!("{pin_code:06}"))
                })
            })),
            display_pin_code: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_2.clone();
                let tx_clone = tx_clone_2.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::DisplayPinCode(
                                BluerDevice::from_device(&device).await,
                                req.pincode,
                            ),
                        ))
                        .await;

                    Ok(())
                })
            })),
            request_passkey: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_3.clone();
                let tx_clone = tx_clone_3.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::RequestPasskey(
                                BluerDevice::from_device(&device).await,
                            ),
                        ))
                        .await;
                    let pin_code = fastrand::u32(0..999999);
                    Ok(pin_code)
                })
            })),
            display_passkey: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_4.clone();
                let tx_clone = tx_clone_4.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::DisplayPasskey(
                                BluerDevice::from_device(&device).await,
                                format!("{:06}", req.passkey),
                            ),
                        ))
                        .await;
                    Ok(())
                })
            })),
            request_confirmation: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_5.clone();
                let tx_clone = tx_clone_5.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let (tx, mut rx) = channel(1);
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::RequestConfirmation(
                                BluerDevice::from_device(&device).await,
                                format!("{:06}", req.passkey),
                                tx,
                            ),
                        ))
                        .await;
                    let res = rx.recv().await;
                    match res {
                        Some(res) if res => Ok(()),
                        _ => Err(bluer::agent::ReqError::Rejected),
                    }
                })
            })),
            request_authorization: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_6.clone();
                let tx_clone = tx_clone_6.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let (tx, mut rx) = channel(1);
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::RequestDeviceAuthorization(
                                BluerDevice::from_device(&device).await,
                                tx,
                            ),
                        ))
                        .await;
                    let res = rx.recv().await;
                    match res {
                        Some(res) if res => Ok(()),
                        _ => Err(bluer::agent::ReqError::Rejected),
                    }
                })
            })),
            authorize_service: Some(Box::new(move |req| {
                let agent_clone = adapter_clone_7.clone();
                let tx_clone = tx_clone_7.clone();
                Box::pin(async move {
                    let Ok(device) = agent_clone.device(req.device) else {
                        return Err(bluer::agent::ReqError::Rejected);
                    };
                    let (tx, mut rx) = channel(1);
                    // TODO better describe the service to the user
                    let _ = tx_clone
                        .send(BluerSessionEvent::AgentEvent(
                            BluerAgentEvent::RequestServiceAuthorization(
                                BluerDevice::from_device(&device).await,
                                req.service,
                                tx,
                            ),
                        ))
                        .await;
                    let res = rx.recv().await;
                    match res {
                        Some(res) if res => Ok(()),
                        _ => Err(bluer::agent::ReqError::Rejected),
                    }
                })
            })),
            _non_exhaustive: (),
        };
        let _agent_handle = session.register_agent(_agent).await?;
        let (wake_up_discover_tx, wake_up_discover_rx) = channel(10);
        let mut self_ = Self {
            _agent_handle,
            _session: session,
            adapter,
            rx: Some(rx),
            req_tx,
            wake_up_discover_rx: Some(wake_up_discover_rx),
            wake_up_discover_tx,
            tx,
            active_requests: Default::default(),
        };
        self_.process_requests(req_rx);
        self_.process_changes();
        self_.listen_bluetooth_power_changes();

        Ok(self_)
    }

    #[inline]
    fn listen_bluetooth_power_changes(&self) {
        let tx = self.tx.clone();
        let req_tx = self.req_tx.clone();
        let adapter_clone = self.adapter.clone();
        let wake_up_discover_tx = self.wake_up_discover_tx.clone();
        let _handle: JoinHandle<anyhow::Result<()>> = spawn(async move {
            let mut status = adapter_clone.is_powered().await.unwrap_or_default();
            let mut interval = tokio::time::interval(Duration::from_secs(10));
            interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
            let mut devices = Vec::new();
            loop {
                tick(&mut interval).await;
                let new_status = adapter_clone.is_powered().await.unwrap_or_default();
                devices = build_device_list(devices, &adapter_clone).await;
                let power_changed = new_status != status;
                status = new_status;
                let state = BluerState {
                    devices: devices.clone(),
                    bluetooth_enabled: status,
                };
                if power_changed && state.bluetooth_enabled {
                    for d in &state.devices {
                        if d.paired_and_trusted() {
                            _ = req_tx.send(BluerRequest::ConnectDevice(d.address)).await;
                        }
                    }
                    _ = wake_up_discover_tx.send(()).await;
                }
                let _ = tx.send(BluerSessionEvent::ChangesProcessed(state)).await;
            }
        });
    }

    #[inline]
    fn process_changes(&mut self) {
        let req_tx = self.req_tx.clone();
        let tx = self.tx.clone();
        let Some(mut wake_up) = self.wake_up_discover_rx.take() else {
            tracing::error!("Failed to take wake up channel");
            return;
        };
        let adapter_clone = self.adapter.clone();

        _ = spawn(async move {
            let mut is_powered = adapter_clone.is_powered().await.unwrap_or_default();

            let mut devices: Vec<BluerDevice> = Vec::new();
            let mut interval = tokio::time::interval(Duration::from_secs(1));
            interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);

            loop {
                interval.tick().await;

                let wakeup_fut = wake_up.recv();

                let listener_fut = async {
                    if DISCOVERY.load(Ordering::SeqCst) || devices.is_empty() {
                        let mut interval = tokio::time::interval(Duration::from_secs(10));
                        interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
                        let Ok(mut change_stream) =
                            adapter_clone.discover_devices_with_changes().await
                        else {
                            tick(&mut interval).await;
                            return;
                        };

                        loop {
                            let Some(adapter_event) = change_stream.next().await else {
                                break;
                            };
                            match adapter_event {
                                bluer::AdapterEvent::PropertyChanged(AdapterProperty::Powered(
                                    v,
                                )) => {
                                    is_powered = v;
                                }
                                e => {
                                    match e {
                                        bluer::AdapterEvent::DeviceAdded(address)
                                            if !devices.iter().any(|d| d.address == address) =>
                                        {
                                            devices =
                                                build_device_list(Vec::new(), &adapter_clone).await;
                                            for d in devices.iter().filter(|d| {
                                                d.paired_and_trusted()
                                                    && !matches!(
                                                        d.status,
                                                        BluerDeviceStatus::Connected
                                                    )
                                            }) {
                                                _ = req_tx
                                                    .send(BluerRequest::ConnectDevice(d.address))
                                                    .await;
                                            }
                                        }
                                        bluer::AdapterEvent::DeviceRemoved(address)
                                            if devices.iter().any(|d| d.address == address) =>
                                        {
                                            // Remove the device from new_devices if it exists
                                            devices.retain(|d| d.address != address);
                                        }

                                        bluer::AdapterEvent::PropertyChanged(p) => {
                                            tracing::info!("property change ignored {p:?}");
                                            interval.tick().await;
                                            continue;
                                        }
                                        bluer::AdapterEvent::DeviceAdded(address)
                                        | bluer::AdapterEvent::DeviceRemoved(address) => {
                                            tracing::info!(
                                                "device change that is already handled {address}"
                                            );
                                            interval.tick().await;
                                            continue;
                                        }
                                    }
                                }
                            }

                            // Always refresh power state from the adapter
                            // to avoid stale cached is_powered values
                            is_powered = adapter_clone.is_powered().await.unwrap_or_default();
                            let _ = tx
                                .send(BluerSessionEvent::ChangesProcessed(BluerState {
                                    devices: devices.clone(),
                                    bluetooth_enabled: is_powered,
                                }))
                                .await;

                            interval.tick().await;
                            if !DISCOVERY.load(Ordering::SeqCst) && !devices.is_empty() {
                                break;
                            }
                        }
                    } else {
                        loop {
                            if DISCOVERY.load(Ordering::SeqCst) || devices.is_empty() {
                                break;
                            }
                            interval.tick().await;
                        }
                    }
                };

                futures::pin_mut!(listener_fut);
                futures::pin_mut!(wakeup_fut);

                futures::future::select(listener_fut, wakeup_fut).await;
            }
        });
    }

    #[inline]
    fn process_requests(&mut self, request_rx: Receiver<BluerRequest>) {
        let active_requests = self.active_requests.clone();
        let adapter = self.adapter.clone();
        let tx = self.tx.clone();
        let wake_up_tx = self.wake_up_discover_tx.clone();

        let _handle: JoinHandle<anyhow::Result<()>> = spawn(async move {
            let mut request_rx = request_rx;

            while let Some(req) = request_rx.recv().await {
                let req_clone = req.clone();
                let req_clone_2 = req.clone();
                let active_requests_clone = active_requests.clone();
                let tx_clone = tx.clone();
                let adapter_clone = adapter.clone();
                let wake_up_tx = wake_up_tx.clone();

                let handle = spawn(async move {
                    let mut err_msg = None;
                    match &req_clone {
                        BluerRequest::SetBluetoothEnabled(enabled) => {
                            if let Err(e) = adapter_clone.set_powered(*enabled).await {
                                tracing::error!("Failed to power off bluetooth adapter. {e:?}");
                            }

                            // rfkill will be persisted after reboot
                            let name = adapter_clone.name();
                            if let Some(id) = tokio::process::Command::new("rfkill")
                                .env("PATH", rfkill_path_var())
                                .arg("list")
                                .arg("-n")
                                .arg("--output")
                                .arg("ID,DEVICE")
                                .output()
                                .await
                                .ok()
                                .and_then(|o| {
                                    let lines = String::from_utf8(o.stdout).ok()?;
                                    lines.split('\n').into_iter().find_map(|row| {
                                        let (id, cname) = row.trim().split_once(' ')?;
                                        (name == cname).then_some(id.to_string())
                                    })
                                })
                            {
                                if let Err(err) = tokio::process::Command::new("rfkill")
                                    .env("PATH", rfkill_path_var())
                                    .arg(if *enabled { "unblock" } else { "block" })
                                    .arg(id)
                                    .output()
                                    .await
                                {
                                    tracing::error!(
                                        "Failed to set bluetooth state using rfkill. {err:?}"
                                    );
                                }
                            }

                            if *enabled {
                                _ = wake_up_tx.send(()).await;
                            }
                        }
                        BluerRequest::PairDevice(address) => {
                            let res = adapter_clone.device(*address);
                            if let Err(err) = res {
                                err_msg = Some(err.to_string());
                            } else if let Ok(device) = res {
                                let res = device.pair().await;
                                if let Err(err) = res {
                                    err_msg = Some(err.to_string());
                                } else {
                                    if let Err(err) = device.set_trusted(true).await {
                                        tracing::error!(?err, "Failed to trust device.");
                                    }
                                }
                            }
                        }
                        BluerRequest::ConnectDevice(address) => {
                            let res = adapter_clone.device(*address);
                            if let Err(err) = res {
                                err_msg = Some(err.to_string());
                            } else if let Ok(device) = res {
                                let res = device.connect().await;
                                if let Err(err) = res {
                                    err_msg = Some(err.to_string());
                                } else {
                                    if let Err(err) = device.set_trusted(true).await {
                                        tracing::error!(?err, "Failed to trust device.");
                                    }
                                }
                            }
                        }
                        BluerRequest::DisconnectDevice(address) => {
                            let res = adapter_clone.device(*address);
                            if let Err(err) = res {
                                err_msg = Some(err.to_string());
                            } else if let Ok(device) = res {
                                let res = device.disconnect().await;
                                if let Err(err) = res {
                                    err_msg = Some(err.to_string());
                                }
                            }
                        }
                        BluerRequest::CancelConnect(_) => {
                            if let Some(handle) = active_requests_clone.lock().await.get(&req_clone)
                            {
                                handle.abort();
                            } else {
                                err_msg = Some("No active connection request found".to_string());
                            }
                        }
                    }

                    let _ = tx_clone
                        .send(BluerSessionEvent::RequestResponse {
                            req: req_clone,
                            state: bluer_state(&adapter_clone).await,
                            err_msg,
                        })
                        .await;

                    active_requests_clone.lock().await.remove(&req_clone_2);

                    Ok(())
                });

                active_requests.lock().await.insert(req, handle);
            }
            Ok(())
        });
    }
}

#[inline]
async fn bluer_state(adapter: &Adapter) -> BluerState {
    let (devices, bluetooth_enabled) = futures::join!(
        build_device_list(Vec::new(), adapter),
        // TODO is this a proper way of checking if bluetooth is enabled?
        adapter.is_powered().map(Result::unwrap_or_default),
    );

    BluerState {
        devices,
        bluetooth_enabled,
    }
}

#[inline(never)]
async fn build_device_list(mut devices: Vec<BluerDevice>, adapter: &Adapter) -> Vec<BluerDevice> {
    let addrs = adapter.device_addresses().await.unwrap_or_default();

    devices.clear();
    if addrs.len() > devices.capacity() {
        devices.reserve(addrs.len() - devices.capacity());
    }

    // Concurrently collect bluer devices from each address.
    let mut device_stream = addrs
        .into_iter()
        .filter_map(|address| adapter.device(address).ok())
        .map(async move |device| BluerDevice::from_device(&device).await)
        .collect::<FuturesUnordered<_>>();

    while let Some(device) = device_stream.next().await {
        devices.push(device);
    }

    devices.sort_unstable();
    devices
}
