//! Anything related to audio and media API.

use bt_topshim::btif::{BluetoothInterface, RawAddress};
use bt_topshim::profiles::a2dp::{
    A2dp, A2dpCallbacks, A2dpCallbacksDispatcher, A2dpCodecBitsPerSample, A2dpCodecChannelMode,
    A2dpCodecConfig, A2dpCodecIndex, A2dpCodecSampleRate, BtavConnectionState,
    PresentationPosition,
};
use bt_topshim::profiles::avrcp::{Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher};
use bt_topshim::profiles::hfp::{BthfConnectionState, Hfp, HfpCallbacks, HfpCallbacksDispatcher};

use bt_topshim::topstack;

use log::warn;

use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::Arc;
use std::sync::Mutex;

use tokio::sync::mpsc::Sender;

use crate::Message;

pub trait IBluetoothMedia {
    ///
    fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool;

    /// initializes media (both A2dp and AVRCP) stack
    fn initialize(&mut self) -> bool;

    /// clean up media stack
    fn cleanup(&mut self) -> bool;

    // TODO (b/204488289): Accept and validate RawAddress instead.
    fn connect(&mut self, device: String);
    fn set_active_device(&mut self, device: String);
    fn disconnect(&mut self, device: String);
    fn set_audio_config(
        &mut self,
        sample_rate: i32,
        bits_per_sample: i32,
        channel_mode: i32,
    ) -> bool;
    fn set_volume(&mut self, volume: i32);
    fn start_audio_request(&mut self);
    fn stop_audio_request(&mut self);
    fn get_presentation_position(&mut self) -> PresentationPosition;
}

pub trait IBluetoothMediaCallback {
    ///
    fn on_bluetooth_audio_device_added(
        &self,
        addr: String,
        sample_rate: i32,
        bits_per_sample: i32,
        channel_mode: i32,
    );

    ///
    fn on_bluetooth_audio_device_removed(&self, addr: String);

    ///
    fn on_absolute_volume_supported_changed(&self, supported: bool);

    ///
    fn on_absolute_volume_changed(&self, volume: i32);
}

/// Actions that `BluetoothMedia` can take on behalf of the stack.
pub enum MediaActions {
    Connect(String),
    Disconnect(String),
}

pub struct BluetoothMedia {
    intf: Arc<Mutex<BluetoothInterface>>,
    initialized: bool,
    callbacks: Vec<(u32, Box<dyn IBluetoothMediaCallback + Send>)>,
    callback_last_id: u32,
    tx: Sender<Message>,
    a2dp: Option<A2dp>,
    avrcp: Option<Avrcp>,
    a2dp_states: HashMap<RawAddress, BtavConnectionState>,
    hfp: Option<Hfp>,
    hfp_states: HashMap<RawAddress, BthfConnectionState>,
    selectable_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>,
}

impl BluetoothMedia {
    pub fn new(tx: Sender<Message>, intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothMedia {
        BluetoothMedia {
            intf,
            initialized: false,
            callbacks: vec![],
            callback_last_id: 0,
            tx,
            a2dp: None,
            avrcp: None,
            a2dp_states: HashMap::new(),
            hfp: None,
            hfp_states: HashMap::new(),
            selectable_caps: HashMap::new(),
        }
    }

    pub fn dispatch_a2dp_callbacks(&mut self, cb: A2dpCallbacks) {
        match cb {
            A2dpCallbacks::ConnectionState(addr, state) => {
                if !self.a2dp_states.get(&addr).is_none()
                    && state == *self.a2dp_states.get(&addr).unwrap()
                {
                    return;
                }
                match state {
                    BtavConnectionState::Connected => {
                        if let Some(caps) = self.selectable_caps.get(&addr) {
                            for cap in caps {
                                // TODO: support codecs other than SBC.
                                if A2dpCodecIndex::SrcSbc != A2dpCodecIndex::from(cap.codec_type) {
                                    continue;
                                }

                                self.for_all_callbacks(|callback| {
                                    callback.on_bluetooth_audio_device_added(
                                        addr.to_string(),
                                        cap.sample_rate,
                                        cap.bits_per_sample,
                                        cap.channel_mode,
                                    );
                                });
                                return;
                            }
                        }
                    }
                    BtavConnectionState::Connecting => {}
                    BtavConnectionState::Disconnected => {
                        self.for_all_callbacks(|callback| {
                            callback.on_bluetooth_audio_device_removed(addr.to_string());
                        });
                    }
                    BtavConnectionState::Disconnecting => {}
                };
                self.a2dp_states.insert(addr, state);
            }
            A2dpCallbacks::AudioState(_addr, _state) => {}
            A2dpCallbacks::AudioConfig(addr, _config, _local_caps, selectable_caps) => {
                self.selectable_caps.insert(addr, selectable_caps);
            }
            A2dpCallbacks::MandatoryCodecPreferred(_addr) => {}
        }
    }

    pub fn dispatch_avrcp_callbacks(&mut self, cb: AvrcpCallbacks) {
        match cb {
            AvrcpCallbacks::AvrcpAbsoluteVolumeEnabled(supported) => {
                self.for_all_callbacks(|callback| {
                    callback.on_absolute_volume_supported_changed(supported);
                });
            }
            AvrcpCallbacks::AvrcpAbsoluteVolumeUpdate(volume) => {
                self.for_all_callbacks(|callback| {
                    callback.on_absolute_volume_changed(i32::from(volume));
                });
            }
        }
    }

    pub fn dispatch_media_actions(&mut self, action: MediaActions) {
        match action {
            MediaActions::Connect(address) => self.connect(address),
            MediaActions::Disconnect(address) => self.disconnect(address),
        }
    }

    pub fn dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks) {
        match cb {
            HfpCallbacks::ConnectionState(state, addr) => {
                if !self.hfp_states.get(&addr).is_none()
                    && state == *self.hfp_states.get(&addr).unwrap()
                {
                    return;
                }
                match state {
                    BthfConnectionState::Connected => {
                        // TODO: Integrate with A2dp
                    }
                    BthfConnectionState::Connecting => {}
                    BthfConnectionState::Disconnected => {}
                    BthfConnectionState::Disconnecting => {
                        // TODO: Integrate with A2dp
                    }
                }
            }
        }
    }

    fn for_all_callbacks<F: Fn(&Box<dyn IBluetoothMediaCallback + Send>)>(&self, f: F) {
        for callback in &self.callbacks {
            f(&callback.1);
        }
    }
}

fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
    A2dpCallbacksDispatcher {
        dispatch: Box::new(move |cb| {
            let txl = tx.clone();
            topstack::get_runtime().spawn(async move {
                let _ = txl.send(Message::A2dp(cb)).await;
            });
        }),
    }
}

fn get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher {
    AvrcpCallbacksDispatcher {
        dispatch: Box::new(move |cb| {
            let txl = tx.clone();
            topstack::get_runtime().spawn(async move {
                let _ = txl.send(Message::Avrcp(cb)).await;
            });
        }),
    }
}

fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher {
    HfpCallbacksDispatcher {
        dispatch: Box::new(move |cb| {
            let txl = tx.clone();
            topstack::get_runtime().spawn(async move {
                let _ = txl.send(Message::Hfp(cb)).await;
            });
        }),
    }
}

impl IBluetoothMedia for BluetoothMedia {
    fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool {
        self.callback_last_id += 1;
        self.callbacks.push((self.callback_last_id, callback));
        true
    }

    fn initialize(&mut self) -> bool {
        if self.initialized {
            return false;
        }
        self.initialized = true;

        // TEST A2dp
        let a2dp_dispatcher = get_a2dp_dispatcher(self.tx.clone());
        self.a2dp = Some(A2dp::new(&self.intf.lock().unwrap()));
        self.a2dp.as_mut().unwrap().initialize(a2dp_dispatcher);

        // AVRCP
        let avrcp_dispatcher = get_avrcp_dispatcher(self.tx.clone());
        self.avrcp = Some(Avrcp::new(&self.intf.lock().unwrap()));
        self.avrcp.as_mut().unwrap().initialize(avrcp_dispatcher);

        // HFP
        let hfp_dispatcher = get_hfp_dispatcher(self.tx.clone());
        self.hfp = Some(Hfp::new(&self.intf.lock().unwrap()));
        self.hfp.as_mut().unwrap().initialize(hfp_dispatcher);

        true
    }

    fn connect(&mut self, device: String) {
        let addr = RawAddress::from_string(device.clone());
        if addr.is_none() {
            warn!("Invalid device string {}", device);
            return;
        }

        self.a2dp.as_mut().unwrap().connect(device);
        self.hfp.as_mut().unwrap().connect(addr.unwrap());
    }

    fn cleanup(&mut self) -> bool {
        true
    }

    fn set_active_device(&mut self, device: String) {
        self.a2dp.as_mut().unwrap().set_active_device(device);
    }

    fn disconnect(&mut self, device: String) {
        let addr = RawAddress::from_string(device.clone());
        if addr.is_none() {
            warn!("Invalid device string {}", device);
            return;
        }

        self.a2dp.as_mut().unwrap().disconnect(device);
        self.hfp.as_mut().unwrap().disconnect(addr.unwrap());
    }

    fn set_audio_config(
        &mut self,
        sample_rate: i32,
        bits_per_sample: i32,
        channel_mode: i32,
    ) -> bool {
        if !A2dpCodecSampleRate::validate_bits(sample_rate)
            || !A2dpCodecBitsPerSample::validate_bits(bits_per_sample)
            || !A2dpCodecChannelMode::validate_bits(channel_mode)
        {
            return false;
        }
        self.a2dp.as_mut().unwrap().set_audio_config(sample_rate, bits_per_sample, channel_mode);
        true
    }

    fn set_volume(&mut self, volume: i32) {
        match i8::try_from(volume) {
            Ok(val) => self.avrcp.as_mut().unwrap().set_volume(val),
            _ => (),
        };
    }

    fn start_audio_request(&mut self) {
        self.a2dp.as_mut().unwrap().start_audio_request();
    }

    fn stop_audio_request(&mut self) {
        self.a2dp.as_mut().unwrap().stop_audio_request();
    }

    fn get_presentation_position(&mut self) -> PresentationPosition {
        let position = self.a2dp.as_mut().unwrap().get_presentation_position();
        PresentationPosition {
            remote_delay_report_ns: position.remote_delay_report_ns,
            total_bytes_read: position.total_bytes_read,
            data_position_sec: position.data_position_sec,
            data_position_nsec: position.data_position_nsec,
        }
    }
}
