// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    anyhow::{format_err, Error},
    fidl::endpoints::RequestStream,
    fidl_fuchsia_bluetooth_control::{self as control, ControlRequest, ControlRequestStream},
    fuchsia_bluetooth::{bt_fidl_status, types::PeerId},
    fuchsia_syslog::fx_log_warn,
    futures::prelude::*,
    std::sync::Arc,
};

use crate::{host_dispatcher::*, types::status_response};

struct ControlSession {
    discovery_token: Option<Arc<DiscoveryRequestToken>>,
    discoverable_token: Option<Arc<DiscoverableRequestToken>>,
}

impl ControlSession {
    fn new() -> ControlSession {
        ControlSession { discovery_token: None, discoverable_token: None }
    }
}

/// Build the ControlImpl to interact with fidl messages
/// State is stored in the HostDispatcher object
pub async fn start_control_service(
    hd: HostDispatcher,
    mut stream: ControlRequestStream,
) -> Result<(), Error> {
    let event_listener = Arc::new(stream.control_handle());
    hd.add_event_listener(Arc::downgrade(&event_listener));
    let mut session = ControlSession::new();

    while let Some(event) = stream.next().await {
        handler(hd.clone(), &mut session, event?).await?;
    }
    // event_listener will now be dropped, closing the listener
    Ok(())
}

async fn handler(
    hd: HostDispatcher,
    session: &mut ControlSession,
    event: ControlRequest,
) -> fidl::Result<()> {
    match event {
        ControlRequest::Connect { device_id, responder } => {
            let result = hd.connect(device_id).await;
            responder.send(&mut status_response(result))
        }
        ControlRequest::Pair { id, options, responder } => {
            let result = hd.pair(id, options).await;
            responder.send(&mut status_response(result))
        }
        ControlRequest::SetDiscoverable { discoverable, responder } => {
            let mut resp = if discoverable {
                match hd.set_discoverable().await {
                    Ok(token) => {
                        session.discoverable_token = Some(token);
                        bt_fidl_status!()
                    }
                    Err(err) => err.as_status(),
                }
            } else {
                session.discoverable_token = None;
                bt_fidl_status!()
            };
            responder.send(&mut resp)
        }
        ControlRequest::SetIoCapabilities { input, output, control_handle: _ } => {
            hd.set_io_capability(input, output);
            Ok(())
        }
        ControlRequest::Forget { device_id, responder } => {
            let peer_id = device_id
                .parse::<PeerId>()
                .map_err(|_| format_err!(format!("Invalid peer identifier: {}", device_id)));
            let result = match peer_id {
                Ok(peer_id) => hd.forget(peer_id).await,
                Err(e) => Err(e.into()),
            };
            responder.send(&mut status_response(result))
        }
        ControlRequest::Disconnect { device_id, responder } => {
            let result = hd.disconnect(device_id).await;
            responder.send(&mut status_response(result))
        }
        ControlRequest::GetKnownRemoteDevices { responder } => {
            let mut devices: Vec<_> =
                hd.get_peers().into_iter().map(control::RemoteDevice::from).collect();
            responder.send(&mut devices.iter_mut())
        }
        ControlRequest::IsBluetoothAvailable { responder } => {
            let is_available = hd.get_active_host_info().is_some();
            responder.send(is_available)
        }
        ControlRequest::SetPairingDelegate { delegate, responder } => {
            let status = match delegate.map(|d| d.into_proxy()) {
                Some(Ok(proxy)) => hd.set_pairing_delegate(Some(proxy)),
                Some(Err(err)) => {
                    fx_log_warn!(
                        "Invalid Pairing Delegate passed to SetPairingDelegate - ignoring: {}",
                        err
                    );
                    false
                }
                None => hd.set_pairing_delegate(None),
            };
            responder.send(status)
        }
        ControlRequest::GetAdapters { responder } => {
            let mut adapters: Vec<_> =
                hd.get_adapters().await.into_iter().map(control::AdapterInfo::from).collect();
            responder.send(Some(&mut adapters.iter_mut()))
        }
        ControlRequest::SetActiveAdapter { identifier, responder } => {
            let result = hd.set_active_adapter(identifier.clone());
            responder.send(&mut status_response(result))
        }
        ControlRequest::GetActiveAdapterInfo { responder } => {
            let host_info = hd.get_active_host_info();
            responder.send(host_info.map(control::AdapterInfo::from).as_mut())
        }
        ControlRequest::RequestDiscovery { discovery, responder } => {
            let mut resp = if discovery {
                match hd.start_discovery().await {
                    Ok(token) => {
                        session.discovery_token = Some(token);
                        bt_fidl_status!()
                    }
                    Err(err) => err.as_status(),
                }
            } else {
                session.discovery_token = None;
                bt_fidl_status!()
            };
            responder.send(&mut resp)
        }
        ControlRequest::SetName { name, responder } => {
            let result = hd.set_name(name.unwrap_or("".to_string())).await;
            responder.send(&mut status_response(result))
        }
        ControlRequest::SetDeviceClass { device_class, responder } => {
            let device_class = fidl_fuchsia_bluetooth::DeviceClass { value: device_class.value };
            let result = hd.set_device_class(device_class).await;
            responder.send(&mut status_response(result))
        }
    }
}
