using System;
using HarmonyLib;

using RobocraftX;
using RobocraftX.Common;
using RobocraftX.GUI;
using RobocraftX.GUI.MyGamesScreen;
using Svelto.ECS;
using Svelto.ECS.Experimental;

using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Utility;

namespace GamecraftModdingAPI.App
{
	public class GameMenuEngine : IFactoryEngine
    {
		public IEntityFactory Factory { set; private get; }

		public string Name => "GamecraftModdingAPIGameInfoGameEngine";

		public bool isRemovable => false;

		public EntitiesDB entitiesDB { set; private get; }

		public void Dispose()
		{
			IsInMenu = false;
		}

		public void Ready()
		{
			IsInMenu = true;
		}

		// game functionality

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

        public bool CreateMyGame(EGID id, string path = "", uint thumbnailId = 0, string gameName = "", string creatorName = "", string description = "", long createdDate = 0L)
		{
			EntityComponentInitializer eci = Factory.BuildEntity<MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal>(id);
			eci.Init(new MyGameDataEntityStruct
			{
				SavedGamePath = new ECSString(path),
				ThumbnailId = thumbnailId,
				GameName = new ECSString(gameName),
				CreatorName = new ECSString(creatorName),
				GameDescription = new ECSString(description),
				CreatedDate = createdDate,
			});
			// entitiesDB.PublishEntityChange<MyGameDataEntityStruct>(id); // this will always fail
			return true;
		}

		public uint HighestID()
		{
			EntityCollection<MyGameDataEntityStruct> games = entitiesDB.QueryEntities<MyGameDataEntityStruct>(MyGamesScreenExclusiveGroups.MyGames);
			uint max = 0;
			for (int i = 0; i < games.count; i++)
			{
				if (games[i].ID.entityID > max)
				{
					max = games[i].ID.entityID;
				}
			}
			return max;
		}

        public bool EnterGame(EGID id)
		{
			if (!ExistsGameInfo(id)) return false;
			ref MyGameDataEntityStruct mgdes = ref GetGameInfo(id);
			return EnterGame(mgdes.GameName, mgdes.SavedGamePath);
		}

        public bool EnterGame(string gameName, string path, ulong workshopId = 0uL, bool autoEnterSim = false)
		{
			GameMode.CurrentMode = autoEnterSim ? RCXMode.Play : RCXMode.Build;
			GameMode.SaveGameDetails = new SaveGameDetails(gameName, path, workshopId);
			// the private FullGameCompositionRoot.SwitchToGame() method gets passed to menu items for this reason
			AccessTools.Method(typeof(FullGameCompositionRoot), "SwitchToGame").Invoke(FullGameFields.Instance, new object[0]);
			return true;
		}

        public bool SetGameName(EGID id, string name)
		{
			if (!ExistsGameInfo(id)) return false;
			GetGameInfo(id).GameName.Set(name);
			GetGameViewInfo(id).MyGamesSlotComponent.GameName = StringUtil.SanitiseString(name);
			return true;
		}

		public bool SetGameDescription(EGID id, string name)
        {
            if (!ExistsGameInfo(id)) return false;
            GetGameInfo(id).GameDescription.Set(name);
			GetGameViewInfo(id).MyGamesSlotComponent.GameDescription = StringUtil.SanitiseString(name);
            return true;
        }

        public bool ExistsGameInfo(EGID id)
		{
			return entitiesDB.Exists<MyGameDataEntityStruct>(id);
		}

		public ref MyGameDataEntityStruct GetGameInfo(EGID id)
		{
			return ref GetComponent<MyGameDataEntityStruct>(id);
		}

        public ref MyGamesSlotEntityViewStruct GetGameViewInfo(EGID id)
		{
			return ref GetComponent<MyGamesSlotEntityViewStruct>(new EGID(id.entityID, MyGamesScreenExclusiveGroups.GameSlotGuiEntities));
		}

		public ref T GetComponent<T>(EGID id) where T: struct, IEntityComponent
		{
			return ref entitiesDB.QueryEntity<T>(id);
		}
	}

	internal class MyGameDataEntityDescriptor_DamnItFJWhyDidYouMakeThisInternal : GenericEntityDescriptor<MyGameDataEntityStruct> { }
}