using System;
using System.Collections.Generic;
using System.Threading;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;

namespace SimplygonUI
{
    public static class Clipboard
    {
        public static void SetText(string text)
        {
            GUIUtility.systemCopyBuffer = text;
        }
    }

    public class ThreadDispatcher
    {
        private readonly Thread TargetThread = null;
        private readonly object TargetThreadLock = new object();
        private readonly Queue<Action> TargetThreadQueue = new Queue<Action>();

        public ThreadDispatcher()
        {
            TargetThread = Thread.CurrentThread;
        }

        public bool IsOnSameThread()
        {
            return TargetThread != null ? Thread.CurrentThread == TargetThread : false;
        }

        public void InvokeAsyncQueued(Action action)
        {
            lock (TargetThreadLock)
            {
                TargetThreadQueue.Enqueue(action);
            }
        }

        public void InvokeAsync(Action action)
        {
            if (IsOnSameThread())
            {
                action();
            }
            else
            {
                lock (TargetThreadLock)
                {
                    TargetThreadQueue.Enqueue(action);
                }
            }
        }

        public void Invoke(Action action)
        {
            bool bActionCompleted = false;

            InvokeAsync(() =>
            {
                action();
                bActionCompleted = true;
            });

            while (!bActionCompleted)
            {
                Thread.Sleep(10);
            }
        }

        public void Update()
        {
            lock (TargetThreadLock)
            {
                while (TargetThreadQueue.Count > 0)
                {
                    TargetThreadQueue.Dequeue()();
                }
            }
        }
    }

    public interface ISimplygonIntegrationCallback
    {
        bool IsGameObjectsSelected();
        List<KeyValuePair<string, ESimplygonMaterialCaster>> GetMaterialChannelsFromSelection();
    }
    public interface ISimplygonPipelineDropdownCallback
    {
        bool IsLODComponentDropdownEnabled();
        bool IsCascadedLODComponentDropdownEnabled();
        bool IsMaterialCasterComponentDropdownEnabled();
        bool IsPipelineMenuEnabled();
        bool IsRemoveButtonEnabled();
        void NewLODComponentSelected(AdvancedDropdownItem item);
        void NewCascadedLODComponentSelected(SimplygonPipeline pipeline);
        void NewMaterialCasterSelected(SimplygonMaterialCaster materialCaster);
        void RemoveAllMaterialCasters();
        bool IsGameObjectsSelected();
    }

    public class SimplygonTreeViewHeader : MultiColumnHeader
    {
        public SimplygonTreeViewHeader(MultiColumnHeaderState state) : base(state)
        {
        }
        public void ToggleEdit()
        {
            ToggleVisibility(1);
            ResizeToFit();
        }
    }
    public class SimplygonTreeView : TreeView
    {
        private SimplygonPipeline Pipeline { get; set; }
        public bool EditorUI { get; protected set; }
        public bool RenderMaterialCasters { get; set; }
        public SimplygonMaterialCaster PendingMaterialCasterRemoval { get; set; }
        private SimplygonTreeViewHeader customMultiColumnHeader { get; set; }
        public SimplygonTreeView(TreeViewState treeViewState, SimplygonTreeViewHeader multiColumnHeader) : base(treeViewState, multiColumnHeader)
        {
            customMultiColumnHeader = multiColumnHeader;
            useScrollView = false;
            EditorUI = true;
        }
        public void ToggleEdit()
        {
            EditorUI = !EditorUI;
            customMultiColumnHeader.ToggleEdit();
        }
        public void Update(SimplygonPipeline pipeline, bool force = false)
        {
            if (pipeline != null && (Pipeline != pipeline || force))
            {
                Pipeline = pipeline;
                Reload();
            }
        }
        protected override TreeViewItem BuildRoot()
        {
            var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" };
            if (Pipeline != null)
            {
                if (RenderMaterialCasters)
                {
                    foreach (var caster in Pipeline.MaterialCasters)
                    {
                        caster.CreateUI(this, root, EditorUI);
                    }
                }
                else
                {
                    Pipeline.CreateUI(this, root, EditorUI);
                }
                if (root.hasChildren) { SetupDepthsFromParentsAndChildren(root); }
            }
            return root;
        }
        protected void OnAllVisible(object item)
        {
            if (item is SimplygonTreeViewItem)
            {
                ((SimplygonTreeViewItem)item).SetVisible(true, true);
            }
        }
        protected void OnAllHidden(object item)
        {
            if (item is SimplygonTreeViewItem)
            {
                ((SimplygonTreeViewItem)item).SetVisible(false, true);
            }
        }
        protected void OnSetDefaultValue(object item)
        {
            if (item is SimplygonSettingsProperty)
            {
                ((SimplygonSettingsProperty)item).Reset();
            }
        }
        protected void OnSetAllDefaultValues(object item)
        {
            if (item is SimplygonSettings)
            {
                ((SimplygonSettings)item).Reset();
            }
            else if (item is SimplygonSettingsProperty)
            {
                ((SimplygonSettingsProperty)item).Reset();
            }
        }
        protected override void ContextClickedItem(int id)
        {
            var treeViewItem = FindItem(id, rootItem);
            if (treeViewItem is SimplygonTreeViewItem)
            {
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent("Set all default values"), false, OnSetAllDefaultValues, treeViewItem);
                if (EditorUI)
                {
                    menu.AddItem(new GUIContent("All visible"), false, OnAllVisible, treeViewItem);
                    menu.AddItem(new GUIContent("All hidden"), false, OnAllHidden, treeViewItem);
                }
                menu.ShowAsContext();
            }
            else if (treeViewItem is SimplygonSettingsProperty)
            {
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent("Set default value"), false, OnSetDefaultValue, treeViewItem);
                menu.ShowAsContext();
            }
        }
        protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
        {
            return base.BuildRows(root);
        }
        protected override void RowGUI(RowGUIArgs args)
        {
            if (args.item is SimplygonSettingsProperty)
            {
                var settingsProperty = args.item as SimplygonSettingsProperty;
                for (int i = 0; i < args.GetNumVisibleColumns(); ++i)
                {
                    if (i == 0)
                    {
                        Rect cellRect = args.GetCellRect(i);
                        cellRect.x += GetContentIndent(args.item);
                        cellRect.width -= GetContentIndent(args.item);
                        if (EditorUI)
                        {
                            var currentColor = GUI.contentColor;
                            if (!settingsProperty.Visible)
                            {
                                GUI.contentColor = new Color(currentColor.r, currentColor.g, currentColor.b, 0.5f);
                            }
                            settingsProperty.ShowUI(cellRect);
                            GUI.contentColor = currentColor;
                        }
                        else
                        {
                            if (settingsProperty.Visible)
                            {
                                settingsProperty.ShowUI(cellRect);
                            }
                        }
                    }
                    else if (i == 1)
                    {
                        if (EditorUI)
                        {
                            Rect cellRect = args.GetCellRect(i);
                            settingsProperty.Visible = EditorGUI.Toggle(cellRect, settingsProperty.Visible);
                        }
                    }
                }
            }
            else if (args.item is SimplygonMaterialCaster)
            {
                var materialCaster = args.item as SimplygonMaterialCaster;
                for (int i = 0; i < args.GetNumVisibleColumns(); ++i)
                {
                    if (i == 0)
                    {
                        Rect cellRect = args.GetCellRect(i);
                        cellRect.x += GetContentIndent(args.item);
                        GUI.Label(new Rect(cellRect.x, cellRect.y, cellRect.width, cellRect.height), ((TreeViewItem)materialCaster).displayName);
                        if (GUI.Button(new Rect(cellRect.width - 25, cellRect.y, 25, 25), EditorGUIUtility.IconContent("TreeEditor.Trash", "")))
                        {
                            PendingMaterialCasterRemoval = materialCaster;
                        }
                    }
                }
            }
            else
            {
                base.RowGUI(args);
            }
        }
        protected override float GetCustomRowHeight(int row, TreeViewItem item)
        {
            if (item is SimplygonMaterialCaster)
            {
                return 25.0f;
            }
            return base.GetCustomRowHeight(row, item);
        }
    }
}
