﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using NextechAR.ARitize.Plugin;

[CustomEditor(typeof(ExperienceInfo))]
[CanEditMultipleObjects]
public class ExperienceInfoEditor : Editor
{

    //this stuff is duped for now but should be consolidated
    public class ARitizerEditorStyles
    {
        public GUIStyle backButton;
        public GUIStyle menuButton;
        public GUIStyle badButton;
        public GUIStyle titleText;
        public GUIStyle sectionHeaderText;
        public GUIStyle experienceListButton;
        public GUIStyle bigButton;
        public GUIStyle boldFoldout;
        public GUIStyle centeredLargeText;
    }

    public ARitizerEditorStyles editorStyles;

    void SetStyles()
    {
        editorStyles = new ARitizerEditorStyles();
        editorStyles.backButton = new GUIStyle("Button");
        editorStyles.backButton.fixedWidth = 50;

        editorStyles.menuButton = new GUIStyle("Button");
        editorStyles.menuButton.fixedWidth = 150;

        editorStyles.badButton = new GUIStyle("Button");
        editorStyles.badButton.fixedWidth = 150;
        editorStyles.badButton.normal.textColor = Color.red;

        editorStyles.experienceListButton = new GUIStyle("Button");
        editorStyles.experienceListButton.fixedWidth = 350;

        editorStyles.titleText = new GUIStyle("Label");
        editorStyles.titleText.fontSize = 20;
        editorStyles.titleText.alignment = TextAnchor.UpperCenter;
        editorStyles.titleText.fixedHeight = 200;

        editorStyles.sectionHeaderText = new GUIStyle("Label");
        editorStyles.sectionHeaderText.fontSize = 13;
        editorStyles.sectionHeaderText.alignment = TextAnchor.UpperLeft;
        editorStyles.sectionHeaderText.fontStyle = FontStyle.Bold;
        editorStyles.sectionHeaderText.fixedHeight = 200;

        editorStyles.bigButton = new GUIStyle("Button");
        editorStyles.bigButton.fixedHeight = 80;
        editorStyles.bigButton.fontSize = 20;

        editorStyles.boldFoldout = EditorStyles.foldout;
        editorStyles.boldFoldout.fontStyle = FontStyle.Bold;

        editorStyles.centeredLargeText = new GUIStyle("Label");
        editorStyles.centeredLargeText.alignment = TextAnchor.UpperCenter;
        editorStyles.centeredLargeText.fontSize = 20;
        editorStyles.centeredLargeText.fixedHeight = 80;

        hasInitializedStyles = true;
    }

    bool hasInitializedStyles = false;

    // SerializedProperty version;
    SerializedProperty arType;
    SerializedProperty orientation;
    SerializedProperty modules;
    SerializedProperty previewBlacklist;
    SerializedProperty forcedDependencies;


    //slam
    SerializedProperty slamSurfaces;
    SerializedProperty navigationGuidanceTarget;



    //image tracking
    SerializedProperty imageTargetSlug;
    SerializedProperty imageTargetGuide;


    //face tracking
    SerializedProperty faceMesh;

    //wikitude object recog
    SerializedProperty wtoFile;
    SerializedProperty objectTarget;
    SerializedProperty hideOnTrackingLost;

    SerializedProperty trackableSettings;

    // public Object wtoFile;
    // public string objectTarget;
    // public bool hideOnTrackingLost = false;
    Color defColor = Color.white;

    List<System.Type> moduleList;

    void OnEnable()
    {
        moduleList = new List<System.Type>();
        moduleList.Add(typeof(FollowTargetModule));
        moduleList.Add(typeof(LiveStreamModule));
        moduleList.Add(typeof(EnvironmentLightingModule));
        moduleList.Add(typeof(LearningStepsModule));
        moduleList.Add(typeof(LookAtModule));
        moduleList.Add(typeof(CameraSettingsModule));
        moduleList.Add(typeof(RotatorModule));
        moduleList.Add(typeof(UIModule));
        moduleList.Add(typeof(QualitySettingsARModule));
        moduleList.Add(typeof(TransformManipulatorModule));
        moduleList.Add(typeof(InputOutputModule));
        moduleList.Add(typeof(PostProcessorModule));
        moduleList.Add(typeof(VideoModule));

        // internal use only
        // moduleList.Add(typeof(ScreenARCarouselModule));
        // moduleList.Add(typeof(HologramModule));
        // moduleList.Add(typeof(QuizModule));
        // moduleList.Add(typeof(PortalModule));


        // moduleList.Sort();

        moduleList.Sort((x, y) => string.Compare(x.ToString(), y.ToString()));


        defColor = GUI.color;
        // version = serializedObject.FindProperty("version");
        orientation = serializedObject.FindProperty("orientation");
        arType = serializedObject.FindProperty("arType");
        modules = serializedObject.FindProperty("modules");
        previewBlacklist = serializedObject.FindProperty("previewBlacklist");
        forcedDependencies = serializedObject.FindProperty("forcedDependencies");

        //slam
        slamSurfaces = serializedObject.FindProperty("slamSurfaces");
        navigationGuidanceTarget = serializedObject.FindProperty("navigationGuidanceTarget");

        //image tracking
        imageTargetSlug = serializedObject.FindProperty("imageTargetSlug");
        imageTargetGuide = serializedObject.FindProperty("imageTargetGuide");
        trackableSettings = serializedObject.FindProperty("trackableSettings");


        //face tracking
        faceMesh = serializedObject.FindProperty("faceMesh");

        //object tracking
        wtoFile = serializedObject.FindProperty("wtoFile");
        objectTarget = serializedObject.FindProperty("objectTarget");
        hideOnTrackingLost = serializedObject.FindProperty("hideOnTrackingLost");


    }

    public override void OnInspectorGUI()
    {
        if (!hasInitializedStyles)
        {
            SetStyles();
        }

        if (currentMenuState == DataMenuState.defaultView)
        {
            DefaultView();
        }
        else if (currentMenuState == DataMenuState.addingModule)
        {
            AddingModulesView();
        }
        // else if(currentMenuState == DataMenuState.inspectingModule)
        // {
        // 	InspectingModulesView();
        // }


    }

    [SerializeField]
    DataMenuState currentMenuState;

    enum DataMenuState
    {
        defaultView,
        addingModule,
        // inspectingModule,
    }

    bool showModeControls = false;

    public void PutPrefabIntoScene()
    {
        //fred
        string path = AssetDatabase.GetAssetPath(serializedObject.targetObject);
        path = path.Replace(serializedObject.targetObject.name, "AnchorForAR.prefab");
        path = path.Replace(".asset", "");

        if (!FileManager.FileExists(path))
        {
            Debug.LogError("Prefab missing from " + path);
            return;
        }

        Object obj = AssetDatabase.LoadAssetAtPath(path, typeof(Object));

        if (obj != null)
        {

            // open prefab
            // AssetDatabase.OpenAsset(obj);

            // return;

            Selection.activeObject = obj;

            // if(scenePrefabInstance != null)
            // {

            // }

            // if(scenePrefabInstance == null)
            // {

            // }

            scenePrefabInstance = PrefabUtility.InstantiatePrefab(obj);
            StaticCoroutine.Start(SelectionCoroutine(obj, scenePrefabInstance, true));

            // if(instantiate)
            // {
            // 	selectedObjectPrefab = PrefabUtility.InstantiatePrefab(obj);

            // }
            // else
            // {
            // 	StaticCoroutine.Start(SelectionCoroutine (obj, selectedObjectPrefab, false));
            // }

            if (SceneView.lastActiveSceneView != null)
                SceneView.lastActiveSceneView.FrameSelected();
        }
        else
        {
            Debug.LogError("Failed to load prefab at " + path);
        }
    }

    Object scenePrefabInstance = null;

    IEnumerator SelectionCoroutine(Object firstSelection, Object secondSelection, bool alsoInScene = true)
    {
        Selection.activeObject = firstSelection;

        yield return null;

        if (alsoInScene)
        {
            Selection.activeObject = secondSelection;

            if (SceneView.lastActiveSceneView != null)
                SceneView.lastActiveSceneView.FrameSelected();
        }
    }

    void DefaultView()
    {
        serializedObject.Update();

        if (editorStyles == null)
            SetStyles();


        EditorGUILayout.LabelField("Actions", EditorStyles.boldLabel);

        if (GUILayout.Button("Open Prefab", editorStyles.menuButton))
        {
            string path = AssetDatabase.GetAssetPath(serializedObject.targetObject);

            path = path.Replace(serializedObject.targetObject.name, "AnchorForAR.prefab");
            path = path.Replace(".asset", "");
            // Debug.Log(path);
            // string prefabPath = experienceFolder + "/AnchorForAR.prefab";
            Object obj = AssetDatabase.LoadAssetAtPath(path, typeof(Object));
            AssetDatabase.OpenAsset(obj);

        }

        if (GUILayout.Button("Put Prefab Into Scene", editorStyles.menuButton))
        {
            PutPrefabIntoScene();
        }

        EditorGUILayout.LabelField("NTAR Settings", EditorStyles.boldLabel);
        EditorGUILayout.PropertyField(orientation);
        EditorGUILayout.PropertyField(arType, new GUIContent("AR Mode:"));

        showModeControls = EditorGUILayout.Foldout(showModeControls, arType.enumDisplayNames[arType.enumValueIndex], ARitizer.Instance.ui.editorStyles.boldFoldout);
        if (showModeControls)
        {
            EditorGUI.indentLevel++;

            if (arType.enumValueIndex == 0)//SLAM
            {
                // EditorGUILayout.LabelField("Nothing to configure");
                // EditorGUILayout.PropertyField(slamSurfaces, new GUIContent ("Tracked Surfaces"));
                EditorGUILayout.PropertyField(navigationGuidanceTarget, new GUIContent("Navigation Guidance Target (Mesh Renderer)"));
            }
            else if (arType.enumValueIndex == 1)//image tracking
            {
                EditorGUILayout.PropertyField(imageTargetSlug);
                EditorGUILayout.PropertyField(trackableSettings);
                EditorGUILayout.PrefixLabel("Optional:");
                EditorGUILayout.PropertyField(imageTargetGuide);

            }
            // else if(arType.enumValueIndex == 2)//face tracking
            // {
            // 	EditorGUILayout.PropertyField(faceMesh);
            // }
            else if (arType.enumValueIndex == 2)//object tracking
            {
                EditorGUILayout.PropertyField(wtoFile);
                EditorGUILayout.PropertyField(objectTarget);
                EditorGUILayout.PropertyField(hideOnTrackingLost);

            }

            EditorGUI.indentLevel--;
        }

        EditorGUILayout.PropertyField(previewBlacklist, true);
        EditorGUILayout.PropertyField(forcedDependencies, true);

        EditorGUILayout.Space();
        EditorGUILayout.LabelField("Modules", EditorStyles.boldLabel);
        ShowExpandedList(modules);

        serializedObject.ApplyModifiedProperties();
    }

    System.Type moduleToAdd;
    Vector3 modulesScroll;
    Vector3 addModulesScroll;
    void AddingModulesView()
    {
        EditorGUILayout.LabelField("Add New Module", EditorStyles.boldLabel);


        if (moduleToAdd == null)
        {
            addModulesScroll = EditorGUILayout.BeginScrollView(addModulesScroll);
            for (int i = 0; i < moduleList.Count; i++)
            {
                string niceName = ObjectNames.NicifyVariableName(moduleList[i].ToString());

                if (GUILayout.Button(niceName))
                {
                    newModuleInput = modules.arraySize + " New " + moduleList[i].ToString();
                    moduleToAdd = moduleList[i];

                }
            }
            EditorGUILayout.EndScrollView();
        }
        else
        {
            GUI.SetNextControlName("NewModuleName");
            newModuleInput = EditorGUILayout.TextField("New Module Name", newModuleInput);
            if (GUILayout.Button("Add"))
            {
                AddModule(newModuleInput, moduleToAdd);
                moduleToAdd = null;
                newModuleInput = "";
                GUI.FocusControl(null);
            }
            else
            {
                GUI.FocusControl("NewModuleName");
            }




        }


        EditorGUILayout.Space();
        if (GUILayout.Button("Cancel", EditorStyles.miniButton))
        {
            currentMenuState = DataMenuState.defaultView;
            moduleToAdd = null;
            newModuleInput = "";
        }
    }

    // string defaultModuleName

    string newModuleInput;

    void AddModule(string newModuleName, System.Type moduleType)
    {
        modules.arraySize++;

        // var instance = System.Activator.CreateInstance(moduleType) as UnityEngine.Object;
        var instance = ScriptableObject.CreateInstance(moduleType);

        string path = AssetDatabase.GetAssetPath(serializedObject.targetObject);

        path = path.Replace(serializedObject.targetObject.name, "_Modules/" + newModuleName);

        FileManager.CreateDirectoryIfNeeded(path);

        AssetDatabase.CreateAsset(instance, path);

        int lastIndex = modules.arraySize - 1;

        modules.GetArrayElementAtIndex(lastIndex).objectReferenceValue = instance;

        serializedObject.ApplyModifiedProperties();

        currentMenuState = DataMenuState.defaultView;

        modulesScroll = Vector3.up * Mathf.Infinity;
        // modules.InsertArrayElementAtIndex()
    }

    // SerializedProperty moduleBeingInspected;


    ExperienceModule moduleBeingInspected;

    // UnityEditor.Editor editorForModuleBeingInspected;



    void ShowExpandedList(SerializedProperty list)
    {

        // EditorGUILayout.PropertyField(list, new GUIContent (""), true);
        // EditorGUILayout.LabelField(list.arraySize.ToString());
        // EditorGUILayout.LabelField(modulesScroll.ToString());

        modulesScroll = EditorGUILayout.BeginScrollView(modulesScroll);
        for (int i = 0; i < list.arraySize; i++)
        {
            SerializedProperty itemProperty = list.GetArrayElementAtIndex(i);
            if (itemProperty == null || itemProperty.objectReferenceValue == null)
                continue;

            EditorGUILayout.BeginHorizontal();
            // EditorGUILayout.PropertyField(list.GetArrayElementAtIndex(i), GUIContent.none);
            // GUILayout.Button(moveButtonContent, EditorStyles.miniButtonLeft, miniButtonWidth);
            // GUILayout.Button(duplicateButtonContent, EditorStyles.miniButtonMid, miniButtonWidth);

            if (GUILayout.Button(itemProperty.objectReferenceValue.ToString(), EditorStyles.miniButton))
            {


                int instanceId = itemProperty.objectReferenceInstanceIDValue;
                string path = AssetDatabase.GetAssetPath(instanceId);

                ARitizer.Instance.currentExperienceMenu = ARitizer.ExperienceMenu.editModule;
                EditorPrefs.SetString("EditModulePath", path);
                EditorPrefs.SetString("EditModule", itemProperty.objectReferenceValue.ToString());
                // Debug.Log("path: " + path);
                // string modulePath = experiencePath + "/Data.asset";
                // Object dataObj = AssetDatabase.LoadAssetAtPath(path, typeof(Object));
                // editorForModuleBeingInspected = Editor.CreateEditor(dataObj, typeof(ExperienceModule));



                // moduleBeingInspected = itemProperty;
                // currentMenuState = DataMenuState.inspectingModule;
            }
            GUI.color = Color.red;
            if (GUILayout.Button(deleteButtonContent, EditorStyles.miniButton, miniButtonWidth))
            {
                SerializedProperty itemToDelete = list.GetArrayElementAtIndex(i);
                int instanceId = itemToDelete.objectReferenceInstanceIDValue;
                string path = AssetDatabase.GetAssetPath(instanceId);

                Debug.Log("Deleting " + path);

                AssetDatabase.DeleteAsset(path);

                int oldSize = list.arraySize;
                list.DeleteArrayElementAtIndex(i);
                if (list.arraySize == oldSize)
                {
                    list.DeleteArrayElementAtIndex(i);
                }
            }
            GUI.color = defColor;
            EditorGUILayout.EndHorizontal();
        }
        EditorGUILayout.EndScrollView();
        GUI.color = Color.green;
        if (GUILayout.Button(addButtonContent, EditorStyles.miniButton))
        {
            currentMenuState = DataMenuState.addingModule;
            // list.arraySize += 1;
        }
        GUI.color = defColor;
    }

    //styling
    private static GUILayoutOption miniButtonWidth = GUILayout.Width(30f);
    private static GUIContent
        addButtonContent = new GUIContent("+", "new"),
        deleteButtonContent = new GUIContent(" -", "delete");
}

[CustomPropertyDrawer(typeof(ExperienceInfo.TrackableSettings))]
public class TrackableSettingsPropertyDrawer : PropertyDrawer
{
    // int fieldCount = 5;
    string[] fields = {
        "Warn user when too far away",
        "distanceGuidance",
        "distanceThreshold",
        "distanceWarnDelay",
        "distanceWarnMessage",
        "",
        "Warn user when target seems to be off screen",
        "offScreenGuidance",
        "offScreenWarnDelay",
        "offScreenWarnMessage",
    };

    bool isFolded = false;

    float defaultHeight = 16f;
    // Draw the property inside the given rect
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // Using BeginProperty / EndProperty on the parent property means that
        // prefab override logic works on the entire property.

        EditorGUI.BeginProperty(position, label, property);

        Rect foldoutPosition = position;
        foldoutPosition.height = defaultHeight;

        property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, "Trackable Settings");





        // Draw label
        // position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);


        if (property.isExpanded)
        {
            // Don't make child fields be indented
            var indent = EditorGUI.indentLevel;
            EditorGUI.indentLevel = indent + 1;

            // Draw each field
            for (int i = 0; i < fields.Length; i++)
            {
                var fieldRect = new Rect(position.x, position.y + (i * defaultHeight) + defaultHeight, position.width, defaultHeight);
                SerializedProperty subProperty = property.FindPropertyRelative(fields[i]);
                if (subProperty == null)
                {
                    EditorGUI.LabelField(fieldRect, fields[i], EditorStyles.boldLabel);
                }
                else
                {
                    EditorGUI.PropertyField(fieldRect, subProperty);
                }

            }

            // Set indent back to what it was
            EditorGUI.indentLevel = indent;
        }


        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {

        if (!property.isExpanded)
            return base.GetPropertyHeight(property, label);

        float currentHeight = base.GetPropertyHeight(property, label);
        return (currentHeight * (float)fields.Length) + defaultHeight;
    }
}