use std::marker::PhantomData;

use bevy::app::{App, CoreStage, Plugin, PluginGroup, PluginGroupBuilder};
use bevy_kira_audio::{AudioApp, AudioPlugin};

use crate::channels::{
	AmbianceAudioChannel, MusicAudioChannel, SfxAudioChannel, UiSfxAudioChannel,
};
use crate::music_box::MusicBoxState;
use crate::utilities::{AudioSettings, SuppliesAudio};

/// Musicbox encapsulates the concept of different sound types in a number of preset channels, that
/// can be used in certain ways
pub mod channels;
pub mod music_box;
pub mod utilities;

pub mod prelude {
	pub use bevy_kira_audio::{
		AudioChannel, AudioControl, AudioEasing, AudioInstance, AudioSettings as KiraAudioSettings,
		AudioSource, AudioTween,
	};

	pub use super::channels::*;
	pub use super::music_box::MusicBox;
	pub use super::utilities::AudioSettings;
}

pub struct MusicBoxPlugin<T: SuppliesAudio> {
	_t: PhantomData<T>,
}

impl<T: SuppliesAudio> Default for MusicBoxPlugin<T> {
	fn default() -> Self {
		Self {
			_t: PhantomData::default(),
		}
	}
}

impl<T: SuppliesAudio> MusicBoxPlugin<T> {
	pub fn new() -> MusicBoxPlugin<T> {
		Default::default()
	}
}

impl<T: SuppliesAudio> Plugin for MusicBoxPlugin<T> {
	fn build(&self, app: &mut App) {
		app.add_audio_channel::<MusicAudioChannel>()
			.add_audio_channel::<AmbianceAudioChannel>()
			.add_audio_channel::<SfxAudioChannel>()
			.add_audio_channel::<UiSfxAudioChannel>()
			.insert_resource(AudioSettings::default())
			.insert_resource(MusicBoxState::default())
			.add_system_to_stage(CoreStage::Last, utilities::sync_music_volume::<T>);
	}
}

pub struct CombinedAudioPlugins<T: SuppliesAudio> {
	_t: PhantomData<T>,
}

impl<T: SuppliesAudio> Default for CombinedAudioPlugins<T> {
	fn default() -> Self {
		Self {
			_t: PhantomData::default(),
		}
	}
}

impl<T: SuppliesAudio> CombinedAudioPlugins<T> {
	pub fn new() -> CombinedAudioPlugins<T> {
		Default::default()
	}
}

impl<T: SuppliesAudio> PluginGroup for CombinedAudioPlugins<T> {
	fn build(&mut self, group: &mut PluginGroupBuilder) {
		group.add(AudioPlugin).add(MusicBoxPlugin::<T>::new());
	}
}