using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Object = UnityEngine.Object;
using UnityEditor;

namespace Swing.Editor
{
	public static class SceneUtility
	{
		public static string[] findAllScenePaths()
		{
			var guids = AssetDatabase.FindAssets("t:Scene");
			var paths = Array.ConvertAll<string, string>(guids, AssetDatabase.GUIDToAssetPath);
			paths = Array.FindAll(paths, File.Exists); // Unity erroneously considers folders named something.unity as scenes, remove them
			return paths;
		}


		public delegate void ProcessAllScenesDelegate( string _scenePath, Object _sceneObject );

		public static void processAllScenes(
			ProcessAllScenesDelegate _callback )
		{
			processAllScenes(
				"Processing {0} Scenes",
				"Processing scene {1}/{0} : {2}",
				_callback);
		}
		/// <summary>
		/// Format {0} : scene count
		/// Format {1} : scene index
		/// Format {2} : scene path
		/// </summary>
		public static void processAllScenes(
			string _titleFormat,
			string _messageFormat,
			ProcessAllScenesDelegate _callback )
		{
			if (!EditorApplication.SaveCurrentSceneIfUserWantsTo())
			{
				return;
			}

			EditorCoroutine.start(
				processAllScenesCoroutine(_titleFormat, _messageFormat, _callback));
		}
		static IEnumerator processAllScenesCoroutine(
			string _titleFormat,
			string _messageFormat,
			ProcessAllScenesDelegate _callback )
		{
			var scenePaths = findAllScenePaths();
			var sceneCount = scenePaths.Length;
			Debug.Log(string.Format("Processing {0} scenes", sceneCount));

			for (int i = 0; i < sceneCount; i++)
			{
				var scenePath = scenePaths[i];

				EditorUtility.DisplayProgressBar(
					string.Format(_titleFormat, sceneCount, i, scenePath),
					string.Format(_messageFormat, sceneCount, i, scenePath),
					(float)i / sceneCount);

				Object sceneObject = AssetDatabase.LoadMainAssetAtPath(scenePath);

				if (EditorApplication.OpenScene(scenePath))
				{
					// delay one frame to give a chance for all Awake/Start/OnEnable callbacks to trigger
					yield return null;

					try
					{
						_callback(scenePath, sceneObject);
					}
					catch (Exception e)
					{
						Debug.LogError(string.Format("Error while processing scene  '{0}'", scenePath), sceneObject);
						Debug.LogException(e);
					}
				}
				else
				{
					Debug.LogError(string.Format("Failed to open scene '{0}'", scenePath), sceneObject);
				}
			}

			EditorUtility.ClearProgressBar();
			EditorApplication.NewScene();
		}

		[MenuItem("Swing/Scenes/Resave All Scenes")]
		public static void resaveAllScenes()
		{
			processAllScenes(
				"Resaving {0} Scenes",
				"Resaving scene {1}/{0} : {2}",
				( scenePath, sceneObject ) =>
				{
					if (EditorApplication.SaveScene())
					{
						Debug.Log(string.Format("Scene '{0}' saved successfully", scenePath), sceneObject);
					}
					else
					{
						Debug.LogError(string.Format("Scene '{0}' save failed", scenePath), sceneObject);
					}
				});
		}

		[MenuItem("Swing/Scenes/Test Open All Scenes")]
		static void openAllScenes()
		{
			processAllScenes(
				"Opening {0} Scenes",
				"Opening scene {1}/{0}\n{2}",
				( scenePath, sceneObject ) =>
				{
					Debug.Log(string.Format("Scene '{0}' open successfully", scenePath), sceneObject);
				});
		}
	}
}