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 hiveAdiz;

//	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");

			#if !UNITY_EDITOR
			AdizBanner banner = HiveAdizManager.shared.GetAdizBanner();
			Debug.Log ("Banner Hide");
			if(banner != null) {
				banner.Destroy();
				Debug.Log ("Banner Destroy");
			}
			#endif

			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 ();

//			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 ()
		{
			Debug.Log ("on Retry button");

			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);

			// 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");
		}
	}
}
