using NaughtyAttributes;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

//Could be a singleton
public class GameFlowManager : MonoBehaviour {
	[SerializeField] [Required]
	GameTimer gameTimer = null!;

	public enum PauseLevel {
		NotPaused,
		PreventActions,
		WorldFreeze,
	}

	[field: SerializeField]
	public PauseLevel pauseLevel { get; private set; } = PauseLevel.PreventActions;

	public bool CanDoAction => pauseLevel <= PauseLevel.NotPaused;

	public BaseState CurrentState { get; private set; } = null!;
	bool lastStartButton;
	bool lastAcceptButton;
	[SerializeField] GameObject startPrompt;

	#region Unity Messages

	void Awake() {
		CurrentState = new StartFlowState(this);
		if (startPrompt != null) {
			startPrompt.SetActive(true);
		}
	}

	void Start() => CurrentState.EnterState();

	#endregion

	void SetPauseLevel(PauseLevel value) {
		pauseLevel = value;
		Time.timeScale = value >= PauseLevel.WorldFreeze ? 0f : 1f;
	}

	public void GameOver() => SwitchState(new DeadFlowState(this));

	#region Inputs

	public void OnStart(InputAction.CallbackContext ctx) {
		if (!ctx.WasPressedThisFrame(ref lastStartButton))
			return;

		if (CurrentState is StartFlowState) {
			startPrompt.SetActive(false);
			SwitchState(new GameplayFlowState(this));
		}
	}

	public void OnAccept(InputAction.CallbackContext ctx) {
		if (!ctx.WasPressedThisFrame(ref lastAcceptButton))
			return;

		if (CurrentState is DeadFlowState deadState)
			deadState.ReloadGame();
	}

	#endregion

	#region States

	void SwitchState(BaseState newState) {
		CurrentState.LeaveState();
		CurrentState = newState;
		newState.EnterState();
	}

	abstract class GameFlowState : BaseState {
		readonly protected GameFlowManager gameFlowManager;

		protected GameFlowState(GameFlowManager gameFlowManager) {
			this.gameFlowManager = gameFlowManager;
		}
	}

	class StartFlowState : GameFlowState {
		public StartFlowState(GameFlowManager gameFlowManager) : base(gameFlowManager) {}

		public override void EnterState() {
			base.EnterState();

			gameFlowManager.SetPauseLevel(PauseLevel.PreventActions);
		}

		public override void LeaveState() {
			Debug.Log("Let the games begin!!");
		}
	}

	class GameplayFlowState : GameFlowState {
		public GameplayFlowState(GameFlowManager gameFlowManager) : base(gameFlowManager) {}

		public override void EnterState() {
			base.EnterState();

			gameFlowManager.gameTimer.StartTimer();
			gameFlowManager.SetPauseLevel(PauseLevel.NotPaused);
		}

		public override void LeaveState() {
			base.LeaveState();

			gameFlowManager.gameTimer.PauseTimer();
		}
	}

	class PauseMenuFlowState : GameFlowState {
		public PauseMenuFlowState(GameFlowManager gameFlowManager) : base(gameFlowManager) {}

		public override void EnterState() {
			base.EnterState();
			gameFlowManager.SetPauseLevel(PauseLevel.NotPaused);
		}
	}

	class DeadFlowState : GameFlowState {
		public DeadFlowState(GameFlowManager gameFlowManager) : base(gameFlowManager) {}

		public override void EnterState() {
			base.EnterState();

			Debug.Log("You died!\nPress Accept to restart!");
			gameFlowManager.SetPauseLevel(PauseLevel.PreventActions);
		}

		public void ReloadGame() {
			Debug.Log("Reloading scene...");
			SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
		}
	}

	#endregion
}