using UnityEngine;
using System.Collections.Generic;

/* Usage :
   - Placer ce script sur un GameObject vide, nom au choix
   - Pour jouer un son depuis n'importe quel script : SoundManager.PlaySound(nomDeMonSonSansExtension)
   Il y a la même chose pour la musique.
*/

public class SoundManager : MonoBehaviour {

    [SerializeField] private int numberOfSoundChannels = 16; // Combien de sons veut-on pouvoir jouer en même temps à un moment donné ?
    [SerializeField] private bool playMusicOnStart = true; // Doit-on jouer une musique dès le lancement de l'application ?
    [SerializeField] private string nameOfMusicOnStart = ""; // Nom de la musique à jouer au lancement de l'application
    [SerializeField] private string nameOfSoundsFolderInResources = "sounds"; // Nom du fichier contenant tous les sons, à placer dans Resources
    [SerializeField] private string nameOfMusicsFolderInResources = "musics"; // Idem mais pour les musiques

    private static Dictionary<string, AudioClip> sounds;
    private static Dictionary<string, AudioClip> musics;

    private static List<AudioSource> channelsSound;
    private static AudioSource channelMusic; // Un seul canal réservé à la musique

    private static bool fadingMusic = false;
    private static bool fadingOut = false;
    private static string musicToFade;

    private static float soundVolume = 1;
    private static float musicVolume = 1;

    void Awake() {
        channelsSound = new List<AudioSource>();
        for (int i = 0; i < numberOfSoundChannels; i++) {
            channelsSound.Add(gameObject.AddComponent<AudioSource>());
        }
        channelMusic = gameObject.AddComponent<AudioSource>();
        channelMusic.loop = true;
        Object[] soundsTab = Resources.LoadAll(nameOfSoundsFolderInResources);
        Object[] musicsTab = Resources.LoadAll(nameOfMusicsFolderInResources);

        sounds = new Dictionary<string, AudioClip>();
        foreach (Object c in soundsTab) {
            sounds.Add(c.name, c as AudioClip);
        }

        musics = new Dictionary<string, AudioClip>();
        foreach (Object m in musicsTab) {
            musics.Add(m.name, m as AudioClip);
        }
        if (playMusicOnStart && nameOfMusicOnStart.Length != 0) {
            PlayMusic(nameOfMusicOnStart);
        }
        ChangeSoundVolume(soundVolume);
        ChangeMusicVolume(musicVolume);
    }

    void Update() {
        if (fadingMusic) {
            if (fadingOut) {
                channelMusic.volume -= 0.4f * Time.deltaTime;
                if (channelMusic.volume <= 0) {
                    channelMusic.volume = 0;
                    fadingOut = false;
                    channelMusic.Stop();
                    PlayMusic(musicToFade);
                }
            } else {
                channelMusic.volume += 0.4f * Time.deltaTime;
                if (channelMusic.volume >= 1) {
                    channelMusic.volume = 1;
                    fadingMusic = false;
                }
            }
        }
    }

    public static bool PlayMusic(string music) {
        if (!musics.ContainsKey(music)) {
            Debug.LogError("Error : music '" + music + "' not found !");
            return false;
        }
        channelMusic.clip = musics[music];
        channelMusic.Play();
        return true;
    }

    public static void ChangePitchMusic(float value) {
        channelMusic.pitch = value;
    }

    public static void ChangeMusicVolume(float newValue) {
        musicVolume = newValue;
        channelMusic.volume = musicVolume;
    }

    public static bool ChangeMusicSmooth(string music) {
        if (!musics.ContainsKey(music)) {
            Debug.LogError("Error : music '" + music + "' not found !");
            return false;
        }
        musicToFade = music;
        channelMusic.loop = false;
        fadingMusic = true;
        fadingOut = true;
        return true;
    }

    public static bool PlaySound(string sound) {
        if (!sounds.ContainsKey(sound)) {
            Debug.LogError("Error : sound '" + sound + "' not found !");
            return false;
        }
        foreach(AudioSource channel in channelsSound) {
            if (!channel.isPlaying) {
                channel.clip = sounds[sound];
                channel.Play();
                return true;
            }
            
        }
        Debug.LogWarning("Warning : all channels are occupied ! Sound '" + sound + "' not played.");
        return false;
    }

    public static void ChangeSoundVolume(float newValue) {
        soundVolume = newValue;
        foreach(AudioSource channel in channelsSound) {
            channel.volume = soundVolume;
        }
    }

    public static bool SoundIsPlaying(string sound) {
        if (!sounds.ContainsKey(sound)) {
            Debug.LogError("Error : sound '" + sound + "' not found !");
            return false;
        }
        foreach (AudioSource channel in channelsSound) {
            if (channel.isPlaying && channel.clip == sounds[sound]) {
                return true;
            }
        }
        return false;
    }

    public static bool StopSound(string sound) {
        if (!sounds.ContainsKey(sound)) {
            Debug.LogError("Error : sound '" + sound + "' not found !");
            return false;
        }
        foreach (AudioSource channel in channelsSound) {
            if (channel.isPlaying && channel.clip == sounds[sound]) {
                channel.Stop();
                return true;
            }

        }
        Debug.LogWarning("Warning : Tried to stopped sound " + sound + ", but it wasn't playing.");
        return false;
    }
}