using System;
using System.Collections.Generic;
using HarmonyLib;

using RobocraftX;
using RobocraftX.Common;
using RobocraftX.Schedulers;
using RobocraftX.SimulationModeState;
using Svelto.ECS;
using Svelto.Tasks;
using Svelto.Tasks.Lean;

using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Utility;

namespace GamecraftModdingAPI.App
{
	public class GameGameEngine : IApiEngine
    {
		public event EventHandler<GameEventArgs> EnterGame;

        public event EventHandler<GameEventArgs> ExitGame;

		public string Name => "GamecraftModdingAPIGameInfoMenuEngine";

		public bool isRemovable => false;

		public EntitiesDB entitiesDB { set; private get; }

		public void Dispose()
		{
			ExceptionUtil.InvokeEvent(ExitGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder });
			IsInGame = false;
		}

		public void Ready()
		{
			ExceptionUtil.InvokeEvent(EnterGame, this, new GameEventArgs { GameName = GameMode.SaveGameDetails.Name, GamePath = GameMode.SaveGameDetails.Folder });
			IsInGame = true;
		}

		// game functionality

		public bool IsInGame
		{
			get;
			private set;
		} = false;

		public void ExitCurrentGame(bool async = false)
		{
			if (async)
			{
				ExitCurrentGameAsync().RunOn(Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING);
			}
			else
			{
				entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true;
                entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID);
			}

		}

		public IEnumerator<TaskContract> ExitCurrentGameAsync()
		{
			/*
            while (Lean.EveryFrameStepRunner_RUNS_IN_TIME_STOPPED_AND_RUNNING.isStopping) { yield return Yield.It; }
            AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToMenu").Invoke(FullGameFields.Instance, new object[0]);*/
			yield return Yield.It;
			entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID).WantsToQuit = true;
            entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID);
		}

        public void SaveCurrentGame()
		{
			ref GameSceneEntityStruct gses = ref entitiesDB.QueryEntity<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID);
			gses.LoadAfterSaving = false;
			gses.SaveNow = true;
			entitiesDB.PublishEntityChange<GameSceneEntityStruct>(CommonExclusiveGroups.GameSceneEGID);
		}

        public bool IsTimeRunningMode()
		{
			return TimeRunningModeUtil.IsTimeRunningMode(entitiesDB);
		}

        public bool IsTimeStoppedMode()
		{
			return TimeRunningModeUtil.IsTimeStoppedMode(entitiesDB);
		}

        public void ToggleTimeMode()
		{
			TimeRunningModeUtil.ToggleTimeRunningState(entitiesDB);
		}

		public EGID[] GetAllBlocksInGame(BlockIDs filter = BlockIDs.Invalid)
		{
			var allBlocks = entitiesDB.QueryEntities<DBEntityStruct>();
			List<EGID> blockEGIDs = new List<EGID>();
			if (filter == BlockIDs.Invalid)
			{
				foreach (var (blocks, _) in allBlocks)
				foreach (var block in blocks)
					blockEGIDs.Add(block.ID);
				return blockEGIDs.ToArray();
			}
			else
			{
				foreach (var (blocks, _) in allBlocks)
				foreach (var block in blocks)
					if (block.DBID == (ulong) filter)
						blockEGIDs.Add(block.ID);
				return blockEGIDs.ToArray();
			}
		}
	}
}