using UnityEngine;
using UnityEditor;
using XenseAR;
using System.Collections.Generic;

[InitializeOnLoad]
public class CustomAssetbundleHierarchy : MonoBehaviour
{
    bool previousSavedState = false;
    bool previousNewState = false;
    static Dictionary<Color32, Texture2D> textureCache = new Dictionary<Color32, Texture2D>();

    static CustomAssetbundleHierarchy()
    {
        EditorApplication.hierarchyWindowItemOnGUI += HandleHierarchyWindowItemOnGUI;
    }

    private static void HandleHierarchyWindowItemOnGUI(int instanceID, Rect selectionRect)
    {
        var obj = EditorUtility.InstanceIDToObject(instanceID);
        if (obj != null && (obj is GameObject))
        {
            AssetbundleAnchorEditor assetBundleAnchorEditor = (obj as GameObject).GetComponent<AssetbundleAnchorEditor>();
            GltfAnchorEditor gltfAnchorEditor = (obj as GameObject).GetComponent<GltfAnchorEditor>();
            ImageAnchorEditor imageAnchorEditor = (obj as GameObject).GetComponent<ImageAnchorEditor>();

            AnchoringDetails anchoringDetails = (obj as GameObject).GetComponent<AnchoringDetails>();

            if (assetBundleAnchorEditor != null)
            {
                Rect iconRect = new Rect(selectionRect.position, Vector2.one * selectionRect.size.y);
                Rect objNameRect = new Rect(
                    selectionRect.position + new Vector2(iconRect.width + 2, 0),
                    selectionRect.size - new Vector2(iconRect.width + 2, 0)
                );
                
                if(anchoringDetails != null)
                {
                    UpdateState(obj.name,
                        objNameRect,
                        assetBundleAnchorEditor.isSaved,
                        assetBundleAnchorEditor.isNew,
                        assetBundleAnchorEditor.isEdited,
                        assetBundleAnchorEditor.isError,
                        !string.IsNullOrEmpty(anchoringDetails.sizeStr) ? anchoringDetails.sizeStr : "NaN",
                        anchoringDetails.dataSizeBackgroundColor);
                } else
                {
                    UpdateState(obj.name,
                        objNameRect,
                        assetBundleAnchorEditor.isSaved,
                        assetBundleAnchorEditor.isNew,
                        assetBundleAnchorEditor.isEdited,
                        assetBundleAnchorEditor.isError,
                        "NaN",
                        Color.white);
                }
                
            }
            
            if(gltfAnchorEditor != null)
            {
                Rect iconRect = new Rect(selectionRect.position, Vector2.one * selectionRect.size.y);
                Rect objNameRect = new Rect(
                    selectionRect.position + new Vector2(iconRect.width + 2, 0),
                    selectionRect.size - new Vector2(iconRect.width + 2, 0)
                );

                if (anchoringDetails != null)
                {
                    UpdateState(obj.name,
                        objNameRect,
                        gltfAnchorEditor.isSaved,
                        gltfAnchorEditor.isNew,
                        gltfAnchorEditor.isEdited,
                        gltfAnchorEditor.isError,
                        !string.IsNullOrEmpty(anchoringDetails.sizeStr) ? anchoringDetails.sizeStr : "NaN",
                        anchoringDetails.dataSizeBackgroundColor);
                } else
                {
                    UpdateState(obj.name,
                        objNameRect,
                        gltfAnchorEditor.isSaved,
                        gltfAnchorEditor.isNew,
                        gltfAnchorEditor.isEdited,
                        gltfAnchorEditor.isError,
                        "NaN",
                        Color.white);
                }
                    
            }

            if (imageAnchorEditor != null)
            {
                Rect iconRect = new Rect(selectionRect.position, Vector2.one * selectionRect.size.y);
                Rect objNameRect = new Rect(
                    selectionRect.position + new Vector2(iconRect.width + 2, 0),
                    selectionRect.size - new Vector2(iconRect.width + 2, 0)
                );

                if (anchoringDetails != null)
                {
                    UpdateState(obj.name,
                        objNameRect,
                        imageAnchorEditor.isSaved,
                        imageAnchorEditor.isNew,
                        imageAnchorEditor.isEdited,
                        imageAnchorEditor.isError,
                        !string.IsNullOrEmpty(anchoringDetails.sizeStr) ? anchoringDetails.sizeStr : "NaN",
                        anchoringDetails.dataSizeBackgroundColor);
                } else
                {
                    UpdateState(obj.name,
                        objNameRect,
                        imageAnchorEditor.isSaved,
                        imageAnchorEditor.isNew,
                        imageAnchorEditor.isEdited,
                        imageAnchorEditor.isError,
                        "NaN",
                        Color.white);
                }
                    
            }
        }
    }

    static void UpdateState(string name, Rect objNameRect, bool isSaved, bool isNew, bool isEdited, bool isError, string dataSize, Color dataSizeColor)
    {
        Color32 objNameColor = new Color32(205, 205, 205, 255);

        // Draw object name
        GUIStyle nameStyle = new GUIStyle() { normal = new GUIStyleState() { textColor = objNameColor } };
        GUI.Label(objNameRect, name, nameStyle);

        float rightOffset = 0f;

        if (dataSize != "NaN") DrawLabelAtEnd(ref rightOffset, objNameRect, dataSize, dataSizeColor, Color.black);
        if (isSaved) DrawLabelAtEnd(ref rightOffset, objNameRect, isNew ? "New" : "Saved", isNew ? Defines.LabelBackgroundColor.NewColor : Defines.LabelBackgroundColor.SavedColor, Color.white);
        if (isEdited) DrawLabelAtEnd(ref rightOffset, objNameRect, "Edited", Defines.LabelBackgroundColor.EditedColor, Color.white);
        if (isError) DrawLabelAtEnd(ref rightOffset, objNameRect, "Error", Defines.LabelBackgroundColor.ErrorColor, Color.white);
    }

    static void DrawLabelAtEnd(ref float rightOffset, Rect selectionRect, string text, Color32 bgColor, Color textColor)
    {
        if (string.IsNullOrEmpty(text)) return;

        float labelWidth = 50f;
        float labelHeight = selectionRect.height - 2f;

        Rect labelRect = new Rect(
            selectionRect.xMax - labelWidth - rightOffset - 2f,
            selectionRect.y + 1f,
            labelWidth,
            labelHeight
        );

        GUIStyle style = new GUIStyle(GUI.skin.label)
        {
            alignment = TextAnchor.MiddleCenter,
            normal = new GUIStyleState()
            {
                textColor = textColor,
                background = GetTexture(bgColor)
            }
        };

        GUI.Label(labelRect, text, style);

        rightOffset += labelWidth + 2f;
    }

    static Texture2D GetTexture(Color32 color)
    {
        if (textureCache.TryGetValue(color, out var tex))
        {
            if (tex != null)
                return tex;       // cached and valid

            // Cached key exists but texture was destroyed → recreate it
            tex = CreateTexture(color);
            textureCache[color] = tex;
            return tex;
        }

        // Not in cache at all → create new
        tex = CreateTexture(color);
        textureCache[color] = tex;
        return tex;
    }

    static Texture2D CreateTexture(Color32 color)
    {
        var tex = new Texture2D(1, 1);
        tex.SetPixel(0, 0, color);
        tex.Apply();
        return tex;
    }

}
