using QSB.Events;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.Utility;
using UnityEngine;

namespace QSB.ClientServerStateSync
{
	internal class ClientStateManager : MonoBehaviour
	{
		public static ClientStateManager Instance { get; private set; }

		public event ChangeStateEvent OnChangeState;
		public delegate void ChangeStateEvent(ClientState newState);

		private void Awake()
			=> Instance = this;

		private void Start()
		{
			QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
			QSBCore.UnityEvents.RunWhen(() => PlayerTransformSync.LocalInstance != null, () => QSBEventManager.FireEvent(EventNames.QSBClientState, ForceGetCurrentState()));
		}

		public void ChangeClientState(ClientState newState)
		{
			if (QSBPlayerManager.LocalPlayer.State == newState)
			{
				return;
			}

			DebugLog.DebugWrite($"CHANGE CLIENT STATE FROM {QSBPlayerManager.LocalPlayer.State} to {newState}");
			QSBPlayerManager.LocalPlayer.State = newState;
			OnChangeState?.Invoke(newState);
		}

		private void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool inUniverse)
		{
			var serverState = ServerStateManager.Instance.GetServerState();

			ClientState newState;

			if (QSBCore.IsHost)
			{

				switch (newScene)
				{
					case OWScene.TitleScreen:
						DebugLog.DebugWrite($"SERVER LOAD TITLESCREEN");
						newState = ClientState.InTitleScreen;
						break;
					case OWScene.Credits_Fast:
						DebugLog.DebugWrite($"SERVER LOAD SHORT CREDITS");
						newState = ClientState.WatchingShortCredits;
						break;
					case OWScene.Credits_Final:
					case OWScene.PostCreditsScene:
						DebugLog.DebugWrite($"SERVER LOAD LONG CREDITS");
						newState = ClientState.WatchingLongCredits;
						break;
					case OWScene.SolarSystem:
						if (oldScene == OWScene.SolarSystem)
						{
							// reloading scene
							DebugLog.DebugWrite($"SERVER RELOAD SOLARSYSTEM");
							newState = ClientState.WaitingForOthersToReadyInSolarSystem;
						}
						else
						{
							// loading in from title screen
							DebugLog.DebugWrite($"SERVER LOAD SOLARSYSTEM");
							newState = ClientState.AliveInSolarSystem;
						}
						break;
					default:
						newState = ClientState.NotLoaded;
						break;
				}
			}
			else
			{
				switch (newScene)
				{
					case OWScene.TitleScreen:
						DebugLog.DebugWrite($"CLIENT LOAD TITLESCREEN");
						newState = ClientState.InTitleScreen;
						break;
					case OWScene.Credits_Fast:
						DebugLog.DebugWrite($"CLIENT LOAD SHORT CREDITS");
						newState = ClientState.WatchingShortCredits;
						break;
					case OWScene.Credits_Final:
					case OWScene.PostCreditsScene:
						DebugLog.DebugWrite($"CLIENT LOAD LONG CREDITS");
						newState = ClientState.WatchingLongCredits;
						break;
					case OWScene.SolarSystem:
						if (serverState == ServerState.WaitingForAllPlayersToDie)
						{
							DebugLog.DebugWrite($"SEVER IN DEATH PHASE - WAIT");
							newState = ClientState.WaitingForOthersToReadyInSolarSystem;
							break;
						}

						if (oldScene == OWScene.SolarSystem)
						{
							// reloading scene
							DebugLog.DebugWrite($"CLIENT RELOAD SOLARSYSTEM");
							newState = ClientState.WaitingForOthersToReadyInSolarSystem;
						}
						else
						{
							// loading in from title screen
							DebugLog.DebugWrite($"CLIENT LOAD SOLARSYSTEM");
							if (serverState == ServerState.WaitingForAllPlayersToReady)
							{
								newState = ClientState.WaitingForOthersToReadyInSolarSystem;
							}
							else
							{
								newState = ClientState.AliveInSolarSystem;
							}
						}
						break;
					default:
						newState = ClientState.NotLoaded;
						break;
				}
			}

			QSBEventManager.FireEvent(EventNames.QSBClientState, newState);
		}

		public void OnDeath()
		{
			var currentScene = QSBSceneManager.CurrentScene;
			if (currentScene == OWScene.SolarSystem)
			{
				QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.DeadInSolarSystem);
			}
			else if (currentScene == OWScene.EyeOfTheUniverse)
			{
				DebugLog.ToConsole($"Error - You died in the Eye? HOW DID YOU DO THAT?!", OWML.Common.MessageType.Error);
			}
			else
			{
				// whaaaaaaaaa
				DebugLog.ToConsole($"Error - You died... in a menu? In the credits? In any case, you should never see this. :P", OWML.Common.MessageType.Error);
			}
		}

		public void OnRespawn()
		{
			var currentScene = QSBSceneManager.CurrentScene;
			if (currentScene == OWScene.SolarSystem)
			{
				DebugLog.DebugWrite($"RESPAWN!");
				QSBEventManager.FireEvent(EventNames.QSBClientState, ClientState.AliveInSolarSystem);
			}
			else
			{
				DebugLog.ToConsole($"Error - Player tried to respawn in scene {currentScene}", OWML.Common.MessageType.Error);
			}
		}

		private ClientState ForceGetCurrentState()
		{
			DebugLog.DebugWrite($"ForceGetCurrentState");
			var currentScene = LoadManager.GetCurrentScene();
			var lastScene = LoadManager.GetPreviousScene();

			switch (currentScene)
			{
				case OWScene.TitleScreen:
					DebugLog.DebugWrite($"- TitleScreen");
					return ClientState.InTitleScreen;
				case OWScene.Credits_Fast:
					DebugLog.DebugWrite($"- Short Credits");
					return ClientState.WatchingShortCredits;
				case OWScene.Credits_Final:
				case OWScene.PostCreditsScene:
					DebugLog.DebugWrite($"- Long Credits");
					return ClientState.WatchingLongCredits;
				case OWScene.SolarSystem:
					DebugLog.DebugWrite($"- SolarSystem");
					return ClientState.AliveInSolarSystem;
				case OWScene.EyeOfTheUniverse:
					DebugLog.DebugWrite($"- Eye");
					return ClientState.AliveInEye;
				default:
					DebugLog.DebugWrite($"- Not Loaded");
					return ClientState.NotLoaded;
			}
		}
	}
}
