using System.Threading.Tasks;
using Mox.Shared;
using Mox.Shared.Renderer;
using Mox.Shared.UI;
using Mox.Shared.Math;
using Mox.Shared.Serializer;

namespace Game.Shared
{
	public class GameLoop : IGameLoop
	{
		public GameLoop(ProgramBase _program)
		{
			m_Program = _program;
			Instance = this;
		}

		public async Task Init()
		{
			RendererBase.Instance.Atlas = await Atlas.Create("atlas");
			
			var uiSerializer = new XmlSerializerLoad(await IOHelper.GetText("Templates.xml"));
			m_Program.UIRoot.SerializeTemplates(uiSerializer);

			m_MainUI = await AddUI("MainUI.xml");
			m_SettingsUI = await AddUI("SettingsUI.xml");
			m_SettingsUI.Visibility = EVisibility.Collapsed;
			m_CreditsUI = await AddUI("CreditsUI.xml");
			m_CreditsUI.Visibility = EVisibility.Collapsed;

			m_Program.UIRoot.EventHandlers[EEventType.ButtonClicked] = OnButtonClicked;
			m_Program.UIRoot.EventHandlers[EEventType.CheckBoxCheckChanged] = OnCheckBoxCheckChanged;

			await m_Program.RegisterSound("music", "menumusic.mp3");
			await m_Program.RegisterSound("sndButtonHover", "button-hover.wav");

			m_GameState = new GameState();

			if (m_Program.GetData("GameState", out var sGameState))
			{
				m_GameState.Serialize(new XmlSerializerLoad(sGameState));
			}
			else
			{
				m_Program.UIRoot.TaggedControls["btnContinue"].Visibility = EVisibility.Collapsed;
			}

			var chkMusic = (CheckBox)m_Program.UIRoot.TaggedControls["chkMusic"];
			chkMusic.Checked = m_GameState.PlayMusic;
		}

		private async Task<Control> AddUI(string _sXml)
		{
			var uiSerializer = new XmlSerializerLoad(await IOHelper.GetText(_sXml));
			m_Program.UIRoot.SerializeControl(uiSerializer, out var control);
			m_Program.UIRoot.MainControl.Children.Add(control);
			control.Parent = m_Program.UIRoot.MainControl;

			return control;
		}

		private void OnCheckBoxCheckChanged(SEventProperties _eventProperties)
		{
			var evt = (SCheckBoxEventData)_eventProperties.Data;

			switch (evt.Tag)
			{
				case "chkMusic":
					m_GameState.PlayMusic = evt.Checked;
					SaveGameState();
					break;
			}
		}

		public void SaveGameState()
		{
			var serializer = new XmlSerializerSave();
			m_GameState.Serialize(serializer);
			m_Program.SetData("GameState", serializer.m_sXml);
		}

		private void OnButtonClicked(SEventProperties _eventProperties)
		{
			var evt = (SButtonEventData) _eventProperties.Data;

			switch (evt.Tag)
			{
				case "btnStart":
					{
						m_GameState = new GameState();
						SaveGameState();
					}
					break;
				case "btnContinue":
					{
					}
					break;
				case "btnSettings":
					{
						m_MainUI.Visibility = EVisibility.Collapsed;
						m_SettingsUI.Visibility = EVisibility.Visible;
					}
					break;
				case "btnCredits":
					{
						m_MainUI.Visibility = EVisibility.Collapsed;
						m_CreditsUI.Visibility = EVisibility.Visible;
					}
					break;
				case "btnLeaveCredits":
					{
						m_MainUI.Visibility = EVisibility.Visible;
						m_CreditsUI.Visibility = EVisibility.Collapsed;
					}
					break;
				case "btnLeaveSettings":
					{
						m_MainUI.Visibility = EVisibility.Visible;
						m_SettingsUI.Visibility = EVisibility.Collapsed;
					}
					break;
			}
		}

		public void OnKeyPressed(EKey _eKey)
		{
			m_Program.ShowMessage(_eKey.ToString());
		}

		public void OnMouseDown(int _iX, int _iY)
		{
			m_bMouseDown = true;
			m_iMouseX = _iX;
			m_iMouseY = _iY;
		}

		public void OnMouseMoved(int _iX, int _iY)
		{
			m_iMouseX = _iX;
			m_iMouseY = _iY;
		}

		public void OnMouseUp(int _iX, int _iY)
		{
			m_bMouseDown = false;
			m_iMouseX = _iX;
			m_iMouseY = _iY;
		}

		public void Update(double _dDelta)
		{
			m_dTime += _dDelta;
			m_Program.UIRoot.Layout();

			var renderer = RendererBase.Instance;
			renderer.Clear(new Color(1, 0, 0, 1));

			renderer.SetTextColor(new Color(0, 0, 0, 1));
			//renderer.SetTextStyle("Calibri", 8);
			//renderer.DrawText($"FPS={(1 / _dDelta):F}, Total={m_dTime:F}", 400, 300);
			renderer.DrawText("Hex Tower Defense", 400, 8);

			//renderer.SetTextColor(new Color(m_bMouseDown ? 1 : 0, 0, 0, 1));
			//renderer.DrawText("X", m_iMouseX, m_iMouseY);
		}

		public static GameLoop Instance
		{
			get;
			private set;
		}

		private double m_dTime;
		private Control m_MainUI;
		private int m_iMouseX;
		private int m_iMouseY;
		private bool m_bMouseDown;
		private readonly ProgramBase m_Program;
		private Control m_SettingsUI;
		private GameState m_GameState;
		private Control m_CreditsUI;
	}
}
