/*
I’ll walk through the script ABitsnip that is a part of the “Bit System” in Hell Glider 2!

An ABitSnip represents each clip or “snip” of this bit… each shot of the camera. An ABItSnip may be a video, image, or simply a 
camera shot. This is the abstracted functionality that each of those implementations use.

An ABitSnip is controlled by the BitController (not shown). The BitController holds a list of ABitSnips which make up an entire bit. 

This BitController goes down the list starting at index 0, and plays each ABitSnip incrementally. When playing a bit, the 
BitController calls the Enter function, and also subscribes to the OnFinished Action on the current ABitSnip. 
Once the ABitSnip is finished, it fires off the OnFinished action (which the BitController is subscribed to). 
The BitController then increments its index to the next ABitSnip in the list and proceeds with the same process of subscribin 
to this NEW ABitSnip’s OnFinished Action.

ABitController has some abstract methods that its implementations have to implement:
--> Play()
--> FinishSnip()

and some virtual methods that implement some base functionality, but are allowed to overriden/added to:
--> Enter()
--> BitUpdate()

There is also a method for playing AudioBySeconds() here. This may be used if the
audioBySeconds list is non empty. In some implementations there are more options such as audioByFrame (for video clips).
The two may be used mutually as well.

AudioByFrame is an instance of overriding the BitUpdate method to include checks for audioByFrame

There is plenty more to say, but this is a good generalized overview! Thanks for reading!!

 */
public abstract class ABitSnip : MonoBehaviour
{

    /// <summary>
    /// When this BitSnip is finished, this will be called.
    /// </summary>
    public Action OnFinished;
    public CinemachineVirtualCamera cam;


    /// <summary>
    /// List of audioClips to play at corresponding frame number.
    /// </summary>
    public List<SoundProfile> audioClips;
    /// <summary>
    /// If true, audio will bleed through, and not be stoped at end of snip.
    /// </summary>
    public List<bool> audioBleedThrough;

    public List<float> audioBySeconds;
    private int audioSecondIndex = 0;
    protected float elapsedTime;


    public virtual void Enter() {
        elapsedTime = 0f;
    }

    /// <summary>
    /// Must declare a body on all derived classes.
    /// </summary>
    public abstract void Play();

    public abstract void FinishSnip();

    /// <summary>
    /// Invoke using real seconds (even when Time.timscale = 0).
    /// </summary>
    /// <param name="func"></param>
    /// <param name="time"></param>
    /// <returns></returns>
    protected IEnumerator InvokeRealtime(Action func, float time)
    {
        yield return new WaitForSecondsRealtime(time);
        func();
    }

    /// <summary>
    /// Handles audio to be played by seconds.
    /// </summary>
    private void AudioBySeconds() {
        elapsedTime += Time.deltaTime;
        if (audioBySeconds == null || audioSecondIndex >= audioBySeconds.Count) return;

        float difference = .01f;
        if (Mathf.Abs(audioBySeconds[audioSecondIndex] - elapsedTime) < difference) {
            SoundManager.INSTANCE.PlaySound(audioClips[audioSecondIndex], transform.position);
            audioSecondIndex++;
        }
    }

    /// <summary>
    /// Called by the BitController every frame.
    /// </summary>
    public virtual void BitUpdate() {
        AudioBySeconds();
    }

}

/** CodeExplaination - BitSystem **/