using System.Collections;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// Manages the audio elements in the game, including sound effects and background music.
/// </summary>
public class AudioManager : MonoBehaviour
{
    [Header("Volume Elements")]
    public Slider musicVolumeSlider; // Slider for controlling music volume
    public Slider EffectsVolumeSlider; // Slider for controlling sound effects volume

    [Header("Sound Effect Clips")]
    public AudioClip shootingSound; // Sound effect for shooting
    public AudioClip enemyDestroyedSound; // Sound effect for enemy destruction
    public AudioClip dashSound; // Sound effect for dashing
    public AudioClip bulletCollisionSound; // Sound effect for bullet collision
    public AudioClip UIClickSound; // Sound effect for UI click

    [Header("Background Music Tracks")]
    public AudioClip[] musicTracks; // Array of background music tracks

    [Header("Volume Ranges")]
    [Range(0.0f, 1.0f)]
    public float soundEffectVolume = 0.5f; // Volume for sound effects
    [Range(0.0f, 1.0f)]
    public float musicVolume = 0.25f; // Volume for background music

    [Header("Muffle Parameters")]
    public float muffleDuration = 1.0f; // Duration of audio muffle effect
    public float muffledCutoffFrequency = 900f; // Low pass filter cutoff frequency when muffled
    private bool isMuffled = false; // Flag to track muffle state

    private AudioSource soundEffectsSource; // AudioSource for playing sound effects
    private AudioSource musicSource; // AudioSource for playing background music

    private AudioLowPassFilter lowPassFilter; // Reference to the low pass filter component

    public static AudioManager instance; // Singleton instance of AudioManager

    /// <summary>
    /// Initializes the singleton instance.
    /// </summary>
    private void Awake()
    {
        instance = this;
    }

    /// <summary>
    /// Initializes volume sliders, audio sources, and starts playing music.
    /// </summary>
    private void Start()
    {
        // Ensure the volume has a default and is saved when a user changes it (Feel free to change this from 0 => 1f).
        musicVolume = PlayerPrefs.HasKey("volume") ? musicVolume = 0.25f : musicVolume = PlayerPrefs.GetFloat("volume");
        soundEffectVolume = PlayerPrefs.HasKey("effects") ? musicVolume = 0.5f : musicVolume = PlayerPrefs.GetFloat("effects");

        // Add two AudioSources to the GameObject
        soundEffectsSource = gameObject.AddComponent<AudioSource>();
        soundEffectsSource.loop = false;
        soundEffectsSource.playOnAwake = false;

        musicSource = gameObject.AddComponent<AudioSource>();

        // Set volume levels for each AudioSource
        soundEffectsSource.volume = soundEffectVolume;
        musicSource.volume = musicVolume;

        // Add a low pass filter component to the GameObject
        lowPassFilter = gameObject.AddComponent<AudioLowPassFilter>();
        lowPassFilter.cutoffFrequency = 5000; // Set default cutoff frequency

        // Start playing music
        PlayRandomMusicTrack();

        UnmuffleAudio();
    }

    /// <summary>
    /// Updates the volume of sound effects and background music based on slider values.
    /// </summary>
    private void Update()
    {
        soundEffectsSource.volume = EffectsVolumeSlider.value;
        musicSource.volume = musicVolumeSlider.value;
    }

    /// <summary>
    /// Saves the current volume values to playerprefs for repeat sessions.
    /// </summary>
    public void SaveAudio()
    {
        PlayerPrefs.SetFloat("volume", musicVolumeSlider.value);
        PlayerPrefs.SetFloat("effects", EffectsVolumeSlider.value);
    }

    // Sound effect playback methods

    /// <summary>
    /// Plays the shooting sound effect.
    /// </summary>
    public void PlayShootingSound()
    {
        PlaySoundEffect(shootingSound);
    }

    /// <summary>
    /// Plays the enemy destroyed sound effect.
    /// </summary>
    public void PlayEnemyDestroyedSound()
    {
        PlaySoundEffect(enemyDestroyedSound);
    }

    /// <summary>
    /// Plays the dash sound effect.
    /// </summary>
    public void PlayDashSound()
    {
        PlaySoundEffect(dashSound);
    }

    /// <summary>
    /// Plays the bullet collision sound effect.
    /// </summary>
    public void PlayBulletCollisionSound()
    {
        PlaySoundEffect(bulletCollisionSound);
    }

    /// <summary>
    /// Plays the UI click sound effect.
    /// </summary>
    public void PlayClickSound()
    {
        PlaySoundEffect(UIClickSound);
    }

    // Audio muffle methods

    /// <summary>
    /// Muffles audio by applying a low pass filter.
    /// </summary>
    public void MuffleAudio()
    {
        if (!isMuffled)
        {
            StartCoroutine(MuffleCoroutine(true));
            isMuffled = true;
        }
    }

    /// <summary>
    /// Unmuffles audio by removing the low pass filter.
    /// </summary>
    public void UnmuffleAudio()
    {
        if (isMuffled)
        {
            StartCoroutine(MuffleCoroutine(false));
            isMuffled = false;
        }
    }

    /// <summary>
    /// Coroutine for gradually applying or removing the audio muffle effect.
    /// </summary>
    private IEnumerator MuffleCoroutine(bool muffle)
    {
        float startTime = Time.time;
        float endTime = startTime + muffleDuration;
        float startFrequency = lowPassFilter.cutoffFrequency;
        float endFrequency = muffle ? muffledCutoffFrequency : 5000f;

        while (Time.time < endTime)
        {
            float elapsedTime = Time.time - startTime;
            float t = elapsedTime / muffleDuration;
            float frequency = Mathf.Lerp(startFrequency, endFrequency, t);
            lowPassFilter.cutoffFrequency = frequency;
            yield return null;
        }

        lowPassFilter.cutoffFrequency = endFrequency;
    }

    // Audio playback methods

    /// <summary>
    /// Plays a sound effect once.
    /// </summary>
    private void PlaySoundEffect(AudioClip clip)
    {
        soundEffectsSource.PlayOneShot(clip);
    }

    /// <summary>
    /// Plays a random music track.
    /// </summary>
    public void PlayRandomMusicTrack()
    {
        int randomIndex = Random.Range(0, musicTracks.Length);
        PlayMusicTrack(musicTracks[randomIndex]);
    }

    /// <summary>
    /// Plays the specified music track.
    /// </summary>
    private void PlayMusicTrack(AudioClip track)
    {
        musicSource.clip = track;
        musicSource.Play();

        StartCoroutine(WaitForMusicToEndAndPlayNext());
    }

    /// <summary>
    /// Waits for the current music track to end and plays the next random track.
    /// </summary>
    private IEnumerator WaitForMusicToEndAndPlayNext()
    {
        while (musicSource.isPlaying)
        {
            yield return null;
        }

        PlayRandomMusicTrack();
    }
}
