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

public class AudioManager : MonoBehaviour, IGameManager {
    public ManagerStatus status 
    {
        get; private set;
    }

    [SerializeField]
    private List<string> playList;

    [SerializeField]
    private AudioSource soundSource;

    [SerializeField]
    private AudioSource music1Source;

    [SerializeField]
    private AudioSource music2Source;

    [SerializeField]
    private string introBGMusic;

    [SerializeField]
    private string levelBGMusic;

    private AudioSource activeMusic;
    private AudioSource inactiveMusic;

    [SerializeField]
    private float crossFadeRate = 1.5f;
    private bool isCrossFading;

    // gets or sets the volume of the audio listener attached to this object
    public float soundVolume
    {
        get { return AudioListener.volume; }
        set { AudioListener.volume = value; }
    }

    // gets or sets whether the volume of the audio listener is muted or not
    public bool muteSound
    {
        get { return AudioListener.pause; }
        set { AudioListener.pause = value; }
    }

    // backing field for musicVolume property
    private float _musicVolume;

    // property definition for the music volume using the more complex full definition method
    // when setting the property, it also checks to see if a music source has been set
    // and adjusts the volume of both music sources accordingly
    public float musicVolume
    {
        get { return _musicVolume; }
        set
        {
            _musicVolume = value;
            // Use the value to set the volume for the two music sources
            if (music1Source != null)
            {
                music1Source.volume = value;
                music2Source.volume = value;
            }
        }
    }

    // backing field for muteMusic property
    private bool _muteMusic;

    public bool muteMusic
    {
        get { return _muteMusic; }
        set
        {
            _muteMusic = value;
            // Use the value to mute/unmute the volume for the two music sources
            if (music1Source != null)
            {
                music1Source.mute = value;
                music2Source.mute = value;
            }
        }
    }


    public void StartUp()
    {
        // Initialise audio sources here
        initMusicSettings();

        status = ManagerStatus.Started;
    }


    private void initMusicSettings()
    {
        // Ignore audio listener volume settings
        // as this is being set programmatically
        music1Source.ignoreListenerVolume = true;
        music2Source.ignoreListenerVolume = true;

        musicVolume = 1f;
        soundVolume = 1f;

        activeMusic = music1Source;
        inactiveMusic = music2Source;
        muteMusic = false;
    }


    private void Awake()
    {

    }

    // Use this for initialization
    void Start () {
        StartCoroutine(PlayStartMusic());
	}
	
	// Update is called once per frame
	void Update () {
		
	}

    private IEnumerator PlayStartMusic()
    {
        if (!string.IsNullOrEmpty(introBGMusic))
        {
            PlayIntroMusic();
        }

        yield return new WaitForSeconds(10f);
        if (!string.IsNullOrEmpty(levelBGMusic))
        {
            PlayLevelMusic();
        } else
        {
            StopMusic();
        }
    }

    public void PlaySound(AudioClip clip)
    {
        soundSource.PlayOneShot(clip);
    }


    // Fades the background music in and out of different background tunes
    private IEnumerator CrossFadeMusic(AudioClip clip)
    {
        // start cross fading from old music playing to new clip
        isCrossFading = true;

        // set inactive music to the new clip to play and make it start playing from volume zero
        inactiveMusic.clip = clip;
        inactiveMusic.volume = 0;
        inactiveMusic.Play();

        // gradually increase (inactive – new music)/decrease (active – old music) volume by crossfade rate
        float scaledRate = crossFadeRate * musicVolume;

        // cross fade until currently active (previous) music's volume reaches zero
        while (activeMusic.volume > 0)
        {
            // Decrease previous music's volume
            activeMusic.volume -= scaledRate * Time.deltaTime;

            // Increase new music's volume
            inactiveMusic.volume += scaledRate * Time.deltaTime;

            // temporarily yield control till next frame
            yield return null;
        }


        // Previous music's volume is now zero, can stop it
        // Inactive currently contains new music to play
        // Active contains previous music that was playing
        // Swap inactive and active music around using temp variable
        // Store previous music (active at the moment) in temp variable
        AudioSource temp = activeMusic;


        // Set active music to the new music (inactive at the moment)
        activeMusic = inactiveMusic;
        activeMusic.volume = musicVolume;

        // Set inactive music to previous music (from temp variable) and stop it
        inactiveMusic = temp;
        inactiveMusic.Stop();

        // Stop cross fading
        isCrossFading = false;
    }

    private void PlayMusic(string musicFile)
    {
        if (string.IsNullOrEmpty(musicFile)) return;
        // Lazy load the music source
        AudioClip clip = Resources.Load("Music/" + musicFile) as AudioClip;
        if (clip != null)
        {
            PlayMusic(clip);
        }
    }

    private void PlayMusic(AudioClip clip)
    {
        if (!isCrossFading)
        {
            StartCoroutine(CrossFadeMusic(clip));
        }        
    }

    public void PlayIntroMusic()
    {
        PlayMusic(introBGMusic);
    }

    public void PlayLevelMusic()
    {
        PlayMusic(levelBGMusic);
    }

    public void PlayBackgroundMusic(string title)
    {
        if (playList.Contains(title))
        {
            PlayMusic(title);
        }
    }


    public void StopMusic()
    {
        activeMusic.Stop();
        inactiveMusic.Stop();
    }

}
