//============= Copyright (c) Ludic GmbH, All rights reserved. ==============
//
// Purpose: Part of the My Behaviour Tree Controller Code
//
//=============================================================================


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
[CustomEditor(typeof(ComponentController))]
public class ComponentControllerInspector : Editor {
    public override void OnInspectorGUI() {
        ComponentController myTarget = (ComponentController)target;
        if (myTarget.handlers == null || myTarget.handlers.Length == 0) {
            Debug.Log($"myTarget.handlers is null or empty for {myTarget.name}: trigged list update");
            UpdateObject(myTarget);
        }

        if (myTarget.handlers.Any(h => (h == null))) {
            Debug.Log($"myTarget.handlers has null entry {myTarget.name}: trigged list update");
            UpdateObject(myTarget);
        }

        // GUILayout.Toggle(myTarget.CheckHandlersModified(), "CheckHandlersModified");

        if (myTarget.CheckHandlersModified()) {
            Debug.Log("CheckHandlersModified: trigged list update");
            UpdateObject(myTarget);
        }

        if (GUILayout.Button("UpdateObject")) {
            UpdateObject(myTarget);
        }

        DrawDefaultInspector();

        foreach (ComponentHandler compHand in myTarget.handlers) {
            ComponentHandlerInspector e = Editor.CreateEditor(compHand) as ComponentHandlerInspector;
            if (e != null) {
                ComponentHandler theTarget = (ComponentHandler)e.target;
                GUILayout.BeginVertical(EditorStyles.helpBox);
                
                // // --------
                // if (theTarget.helpText != null) {
                //     theTarget.showHelpText = EditorGUILayout.ToggleLeft("Show Info", theTarget.showHelpText);
                // }
                // // EditorGUILayout.Space();
                // // EditorGUILayout.Space();
                // // EditorGUILayout.EndHorizontal();
                // EditorGUILayout.BeginHorizontal();
                // if (theTarget.showHelpText) {
                //     if (theTarget.helpText != null) {
                //         // string[][] helpTextSplit = theTarget.helpText;
                //         for (int i=0; i<theTarget.helpText.Length; i++) {
                //             if (GUILayout.Button(new GUIContent($"{theTarget.helpText[i][0]} Command", theTarget.helpText[i][1]), GUILayout.MaxWidth(140))) {
                //                 EditorGUIUtility.systemCopyBuffer = theTarget.helpText[i][2];
                //             }
                //             if (((i+1)%3)==0) {
                //                 EditorGUILayout.EndHorizontal();
                //                 EditorGUILayout.BeginHorizontal();
                //             }
                //         }
                //     }
                // }
                // EditorGUILayout.EndHorizontal();
                // // --------

                e.OnCustomInspectorGUI();
                GUILayout.EndVertical();
            }
        }
    }

    public void UpdateObject (ComponentController myTarget) {
        myTarget.UpdateObject();

        BTC.Instance.ClearObjects();
        BTC.Instance.UpdateObjects();

        EditorUtility.SetDirty(myTarget);
        EditorSceneManager.MarkSceneDirty(myTarget.gameObject.scene);
    }
}
#endif

public class ComponentController : MonoBehaviour {
    [HideInInspector]
    public ComponentHandler[] handlers;

    [HideInInspector]
    public string roomId;
    public string uniqueId;

    public string objectName {
        get {
            return name;
        }
        set {
            name = value;
        }
    }

    public virtual void Awake () {
        UpdateObject();
    }

    public ComponentHandler[] GetCurrentHandlers () {
        List<ComponentHandler> handlersList = GetComponents<ComponentHandler>().ToList();
        // Debug.Log("GetCurrentHandlers "+string.Join("/", handlersList.Select(e => e.TypeLabel())) + " old " + string.Join("/", handlers.Select(e => e.TypeLabel())));
        return handlersList.OrderBy(o => o.TypeLabel()).ToArray();
    }

    public bool CheckHandlersModified () {
        ComponentHandler[] currentHandlers = GetCurrentHandlers();
        bool isModified = (HandlersAsTypeLabelString(handlers) != HandlersAsTypeLabelString(currentHandlers));
        // Debug.Log("CheckHandlersModified: currentHandlers = "+string.Join("/", currentHandlers.Select(e => e.TypeLabel())) + " ; handlers = " + string.Join("/", handlers.Select(e => e.TypeLabel())) + " isModified " + isModified);
        return isModified;
    }

    // the combination of all types
    public string HandlersAsTypeLabelString (ComponentHandler[] h) {
        return string.Join("/", h.Select(e => e.TypeLabel()));
    }

    // the combination of all types
    public string ContentLabelAsString (List<string> labels) {
        return string.Join("_", labels);
    }

    public string SanitizeString (string unicodeString) {
        //// Create two different encodings.
        //Encoding ascii = Encoding.ASCII;
        //Encoding unicode = Encoding.Unicode;

        //// Convert the string into a byte array.
        //byte[] unicodeBytes = unicode.GetBytes(unicodeString);

        //// Perform the conversion from one encoding to the other.
        //byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);

        //// Convert the new byte[] into a char[] and then into a string.
        //char[] asciiChars = new char[ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
        //ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);
        //string asciiString = new string(asciiChars);

        //return asciiString.Replace("_", "").Replace("/", "").Replace("-", "").Replace("&", "").Replace(" ", "").Replace("?", "");
        return Regex.Replace(unicodeString, "[^A-Za-z0-9]", "");
    }

    public void UpdateObject () {
        UpdateRoomId();

        // the first content label
        handlers = GetCurrentHandlers();
        string handlersLabel = HandlersAsTypeLabelString(handlers);

        List<string> contentLabels = new List<string>();
        for (int i=0; i<handlers.Length; i++) {
            string lbl = handlers[i].ContentLabel();
            lbl = SanitizeString(lbl);
            lbl = lbl.Substring(0,Mathf.Min(lbl.Length, 18));
            if (!string.IsNullOrEmpty(lbl)) {
                contentLabels.Add( lbl );
            }
        }
        if (!string.IsNullOrEmpty(uniqueId)) {
            contentLabels.Add(uniqueId);
        }
        string contentLabel = ContentLabelAsString(contentLabels);

        // Debug.Log($"pre:      {pre}");
        // Debug.Log($"roomId:   {roomId}");
        // Debug.Log($"id:       {id}");
        // Debug.Log($"uniqueId: {uniqueId}");

        List<string> gameObjectNameComponents = new List<string>();
        if (!string.IsNullOrEmpty(handlersLabel)) {
            gameObjectNameComponents.Add(handlersLabel);
        }
        if (!string.IsNullOrEmpty(roomId)) {
            gameObjectNameComponents.Add(roomId);
        }
        if (!string.IsNullOrEmpty(contentLabel)) {
            gameObjectNameComponents.Add(contentLabel);
        }
        string newName = string.Join(".", gameObjectNameComponents);
        if (newName != gameObject.name) {
            Debug.LogWarning($"BTC renamed {gameObject.name} to {newName}\n\n\n\n");
            gameObject.name = newName;
        }

        // BTC.Instance.ClearObjects();
        // BTC.Instance.UpdateObjects();
    }

    protected void UpdateRoomId() {
        string[] rootName = transform.root.name.Split('.');
        if (rootName.Length > 0) {
            roomId = SanitizeString(rootName[0]);
        }
        else {
            roomId = "undefined";
        }

        if (transform.parent == null) {
            roomId = "";
        }
    }
}