using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityStandardAssets.Characters.ThirdPerson;
using GameUtility;
using GameNetwork;
using hive;
using hive.adkit.daro;

//	Summary
//		* 게임 진행을 제어한다.

namespace Game
{
	/*
		Game의 진행 상태.
		Ready: 게임 진행 대기 상태.
		Play: 게임 진행 중.
		Pause: 게임 일시 정지.
		End: 게임 종료.
	*/
	public enum GameState
	{
		Ready,
		Play,
		Pause,
		End
	}

	/*
		게임 진행 관리자.
	*/
	public class GameManager : MonoBehaviour
	{
#if UNITY_EDITOR
		public bool showDebug = true;
#else
	public bool showDebug = false;
#endif // UNITY_EDITOR

		//
		public GameState GS;

		public GameObject BottomBar;

		public GameObject Player;

		public GameObject DebugPanel;
		public GameObject DefaultPanel;
		public GameObject ScorePanel;
		public GameObject PausePanel;
		public GameObject[] SideBars;

		public GameObject[] Bottoms;

		public GameObject[] Backgrounds;

		public Text TimeLabel;

		public Text SpeedLevel;

		public AudioSource m_BackgroundAudioSource;

		float m_time_interval;

		float m_Last_interval;

		public SimpleCharacterControl m_Character_SpaceMan;
		public SimpleCharacterControl m_Character_SuperSuit;
		public SimpleCharacterControl m_Character_DevilSuit;
		PlayerController m_PlayerController;
		PlayerHealth m_PlayerHealth;
		BottomController m_BottomController;

		GameBalance m_GameBalance;

		SimpleCharacterControl Character;

		float m_Speed = 4f;

		bool[] sendAchievementFlag = { false, false, false, false, false };
		// 10, 30, 60, 120, 180;

		// Use this for initialization
		void Start()
		{
			Debug.Log("START");
			Player.SetActive(true);

#if UNITY_EDITOR
			PlayerSettings.Instance().BaseHealth = 100;
			PlayerSettings.Instance().HealthUpValue = 10;

			PlayerSettings.Instance().BaseSpeed = 4f;
			PlayerSettings.Instance().SpeedUpValue = 0.1f;
#endif // UNITY_EDITOR

			m_PlayerController = Player.GetComponent<PlayerController>();
			m_PlayerController.RecoveryValue = 10;
			m_PlayerController.DamageValue = 40;

			m_PlayerHealth = Player.GetComponent<PlayerHealth>();
			m_BottomController = GetComponent<BottomController>();
			m_PlayerHealth.StartingHealth = PlayerSettings.Instance().MaxHealth;

			m_GameBalance = GetComponent<GameBalance>();

			GameReady();
			UpdateAspectObjects();
			GS = GameState.Play;

			DebugPanel.SetActive(showDebug);
		}

		// Update is called once per frame
		void Update()
		{
			if (GameState.Play == GS)
			{
				if (PlayerState.Death != m_PlayerController.PS)
				{
					GamePlay();
				}
				else
				{
					GameEnd();
				}

				UpdatePlayerState();
			}

			UpdateDebugText();
		}

		// MARK: - Public
		/*
			Player의 rigid body를 얻어온다.

			@return RigidBody
	 	*/
		public Rigidbody GetPlayerRigidBody()
		{
			return Character.GetComponent<Rigidbody>();
		}

		/*
	 		Exit Button event.
		*/
		public void onGameExitButton()
		{
			Debug.Log("on Exit button");

			SceneManager.LoadScene("Home", LoadSceneMode.Single);
			HIVEManager.shared.showReview();
			HiveAdKitManager.shared.loadBanner();

			//			SceneManager.LoadScene ("Home", LoadSceneMode.Single);
		}

		// public void onHIVEManagerShowReview(bool isSuccess, string message)
		// {
		// 	Debug.Log ("onHIVEManagerShowReview - " + isSuccess + " message: " + message);

		// 	SceneManager.LoadScene ("Home", LoadSceneMode.Single);
		// }

		/*
	 		Retry Button event.
		*/
		public void onGameRetryButton()
		{
			ScorePanelTouchEnable(false); // 광고 노출후 닫히고 콜백이 올 때 약간의 지연이 생겨 중복 터치 방지를 위해 설정함
			HiveAdKitManager.shared.showInterstitial();
		}

		public void retryGame()
		{
			GameReady();
			GS = GameState.Play;
		}

		/*
	 		Pause Button event.
	 	*/
		public void onGamePauseButton()
		{
			Debug.Log("on Pause button");

			GS = GameState.Pause;
			Character.Pause();

			m_BackgroundAudioSource.Pause();

			foreach (GameObject background in Backgrounds)
			{
				background.GetComponent<AnimationScroll>().Pause();
			}

			foreach (GameObject sideBar in SideBars)
			{
				sideBar.GetComponent<AnimationScroll>().Pause();
			}

			m_BottomController.Pause();

			DefaultPanel.GetComponent<Image>().color = new Color(0, 0, 0, 200);
			PausePanel.SetActive(true);

			Player.SetActive(false);
		}

		/*
	 		Resume Button event.
	 	*/
		public void onGameResumeButton()
		{
			Debug.Log("on Resume button");

			Player.SetActive(true);

			DefaultPanel.GetComponent<Image>().color = new Color(0, 0, 0, 0);
			PausePanel.SetActive(false);

			m_BottomController.Resume(m_Speed);

			foreach (GameObject background in Backgrounds)
			{
				background.GetComponent<AnimationScroll>().Resume();
			}

			foreach (GameObject sideBar in SideBars)
			{
				sideBar.GetComponent<AnimationScroll>().Resume();
			}

			m_BackgroundAudioSource.Play();
			Character.Resume();

			GS = GameState.Play;
		}

		// MARK: - Private
		/*
			Screen 사이즈에 대해 GameObject(s)을 resizing 한다.
	 	*/
		void UpdateAspectObjects()
		{
			float defaultAspect = 320.0f / 480.0f;
			float windowAspect = (float)UnityEngine.Screen.width / (float)UnityEngine.Screen.height;
			float aspectRatio = windowAspect / defaultAspect;

			Debug.Log("Update aspect ratio - " + aspectRatio);

			// Camera
			{
				float cameraAspect = Camera.main.aspect;
				float defaultSize = Camera.main.orthographicSize;

				Camera.main.orthographicSize = defaultSize * (defaultAspect / cameraAspect);

				Vector3 CameraPos = Camera.main.transform.position;

				CameraPos.y += (defaultSize - Camera.main.orthographicSize);

				Camera.main.transform.position = CameraPos;
			}

			// Bottom Dead Zone.
			{
				Vector3 origin = BottomBar.transform.position;
				origin.y = -(Camera.main.orthographicSize + 2);

				BottomBar.transform.position = origin;
			}
		}

		/*
			Player의 heath에 따른 state를 조정한다.
	 	*/
		void UpdatePlayerState()
		{
			if (m_PlayerHealth.CurrentHealth <= 0)
			{
				m_PlayerController.PS = PlayerState.Death;
			}
		}

		/*
			게임 진행 상태를 Ready로 변경한다.
	 	*/
		void GameReady()
		{
			Debug.Log("GameReady");

			GS = GameState.Ready;
			m_PlayerController.PS = PlayerState.Move;

			DefaultPanel.GetComponent<Image>().color = new Color(0, 0, 0, 0);
			DefaultPanel.SetActive(true);
			ScorePanel.SetActive(false);
			PausePanel.SetActive(false);

			if (Character != null)
			{
				DestroyImmediate(Character.gameObject);
			}

			m_BottomController.RemoveAllVisibleItems();
			m_GameBalance.ResetData();

			// float term  = Camera.main.orthographicSize;

			// for (int i = 0; i < 3; i++) {
			// 	BottomItem item = internalCreateBottomItem();

			// 	Vector3 position = item.transform.position;
			// 	position.y = -1 * term / 3 * i - term / 3;

			// 	item.transform.position	= position;
			// }

			// Background
			foreach (GameObject background in Backgrounds)
			{
				background.GetComponent<AnimationScroll>().Resume();
			}

			// Sidebar
			foreach (GameObject sideBar in SideBars)
			{
				sideBar.GetComponent<AnimationScroll>().Resume();
			}

			// Character
			if (PlayerSettings.Instance().SuperSuit)
			{
				Character = Instantiate(m_Character_SuperSuit, new Vector3(0f, 0f, 0f), Quaternion.identity);
			}
			else if (PlayerSettings.Instance().DevilSuit)
			{
				Character = Instantiate(m_Character_DevilSuit, new Vector3(0f, 0f, 0f), Quaternion.identity);
			}
			else
			{
				Character = Instantiate(m_Character_SpaceMan, new Vector3(0f, 0f, 0f), Quaternion.identity);
			}

			// rotate
			Quaternion rotate = Quaternion.identity;
			rotate.y = 0.5f;
			Character.transform.rotation = rotate;

			// position
			Character.transform.position = new Vector3(0, 6, 0);

			Character.GetComponent<FootStep>().FootStepSource = Player.GetComponent<AudioSource>();

			{
				float speed = PlayerSettings.Instance().MaxSpeed;

				Character.GetComponent<PlayerMovement>().m_Speed = speed;

				SpeedLevel.text = "Lv " + PlayerSettings.Instance().SpeedLevel;
			}

			m_PlayerController.Character = Character;

			m_PlayerHealth.StartingHealth = PlayerSettings.Instance().MaxHealth;

			Player.SetActive(true);

			m_time_interval = 0;
		}

		/*
			게임을 진행
		*/
		void GamePlay()
		{
			m_time_interval += Time.deltaTime;
			m_Last_interval += Time.deltaTime;

			m_Speed = m_GameBalance.GetGameSpeed(m_time_interval);

			if (m_BackgroundAudioSource.isPlaying == false)
			{
				m_BackgroundAudioSource.Play();
			}

			UpdateTimer();
			CreateBottomItem();
			UpdateBottomItems();

			if (PlayerSettings.Instance().canAchievement)
			{
				SendTimeAchievementToProvider(m_time_interval);
			}
		}

		/*
			게임을 종료한다.
	 	*/
		void GameEnd()
		{
			Debug.Log("Game end");

			if (PlayerState.Default == m_PlayerController.PS)
			{
				return;
			}

			HIVEManager.shared.promotionShowInAppPromotion();

			m_BackgroundAudioSource.Stop();
			m_PlayerController.Death();

			// Background
			foreach (GameObject background in Backgrounds)
			{
				background.GetComponent<AnimationScroll>().Pause();
			}

			// Sidebar
			foreach (GameObject sidbar in SideBars)
			{
				sidbar.GetComponent<AnimationScroll>().Pause();
			}

			Character.gameObject.SetActive(false);

			m_PlayerController.PS = PlayerState.Default;

			m_BottomController.Pause();

			GS = GameState.End;

			Text scoreLabel = ScorePanel.GetComponentInChildren<Text>();
			scoreLabel.text = GetTimeStringByValue(m_time_interval);
			ScorePanel.SetActive(true);
			ScorePanelTouchEnable(true);

			// send score data to game server.
			GameConnect.shared.SendScore((int)(m_time_interval * 100), onGameConnectSendScore);

			if (PlayerSettings.Instance().canAchievement)
			{
				SendTimeScoreToProvider(m_time_interval);
			}

			AddLevelExp((int)(m_time_interval * 100));
		}

		void AddLevelExp(int score)
		{
			HIVEManager.shared.dataStoreGet("PlayerTotalScore", (bool isSuccess, string data) =>
			{
				if (isSuccess)
				{
					int.TryParse(data, out int parsedScore);
					int totalScore = score + parsedScore;
					int level = (totalScore / 6000) + 1;

					// 애널리틱스 세그먼트, 타게팅 이벤트
					HIVEManager.shared.sendAnalyticsScoreLog("PlayerScore", score);
					HIVEManager.shared.sendAnalyticsScoreLog("PlayerTotalScore", totalScore);
					HIVEManager.shared.sendAnalyticsScoreLog("PlayerLevel", level);

					HIVEManager.shared.dataStoreSet("PlayerTotalScore", totalScore.ToString());
					HIVEManager.shared.dataStoreSet("PlayerLevel", level.ToString());
				}
			});
		}

		/*
			게임 진행 중 bottom item을 생성한다.
	 	*/
		void CreateBottomItem()
		{
			float speedRatio = m_GameBalance.currentGameSpeed / m_GameBalance.defaultGameSpeed;

			if (m_Last_interval < (1f / speedRatio))
			{
				return;
			}

			m_Last_interval = 0f;

			internalCreateBottomItem();

			//		Debug.Log("Create bottom item. " + item.transform.position);
		}

		BottomItem internalCreateBottomItem()
		{
			BottomItem item = m_GameBalance.GetBottomItem(m_time_interval);
			item.Speed = m_Speed;
			item.DisappearTime = 0.5f;
			item.bottomEventEnter += m_BottomController.onBottomEventEnter;
			item.bottomEventStay += m_BottomController.onBottomEventStay;
			item.bottomEventExit += m_BottomController.onBottomEventExit;

			return item;
		}

		/*
			게임 진행에 따른 bottom item(s)을 설정을 적용한다.
	 	*/
		void UpdateBottomItems()
		{
			BottomController.UpdateWithOptions(m_Speed);
		}

		/*
			게임 진행에 따른 timer text의 값을 변경한다.
	 	*/
		void UpdateTimer()
		{
			TimeLabel.text = GetTimeStringByValue(m_time_interval);
		}

		/*
			Play time에 따른 text format을 반환한다.

			@param value time interval (ms)

			@return text format string
		*/
		string GetTimeStringByValue(float value)
		{
			int minutes = (int)value / 60;
			int seconds = (int)value % 60;
			int fraction = (int)(value * 100) % 100;

			return string.Format("{0:00}:{1:00}.{2:00}", minutes, seconds, fraction);
		}

		// MARK: -
		/*
			GooglePlay(or GameCenter)의 리더보드에 점수를 전송한다.

			@param time 게임 진행 시간(ms)
	 	*/
		void SendTimeScoreToProvider(float time)
		{
			int timeToScore = (int)(time * 100);
			string scoreString = timeToScore.ToString();

			string leaderboardId = "CgkImOWwjqIEEAIQBQ";

			Debug.Log("SendTimeScoreToProvider - score: " + timeToScore + " scoreString: " + scoreString);

			// TODO: check 
#if UNITY_ANDROID
			ProviderGoogle.leaderboardsSubmitScore(leaderboardId, timeToScore);
#elif UNITY_IOS
			ProviderApple.reportScore (scoreString, leaderboardId, onReportLeaderboard);
#endif
		}

		/*
			SendTimeScoreToProvider()을 결과 method.
	 	*/
		void onReportLeaderboard(ResultAPI result)
		{
			Debug.Log("onReportLeaderboard - " + result);
		}

		/*
			GooglePlay(or GameCenter)의 업적을 전송한다.

			@param time 게임 진행 시간(ms)
	 	*/
		void SendTimeAchievementToProvider(float time)
		{
			int timeInt = (int)time;
			int index = -1;

			switch (timeInt)
			{
				case 10:
					index = 0;
					break;
				case 30:
					index = 1;
					break;
				case 60:
					index = 2;
					break;
				case 120:
					index = 3;
					break;
				case 180:
					index = 4;
					break;
				default:
					break;
			}

			if (index < 0)
			{
				return;
			}

			if (sendAchievementFlag[index] == true)
			{
				return;
			}

			if (sendAchievementFlag[index] == false)
			{
				sendAchievementFlag[index] = true;
			}

			string achievementId = null;

			switch (index)
			{
				case 0:
					achievementId = "CgkImOWwjqIEEAIQAA";
					break;
				case 1:
					achievementId = "CgkImOWwjqIEEAIQAQ";
					break;
				case 2:
					achievementId = "CgkImOWwjqIEEAIQAg";
					break;
				case 3:
					achievementId = "CgkImOWwjqIEEAIQAw";
					break;
				case 4:
					achievementId = "CgkImOWwjqIEEAIQBA";
					break;
				default:
					break;
			}

			if (achievementId == null)
			{
				return;
			}

			Debug.Log("SendTimeAchievementToProvider - timeInt: " + timeInt + " achievementId: " + achievementId);

			// TODO: check 
#if UNITY_ANDROID
			ProviderGoogle.achievementsUnlock(achievementId);
#elif UNITY_IOS
			ProviderApple.reportAchievement ("100", true, achievementId, onReportAchievement);
#endif
		}

		/*
			SendTimeAchievementToProvider() 결과 method
	 	*/
		void onReportAchievement(ResultAPI result)
		{
			Debug.Log("onReportAchievement - " + result);
		}

		// MARK: - For DEBUG
		void UpdateDebugText()
		{
#if !UNITY_EDITOR
		return;
#else
			if (showDebug == false)
			{
				return;
			}

			int FPS = (int)(1f / Time.deltaTime);

			Text label = DebugPanel.GetComponentInChildren<Text>();

			BottomItem[] bottoms = FindObjectsOfType(typeof(BottomItem)) as BottomItem[];

			string str = string.Format("Health: {0} / {1}\nSpeed: {2:0.0}x\nPlayer Speed: {3}\nNumberOfBottoms: {4}\nBottomType: {5}\nFPS: {6}",
							m_PlayerHealth.CurrentHealth,
							m_PlayerHealth.StartingHealth,
							m_GameBalance.currentGameSpeed / m_GameBalance.defaultGameSpeed,
							(float)PlayerSettings.Instance().MaxSpeed,
							bottoms.Length,
							m_PlayerController.GetCurrentBottomType().ToString(),
							FPS
						);

			label.text = str;
#endif // UNITY_EDITOR
		}


		//====================================
		//	GameConnect 콜백 핸들러
		//====================================
		/*
			게임 서버에 score전달 callback method.

			@param success 성공 여부.
			@param message 결과 메시지.
	 	*/
		void onGameConnectSendScore(bool success, string message)
		{
			Debug.Log("onGameConnectSendScore");
		}

		void ScorePanelTouchEnable(bool isOn)
		{
			CanvasGroup cg = ScorePanel.GetComponent<CanvasGroup>();
			if (cg == null)
				cg = ScorePanel.AddComponent<CanvasGroup>();

			cg.interactable = isOn;
			cg.blocksRaycasts = isOn;
		}
	}
}
