/*
 * @license Private Source License v1.0.0
 * @copyright 2023 Reinhardt Weyers
 *
 * @author Reinhardt Weyers
 *
 * @version 0.1.0
 * 
 * Created On: 04/12/25
 * Last edited: 04/12/25
 */

using UnityEngine;

namespace RetroDev.GameTimer
{
    public class GameTimer
    {
        private float duration;
        private float elapsedTime;
        private bool isRunning;
        private bool isPaused;
        private float pausedTime;

        // Callback function to be invoked when the timer starts.
        private System.Action onStartCallback;

        // Callback function to be invoked when the timer is stopped.
        private System.Action onStopCallback;

        // Callback function to be invoked when the timer is paused.
        private System.Action onPauseCallback;

        // Callback function to be invoked when the timer is resumed.
        private System.Action onResumeCallback;

        // Callback function to be invoked when the timer completes.
        private System.Action onTimerCompleteCallback;

        /// <summary>
        /// Initializes a new instance of the GameTimer class.
        /// </summary>
        /// <param name="duration">Duration of the timer in seconds.</param>
        /// <param name="onTimerCompleteCallback">Callback function to be invoked when the timer completes.</param>
        /// <param name="onStartCallback">Callback function to be invoked when the timer starts.</param>
        /// <param name="onStopCallback">Callback function to be invoked when the timer stops.</param>
        /// <param name="onPauseCallback">Callback function to be invoked when the timer is paused.</param>
        /// <param name="onResumeCallback">Callback function to be invoked when the timer is resumed.</param>
        public GameTimer(
            float duration,
            System.Action onTimerCompleteCallback = null,
            System.Action onStartCallback = null,
            System.Action onStopCallback = null,
            System.Action onPauseCallback = null,
            System.Action onResumeCallback = null)
        {
            this.duration = duration;
            this.elapsedTime = 0f;
            this.isRunning = false;
            this.isPaused = false;
            this.pausedTime = 0f;

            this.onTimerCompleteCallback = onTimerCompleteCallback;
            this.onStartCallback = onStartCallback;
            this.onStopCallback = onStopCallback;
            this.onPauseCallback = onPauseCallback;
            this.onResumeCallback = onResumeCallback;
        }

        /// <summary>
        /// Starts the timer.
        /// </summary>
        public void Start()
        {
            if (!isRunning && !isPaused)
            {
                isRunning = true;
                onStartCallback?.Invoke();
            }
        }

        /// <summary>
        /// Stops the timer.
        /// </summary>
        public void Stop()
        {
            if (isRunning || isPaused)
            {
                isRunning = false;
                isPaused = false;
                pausedTime = 0f;
                onStopCallback?.Invoke();
            }
        }

        /// <summary>
        /// Pauses the timer.
        /// </summary>
        public void Pause()
        {
            if (isRunning && !isPaused)
            {
                isPaused = true;
                pausedTime = elapsedTime;
                onPauseCallback?.Invoke();
            }
        }

        /// <summary>
        /// Resumes the timer from the paused state.
        /// </summary>
        public void Resume()
        {
            if (isRunning && isPaused)
            {
                isPaused = false;
                onResumeCallback?.Invoke();
                elapsedTime = pausedTime;
            }
        }

        /// <summary>
        /// Resets the timer to its initial state.
        /// </summary>
        public void Reset()
        {
            elapsedTime = 0f;
            isPaused = false;
            pausedTime = 0f;
        }

        /// <summary>
        /// Updates the timer. Should be called in the Update() method of a MonoBehaviour.
        /// </summary>
        public void Update()
        {
            if (isRunning && !isPaused)
            {
                elapsedTime += Time.deltaTime;

                if (elapsedTime >= duration)
                {
                    // Timer has reached its duration.
                    Stop();
                    onTimerCompleteCallback?.Invoke();
                }
            }
        }

        /// <summary>
        /// Gets the current elapsed time of the timer.
        /// </summary>
        /// <returns>Elapsed time in seconds.</returns>
        public float GetElapsedTime()
        {
            return elapsedTime;
        }

        /// <summary>
        /// Gets the total duration of the timer.
        /// </summary>
        /// <returns>Duration of the timer in seconds.</returns>
        public float GetDuration()
        {
            return duration;
        }

        /// <summary>
        /// Checks if the timer is currently running.
        /// </summary>
        /// <returns>True if the timer is running, false otherwise.</returns>
        public bool IsRunning()
        {
            return isRunning;
        }

        /// <summary>
        /// Checks if the timer is currently paused.
        /// </summary>
        /// <returns>True if the timer is paused, false otherwise.</returns>
        public bool IsPaused()
        {
            return isPaused;
        }
    }
}
