using System.Collections;
using Animations;
using Audio;
using InteractiveModules;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;

namespace Game
{
	public class ScreenController : MonoBehaviour
	{
		public const float FadeInDuration = 0.5f;
		public const float FadeOutDuration = 0.5f;
		
		[SerializeField] private GameScreensSet gameScreensSet;
		[SerializeField] private VisitedScreensManager visitedScreensManager;
		[SerializeField] private ColorManager colorManager;
		[SerializeField] private GameScreenAsset startScreen;
		[SerializeField] private GameScreenAsset resumeScreen;
		[SerializeField] private GameScreenAsset restartScreen;
		[SerializeField] private GameScreenAsset menuScreen;
		[SerializeField] private GameScreenAsset lastRoomScreen;
		
		[SerializeField] private UnityEngine.Camera gameCamera;
		[SerializeField] private TextChoiceModule textChoiceModule;
		[SerializeField] private TextInfoModule textInfoModule;
		[SerializeField] private ImageInfoModule imageInfoModule;
		[SerializeField] private Transform topModulePosition;
		[SerializeField] private Transform bottomModulePosition;
		[SerializeField] private Transform centralModulePosition;
		[SerializeField] private MusicPlayer musicPlayer;
		[SerializeField] private AudioSource audioSourceScreenOnEnter;
		[SerializeField] private AudioSource audioSourceFade;
		[SerializeField] private TransitionController transitionController;
		
		public GameScreenAsset CurrentScreen { get; private set; }
		public GameScreenAsset LastScreen { get; private set; }
		public GameScreenAsset SavedLastRoomScreen { get; private set; }

		public Color CurrentBackgroundColor { get; private set; }
		public Color CurrentTextColor { get; private set; }
		public bool IsScreenLoading { get; private set; }
		private InteractiveModule CurrentInteractiveModule { get; set; }

		private Coroutine cameraBackgroundBlendCoroutine;
		
		private void Start()
		{
			Application.targetFrameRate = 60;
			
			foreach (var gameScreenAsset in gameScreensSet.items)
				gameScreenAsset.OnEnable();
			
			LoadScreen(startScreen);
		}

		private void Update()
		{
			if(Input.GetMouseButtonUp(0))
				EventSystem.current.SetSelectedGameObject(null);	
		}

		public void Click()
		{	
			if(!IsScreenLoading && !CurrentScreen.IsInteractive)
				LoadNextScreen();
		}
		
		public void LoadNextScreen()
		{
			LoadScreen(CurrentScreen.NextScreen);
		}
		
		public void LoadScreen(GameScreenAsset screenAsset)
		{
			if (IsScreenLoading)
				return;
			
			StopAllCoroutines();
			StartCoroutine(LoadingScreen(screenAsset));
		}

		IEnumerator LoadingScreen(GameScreenAsset screenAsset)
		{
			IsScreenLoading = true;
			
			if(!audioSourceFade.isPlaying)
				audioSourceFade.Play();

			yield return null;
			
			if (screenAsset == resumeScreen || (screenAsset == menuScreen && CurrentScreen == menuScreen))
				screenAsset = LastScreen;
			else if (screenAsset == lastRoomScreen)
				screenAsset = SavedLastRoomScreen;
			else if (screenAsset == restartScreen)
			{
				visitedScreensManager.Clear();
				SceneManager.LoadScene(SceneManager.GetActiveScene().name);
			}

			bool usingTransitionController = (screenAsset is RoomScreenAsset && CurrentScreen is CorridorScreenAsset) || screenAsset is CorridorScreenAsset;
			
			if (CurrentScreen != null)
			{
				// Unload old screen
				CurrentScreen.Visited();
				textInfoModule.Deactivate();
				textChoiceModule.Deactivate();
				imageInfoModule.Deactivate();
				if(CurrentScreen.UseInteractiveModule)
					CurrentInteractiveModule.Deactivate();
				if(CurrentScreen is RoomScreenAsset)
					SavedLastRoomScreen = CurrentScreen;
				
				// Color blend
				if (screenAsset.overrideColor && !usingTransitionController)
					SetBackgroundColor(screenAsset.backgroundColor, FadeOutDuration + FadeInDuration);
				
				yield return new WaitForSeconds(FadeOutDuration + 0.1f);
			}

			// Load new one
			LastScreen = CurrentScreen;
			CurrentScreen = screenAsset;
			visitedScreensManager.Visit(CurrentScreen);

			if (usingTransitionController)
			{
				transitionController.Open(CurrentBackgroundColor);
				SetBackgroundColor(screenAsset.backgroundColor);
			}

			if (CurrentScreen.overrideColor)
			{
				CurrentBackgroundColor = colorManager.GetColor(CurrentScreen.backgroundColor);
				CurrentTextColor = colorManager.GetColor(CurrentScreen.textColor);
			}

			CurrentScreen.Enter();

			if (CurrentScreen.audioOnOpen != null && CurrentScreen.audioOnOpen.Length > 0)
			{
				audioSourceScreenOnEnter.clip = CurrentScreen.audioOnOpen[Mathf.Min(CurrentScreen.VisitsCount, CurrentScreen.audioOnOpen.Length - 1)];
				audioSourceScreenOnEnter.Play();
			}

			if(CurrentScreen.music != null)
				musicPlayer.PlayMusic(CurrentScreen.music);
			
			if (CurrentScreen.UseTextInfo)
			{
				textInfoModule.transform.position = GetTextInfoModulePosition();
				textInfoModule.Activate(CurrentTextColor);
			}

			if (CurrentScreen.UseTextChoice)
			{
				textChoiceModule.transform.position = GetTextChoiceModulePosition();
				textChoiceModule.Activate();
			}

			if (CurrentScreen.UseImageInfo)
			{
				imageInfoModule.transform.position = GetImageInfoModulePosition();
				imageInfoModule.Activate();
			}

			if (CurrentScreen.UseInteractiveModule)
			{
				CurrentInteractiveModule = Instantiate(CurrentScreen.InteractiveModule, GetInteractiveModulePosition(), Quaternion.identity);
				CurrentInteractiveModule.Activate(this);
			}

			yield return new WaitForSeconds(FadeInDuration * 0.5f);
			IsScreenLoading = false;
		}

		private Vector3 GetTextInfoModulePosition()
		{
			if (CurrentScreen.ModulesCount == 2)
				return topModulePosition.position;
			
			return centralModulePosition.position;
		}
		
		private Vector3 GetTextChoiceModulePosition()
		{
			if (CurrentScreen.ModulesCount == 2)
				return bottomModulePosition.position;

			return centralModulePosition.position;
		}

		private Vector3 GetImageInfoModulePosition()
		{
			if (CurrentScreen.ModulesCount == 2)
				return bottomModulePosition.position;

			return centralModulePosition.position;
		}

		private Vector3 GetInteractiveModulePosition()
		{
			return centralModulePosition.position;
		}

		public void SetBackgroundColor(ColorType colorType, float duration = 0)
		{
			SetBackgroundColor(colorManager.GetColor(colorType));
		}
		
		public void SetBackgroundColor(Color color, float duration = 0)
		{
			if (duration > 0)
			{
				if(cameraBackgroundBlendCoroutine != null)
					StopCoroutine(cameraBackgroundBlendCoroutine);
				cameraBackgroundBlendCoroutine = StartCoroutine(BackgroundBlending(color, duration));
			}
			else
			{
				gameCamera.backgroundColor = color;
			}
		}
		
		private IEnumerator BackgroundBlending(Color color, float duration)
		{
			var startColor = gameCamera.backgroundColor;
			var targetColor = color;
			float progress = 0;

			while (progress < duration)
			{
				progress += Time.deltaTime;
				progress = Mathf.Min(progress, duration);
				gameCamera.backgroundColor = Color.Lerp(startColor, targetColor, progress / duration);
				yield return null;
			}
			
			cameraBackgroundBlendCoroutine = null;
		}
		
		private void OnDrawGizmos()
		{
			Gizmos.color = Color.magenta;
			Gizmos.DrawSphere(topModulePosition.position, 0.2f);
			Gizmos.DrawSphere(bottomModulePosition.position, 0.2f);
			Gizmos.DrawSphere(centralModulePosition.position, 0.2f);
		}
	}
}