//! Sample bank

use fmod;
use vec_map::VecMap;

/// A vecmap of FMOD sounds.
#[derive(Debug, PartialEq)]
pub struct Sampler {
  samples : VecMap <fmod::Sound>,
  system  : fmod::System
}

pub type IndexType = u16;
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Id (pub IndexType);

impl Sampler {
  pub fn new (system : &fmod::System) -> Self {
    Sampler {
      samples: VecMap::new(),
      system:  system.clone()
    }
  }

  #[inline]
  #[expect(clippy::missing_panics_doc)]
  pub fn load (&mut self, files : VecMap <String>) {
    let samples = files.into_iter().map (|(i, s)|
      ( i,
        self.system.create_sound_from_file (&s, fmod::Mode::DEFAULT, None).unwrap()
      )
    ).collect::<VecMap <fmod::Sound>>();
    self.samples.extend (samples);
  }
  #[inline]
  #[expect(clippy::missing_panics_doc)]
  pub fn load_memory (&mut self, files : VecMap <&[u8]>) {
    let samples = files.into_iter().map (|(i, bytes)|
      ( i,
        self.system.create_sound_from_memory (bytes, fmod::Mode::DEFAULT, None).unwrap()
      )
    ).collect::<VecMap <fmod::Sound>>();
    self.samples.extend (samples);
  }
  #[inline]
  #[expect(clippy::missing_panics_doc)]
  pub fn load_pcm (&mut self, pcms : VecMap <&[i16]>) {
    let samples = pcms.into_iter().map (|(i, pcm)|
      ( i,
        self.system.create_sound_from_pcm (pcm, fmod::Mode::DEFAULT, None).unwrap()
      )
    ).collect::<VecMap <fmod::Sound>>();
    self.samples.extend (samples);
  }
  #[inline]
  pub fn get (&self, id : Id) -> Option <&fmod::Sound> {
    self.samples.get (id.0 as usize)
  }
  #[inline]
  pub fn get_mut (&mut self, id : Id) -> Option <&mut fmod::Sound> {
    self.samples.get_mut (id.0 as usize)
  }
  #[inline]
  pub fn set (&mut self, sample : fmod::Sound, id : Id) {
    let _ = self.samples.insert (id.0 as usize, sample);
  }
  #[inline]
  pub fn remove (&mut self, id : Id) -> Option <fmod::Sound> {
    self.samples.remove (id.0 as usize)
  }
  /// Start playing on a fresh channel; the priority system will "steal" an
  /// existing channel if there are no free channels.
  ///
  /// If no mode is given, the current mode for the sound (`sound.get_mode()`)
  /// will be used. Providing a mode will set the mode on the sound.
  #[inline]
  #[expect(clippy::missing_panics_doc)]
  pub fn play (&mut self,
    id            : Id,
    mode          : Option <fmod::Mode>,
    channel_group : Option <&mut fmod::ChannelGroup>
  ) -> fmod::Channel {
    let sample = self.samples.get_mut (id.0 as usize).unwrap();
    mode.map (|mode| sample.set_mode (mode).unwrap());
    sample.play (channel_group, false).unwrap()
  }
  /// "Play" on a fresh channel with 'paused = true'
  #[inline]
  #[expect(clippy::missing_panics_doc)]
  pub fn cue (&mut self,
    id            : Id,
    mode          : Option <fmod::Mode>,
    channel_group : Option <&mut fmod::ChannelGroup>
  ) -> fmod::Channel {
    let sample = self.samples.get_mut (id.0 as usize).unwrap();
    mode.map (|mode| sample.set_mode (mode).unwrap());
    sample.play (channel_group, true).unwrap()
  }
}

impl Id {
  #[inline]
  pub const fn index (&self) -> usize {
    self.0 as usize
  }
}
