using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class MusicPlayer : MonoBehaviour
{
    #region Singleton Instance
    private static MusicPlayer instance;
    public static MusicPlayer Instance
    {
        get
        {
            Util.AssertTrue(instance != null, "Instancia do singleton nao foi encontrada");
            return instance;
        }
        private set
        {
            instance = value;
        }
    }
    #endregion

    private bool _enabled = true;
    public bool Enabled
    {
        get
        {
            return _enabled;
        }
        set
        {
            if (!value)
            {
                StopSound();
                if (mCurrentFadeCoroutine != null)
                {
                    mCurrentFadeCoroutine.Stop();
                }
            }
            _enabled = value;
        }
    }
    
    public enum Songs
    {
        Gameplay
    }

    public AudioSource Gameplay;
    
    private const float DEFAULT_FADE_TIME = 1.0f;
	private bool isFading = false;
    private List<Songs> clipQueue = new List<Songs>();
	private AudioSource currentlyPlayingClip = null;
    private Songs? currentEnumClip = null;
    private Coroutine mCurrentFadeCoroutine = null;

	void Awake()
	{
        Util.AssertTrue(GameObject.FindObjectsOfType(GetType()).Length == 1, "There can be only 1 MusicPlayer in the game");
        //DontDestroyOnLoad(this);
        instance = this;
	}

    private void SetNewMusic(Songs newClip)
	{
		currentEnumClip = newClip;
		switch (newClip)
		{
            case Songs.Gameplay:
                currentlyPlayingClip = Gameplay;
                break;
                break;
			default:
                Util.AssertTrue(false, "Song not implemented");
				break;
		}
	}

    public void PlayMusic(Songs newClip, bool loop)
	{
        if (Enabled)
        {
            if (newClip != currentEnumClip)
            {
                if (currentlyPlayingClip != null)
                {
                    StopSound();
                }
                SetNewMusic(newClip);
                currentlyPlayingClip.loop = loop;
                currentlyPlayingClip.Play();
            }
            else
            {
                currentlyPlayingClip.loop = loop;
            }
        }
	}

    public void FadeOutFadeIn(Songs newClip, bool loopNewClip, float outTimer = DEFAULT_FADE_TIME, float inTimer = DEFAULT_FADE_TIME)
	{
        if (Enabled)
        {
            if ((!isFading) && (clipQueue.Count == 0))
            {
                if (newClip != currentEnumClip)
                {
                    isFading = true;
                    mCurrentFadeCoroutine = AsyncManager.Execute(this, InternalFadeOutFadeIn, newClip, loopNewClip, outTimer, inTimer);
                }
                else
                {
                    currentlyPlayingClip.loop = loopNewClip;
                }
            }
            else
            {
                clipQueue.Clear();
                clipQueue.Add(newClip);
            }
        }
	}

    private IEnumerator InternalFadeOutFadeIn(Songs newClip, bool loopNewClip, float outTimer, float inTimer)
	{
		float start = currentlyPlayingClip.volume;
		float end = 0.0f;
		float i = 0.0f;
		float step = 1.0f / outTimer;
		while (i <= 1.0f)
		{
			i += step * Time.deltaTime;
			currentlyPlayingClip.volume = Mathf.Lerp(start, end, i);
			yield return new WaitForSeconds(step * Time.deltaTime);
		}
		currentlyPlayingClip.Stop();
		currentlyPlayingClip.volume = start;

		SetNewMusic(newClip);
		currentlyPlayingClip.loop = loopNewClip;
		start = 0.0f;
		end = currentlyPlayingClip.volume;
		i = 0.0f;
		step = 1.0f / inTimer;
		currentlyPlayingClip.volume = 0.0f;
		currentlyPlayingClip.Play();
		while (i <= 1.0f)
		{
			i += step * Time.deltaTime;
			currentlyPlayingClip.volume = Mathf.Lerp(start, end, i);
			yield return new WaitForSeconds(step * Time.deltaTime);
		}
		currentlyPlayingClip.volume = end;
		isFading = false;
		if (clipQueue.Count > 0)
		{
            Songs c = clipQueue[0];
			clipQueue.Clear();
			FadeOutFadeIn(c, true, outTimer, inTimer);
		}
	}

    void Update()
    {
        if (!isFading)
        {
            if (clipQueue.Count > 0)
            {
                Songs c = clipQueue[0];
                clipQueue.Clear();
                FadeOutFadeIn(c, true);
            }
        }
    }

    public void StopSound()
    {
        if (currentlyPlayingClip != null)
        {
            currentlyPlayingClip.Stop();
        }
        isFading = false;
        clipQueue = new List<Songs>();
        currentlyPlayingClip = null;
        currentEnumClip = null;
    }
}