#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using ConjureOS.CustomWindow;

namespace ConjureOS.MetadataWindow
{
    public class ConjureArcadeMetadataWindow : EditorWindow
    {
        private const string WindowName = "Arcade Game Metadata Editor";

        // Game Metadata
        private static ConjureArcadeMetadata metadata;
        private ConjureArcadeMetadataValidator metadataValidator;
        private SerializedObject serializedObject;

        // Metadata Properties
        private SerializedProperty gameTitleProperty;
        private SerializedProperty versionProperty;
        private SerializedProperty descriptionProperty;
        private SerializedProperty minNumPlayerProperty;
        private SerializedProperty maxNumPlayerProperty;
        private SerializedProperty useLeaderboardProperty;
        private SerializedProperty thumbnailProperty;
        private SerializedProperty gameplayImageProperty;
        private SerializedProperty developersProperty;
        private SerializedProperty genresProperty;

        private ReorderableList developersList;
        private ReorderableList genresList;

        // UI Properties
        private Vector2 scrollPos = Vector2.zero;

        private void OnEnable()
        {
            metadataValidator = new ConjureArcadeMetadataValidator();
            titleContent = new GUIContent(WindowName);

            if (!metadata)
            {
                OnLoad();
            }

            serializedObject = new SerializedObject(metadata);
            SetUpProperties(serializedObject);
        }

        [InitializeOnLoadMethod]
        private static void OnLoad()
        {
            if (!metadata)
            {
                metadata = AssetDatabase.LoadAssetAtPath<ConjureArcadeMetadata>(ConjureArcadeMetadata.MetadataAssetPath);

                // Data exists
                if (metadata)
                {
                    return;
                }

                metadata = CreateInstance<ConjureArcadeMetadata>();

                AssetDatabase.CreateAsset(metadata, ConjureArcadeMetadata.MetadataAssetPath);
                AssetDatabase.Refresh();
            }
        }

        private void OnGUI()
        {
            serializedObject.Update();

            // Add padding to the window
            int globalSpace = 2;
            int uniformPadding = ConjureArcadeGUI.Style.UniformPadding;
            RectOffset padding = new RectOffset(uniformPadding, uniformPadding, 0, 0);
            Rect area = new Rect(
                padding.right,
                padding.top,
                position.width - (padding.left),
                position.height - (padding.top + padding.bottom));

            // Generate input fields
            GUILayout.BeginArea(area);

            // Scrollbar
            RectOffset vertScrollbarPadding = new RectOffset(uniformPadding, 0, 0, 0);
            GUIStyle vertScrollbarSkin = new GUIStyle(GUI.skin.verticalScrollbar);
            vertScrollbarSkin.margin = vertScrollbarPadding;

            scrollPos = GUILayout.BeginScrollView(scrollPos, false, true, new GUIStyle(GUI.skin.horizontalScrollbar), vertScrollbarSkin);

            GUILayout.Space(uniformPadding);
            GUILayout.Label("GAME METADATA", EditorStyles.boldLabel);

            EditorGUILayout.PropertyField(gameTitleProperty, new GUIContent("Game Title"));
            ShowErrorMessage(metadataValidator.GameTitleErrorMessage);
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(versionProperty, new GUIContent("Version"));
            ShowErrorMessage(metadataValidator.VersionErrorMessage);
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(descriptionProperty, new GUIContent("Description"), GUILayout.Height(150));
            ShowErrorMessage(metadataValidator.DescriptionErrorMessage);
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(minNumPlayerProperty, new GUIContent("Min Number of Players"));
            ShowErrorMessage(metadataValidator.MinNumPlayerErrorMessage);
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(maxNumPlayerProperty, new GUIContent("Max Number of Players"));
            ShowErrorMessage(metadataValidator.MaxNumPlayerErrorMessage);
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(useLeaderboardProperty, new GUIContent("Use Leaderboard"));
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(thumbnailProperty, new GUIContent("Thumbnail"));
            ShowErrorMessage(metadataValidator.ThumbnailErrorMessage);
            GUILayout.Space(globalSpace);

            EditorGUILayout.PropertyField(gameplayImageProperty, new GUIContent("Gameplay Image"));
            ShowErrorMessage(metadataValidator.GameplayImageErrorMessage);
            GUILayout.Space(globalSpace);

            GUILayout.Space(10);
            developersList.DoLayoutList();
            ShowErrorMessage(metadataValidator.DevelopersErrorMessage);

            GUILayout.Space(10);
            UpdateReorderableListInteractions(genresList, ConjureArcadeMetadata.MaxSelectedGenres);
            genresList.DoLayoutList();
            ShowErrorMessage(metadataValidator.GenresErrorMessage);

            GUILayout.Space(10);

            // Show release date and last change date ONLY if a date has been set
            if (metadata.ReleaseDate != DateTime.MinValue)
            {
                GUILayout.Label("Release Date: " + metadata.ReleaseDate.ToString());
            }
            if (metadata.LastGameUpdate != DateTime.MinValue)
            {
                GUILayout.Label("Last Change: " + metadata.LastGameUpdate.ToString());
            }

            // Validate properties and save data
            serializedObject.ApplyModifiedProperties();

            GUILayout.Space(30);
            if (GUILayout.Button("Execute Validation", GUILayout.Width(150)))
            {
                metadataValidator.ValidateMetadata(metadata);
            }
            
            GUILayout.Space(globalSpace);

            ShowValidationResultMessage();
            
            GUILayout.Space(uniformPadding);

            GUILayout.EndScrollView();
            GUILayout.EndArea();
        }

        private void ShowErrorMessage(string errorMessage)
        {
            if (errorMessage != string.Empty)
            {
                GUILayout.Label(errorMessage, ConjureArcadeGUI.Style.ErrorStyle);
                GUILayout.Space(3);
            }
        }

        private void ShowValidationResultMessage()
        {
            MetadataValidationStateType validationState = metadataValidator.GetValidationStateType();

            switch (validationState)
            {
                case MetadataValidationStateType.NotVerified:
                    // No message is displayed
                    return;

                case MetadataValidationStateType.Validated:
                    // No error, means it's a success
                    GUILayout.Label(ConjureArcadeGUI.Message.MetadataConfirmedMessage, ConjureArcadeGUI.Style.SuccessStyle);
                    GUILayout.Space(3);
                    break;

                case MetadataValidationStateType.Failed:
                    // Errors were detected
                    string plural = (metadataValidator.ErrorCount > 1) ? "s" : "";
                    string formatedMessage = string.Format(ConjureArcadeGUI.Message.MetadataFailedMessage, metadataValidator.ErrorCount, plural);
                    ShowErrorMessage(formatedMessage);
                    break;
            }
        }

        private void SetUpProperties(SerializedObject serializedObject)
        {
            // Get data
            gameTitleProperty = serializedObject.FindProperty("gameTitle");
            versionProperty = serializedObject.FindProperty("version");
            descriptionProperty = serializedObject.FindProperty("description");
            minNumPlayerProperty = serializedObject.FindProperty("minNumPlayer");
            maxNumPlayerProperty = serializedObject.FindProperty("maxNumPlayer");
            useLeaderboardProperty = serializedObject.FindProperty("useLeaderboard");
            thumbnailProperty = serializedObject.FindProperty("thumbnail");
            gameplayImageProperty = serializedObject.FindProperty("gameplayImage");

            // Get developers data and prepare list
            developersProperty = serializedObject.FindProperty("developers");
            developersList = new ReorderableList(serializedObject, developersProperty, true, true, true, true);
            developersList.drawElementCallback = DrawDevelopersListItems;
            developersList.drawHeaderCallback = DrawDevelopersListHeader;
            developersList.onReorderCallback = OnDevelopersReorder;


            // Get genres data and prepare list
            genresProperty = serializedObject.FindProperty("genres");
            genresList = new ReorderableList(serializedObject, genresProperty, true, true, true, true);
            genresList.drawElementCallback = DrawGenresListItems;
            genresList.drawHeaderCallback = DrawGenresListHeader;
        }

        private void UpdateReorderableListInteractions(ReorderableList list, int countLimit)
        {
            // Hide or show the "Add" button only if the count limit has not been reached
            if (genresList.count >= countLimit)
            {
                list.displayAdd = false;
            }
            else
            {
                list.displayAdd = true;
            }
        }


        // ReorderableList Callbacks =====
        private void DrawGenresListItems(Rect rect, int index, bool isActive, bool isFocused)
        {
            // Get the selected genre of the current item
            var element = genresProperty.GetArrayElementAtIndex(index);
            var selectedGenre = element.FindPropertyRelative(nameof(GameGenre.selectedGenre));

            var popupHeight = EditorGUI.GetPropertyHeight(selectedGenre);

            // Create popup
            selectedGenre.intValue = EditorGUI.Popup(new Rect(rect.x, rect.y, rect.width, popupHeight), selectedGenre.intValue, ConjureArcadeMetadata.GenreOptions);
        }

        private void DrawDevelopersListItems(Rect rect, int index, bool isActive, bool isFocused)
        {
            // Get the selected genre of the current item
            var element = developersProperty.GetArrayElementAtIndex(index);

            // Create popup
            GUIStyle fieldErrorIndicatorStyle = new GUIStyle(EditorStyles.textField);
            fieldErrorIndicatorStyle.normal.textColor = ConjureArcadeGUI.Style.ColorError;

            for (int i = 0; i < metadataValidator.DevelopersErrorIndex.Count; i++)
            {
                if (index == metadataValidator.DevelopersErrorIndex[i])
                {
                    element.stringValue = EditorGUI.TextField(new Rect(rect.x, rect.y, rect.width, rect.height), element.stringValue, fieldErrorIndicatorStyle);
                    return;
                }
            }

            element.stringValue = EditorGUI.TextField(new Rect(rect.x, rect.y, rect.width, rect.height), element.stringValue);
        }

        private void DrawGenresListHeader(Rect rect)
        {
            DrawListHeader(rect, "Genres");
        }

        private void DrawDevelopersListHeader(Rect rect)
        {
            DrawListHeader(rect, "Developers");
        }

        private void DrawListHeader(Rect rect, string name)
        {
            EditorGUI.LabelField(rect, name);
        }

        private void OnDevelopersReorder(ReorderableList reList)
        {
            // On reorder of the developers list, data are revalidated because of the new order
            serializedObject.ApplyModifiedProperties();
            metadataValidator.ValidateDevelopersList(metadata.Developers);
        }
    }
}
#endif