using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// GAME 1303 Tier 1 — One place to play music and sound effects.
///
/// SETUP
///  1. Empty GameObject "AudioManager" with this script. It persists between scenes.
///  2. Drop clips into the Named Sounds list and give each a name ("jump", "hit",
///     "collect", "death", "funny_death"). Optional: a Music clip that loops.
///
/// From anywhere:
///     AudioManager.Instance.PlaySFX("jump");
///     AudioManager.Instance.PlaySFX(myClip);          // direct clip
///     AudioManager.Instance.PlaySFX("hit", 0.8f);     // with volume
///     AudioManager.Instance.PlayMusic(bossTheme);
/// Also works from UnityEvents in the Inspector — pick AudioManager -> PlaySFX (string).
/// </summary>
public class AudioManager : MonoBehaviour
{
    public static AudioManager Instance { get; private set; }

    [System.Serializable]
    public class NamedSound
    {
        public string name;
        public AudioClip clip;
        [Range(0f, 1f)] public float volume = 1f;
        [Tooltip("Random pitch variation so repeated sounds don't feel robotic.")]
        [Range(0f, 0.5f)] public float pitchVariation = 0.05f;
    }

    [Header("Sound Effects")]
    public List<NamedSound> namedSounds = new List<NamedSound>();
    [Tooltip("How many SFX can overlap.")]
    public int sfxVoices = 8;

    [Header("Music")]
    public AudioClip musicOnStart;
    [Range(0f, 1f)] public float musicVolume = 0.5f;

    private AudioSource musicSource;
    private AudioSource[] sfxSources;
    private int nextVoice;
    private Dictionary<string, NamedSound> lookup;

    void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }
        Instance = this;
        DontDestroyOnLoad(gameObject);

        musicSource = gameObject.AddComponent<AudioSource>();
        musicSource.loop = true;
        musicSource.playOnAwake = false;

        sfxSources = new AudioSource[sfxVoices];
        for (int i = 0; i < sfxVoices; i++)
        {
            sfxSources[i] = gameObject.AddComponent<AudioSource>();
            sfxSources[i].playOnAwake = false;
        }

        lookup = new Dictionary<string, NamedSound>();
        foreach (var s in namedSounds)
            if (!string.IsNullOrEmpty(s.name) && !lookup.ContainsKey(s.name)) lookup[s.name] = s;
    }

    void Start()
    {
        if (musicOnStart != null) PlayMusic(musicOnStart);
    }

    // ---------- SFX ----------
    public void PlaySFX(string name)
    {
        if (lookup != null && lookup.TryGetValue(name, out NamedSound s))
            Play(s.clip, s.volume, s.pitchVariation);
        else
            Debug.LogWarning($"AudioManager: no sound named '{name}'.");
    }

    public void PlaySFX(string name, float volume)
    {
        if (lookup != null && lookup.TryGetValue(name, out NamedSound s))
            Play(s.clip, volume, s.pitchVariation);
    }

    public void PlaySFX(AudioClip clip, float volume = 1f) => Play(clip, volume, 0.05f);

    void Play(AudioClip clip, float volume, float pitchVar)
    {
        if (clip == null) return;
        AudioSource src = sfxSources[nextVoice];
        nextVoice = (nextVoice + 1) % sfxSources.Length;
        src.pitch = 1f + Random.Range(-pitchVar, pitchVar);
        src.PlayOneShot(clip, volume);
    }

    // ---------- Music ----------
    public void PlayMusic(AudioClip clip)
    {
        if (clip == null || musicSource.clip == clip) return;
        musicSource.clip = clip;
        musicSource.volume = musicVolume;
        musicSource.Play();
    }

    public void StopMusic() => musicSource.Stop();

    public void SetMusicVolume(float v) { musicVolume = v; musicSource.volume = v; }
}