// Copyright (c) Microsoft Corporation. 
// Licensed under the MIT license. 

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
using UnityEditor.IMGUI.Controls;
using Newtonsoft.Json.Linq;
using Simplygon.Unity.EditorPlugin;

namespace SimplygonUI
{
    public partial class SimplygonPipeline : ISimplygonPipelineDropdownCallback
    {
        public bool PendingPipelineRemoval { get; protected set; }
        public ISimplygonPipelineDropdownCallback ParentCallback { get; private set; }
        private TreeViewState treeViewState;
        private TreeViewState materialCasterTreeViewState;
        private SimplygonTreeViewHeader multiColumnHeader;
        private SimplygonTreeView treeView;
        private SimplygonTreeViewHeader materialCasterMultiColumnHeader;
        private SimplygonTreeView materialCasterTreeView;
        private Rect addLODComponentRect;
        public ISimplygonIntegrationCallback ParentIntegration { get; set; }
        private static int LODColorIndex { get; set; }
        private Color LODColor { get; set; }
        private SimplygonMaterialCasterDropdownFactory MaterialCastersDropdownFactory;
        private SimplygonCascadedLODDropdownFactory CascadedLODDropdownFactory;

        public void InitializeUI()
        {
            LODColor = SimplygonUtils.GetLODColor();
            MaterialCastersDropdownFactory = new SimplygonMaterialCasterDropdownFactory(this);
            CascadedLODDropdownFactory = new SimplygonCascadedLODDropdownFactory(this);
        }

        public void SetParentCallback(ISimplygonPipelineDropdownCallback parentCallback)
        {
            ParentCallback = parentCallback;
            foreach (var cascadedPipeline in CascadedPipelines)
            {
                cascadedPipeline.SetParentCallback(parentCallback);
            }
        }
        public void OnUIEnable(ISimplygonIntegrationCallback parentIntegration)
        {
            ParentIntegration = parentIntegration;
            if (treeViewState == null)
            {
                treeViewState = new TreeViewState();
            }
            if (materialCasterTreeViewState == null)
            {
                materialCasterTreeViewState = new TreeViewState();
            }
            if (multiColumnHeader == null)
            {
                var column1 = new MultiColumnHeaderState.Column() { headerContent = new GUIContent(PipelineName, ""), headerTextAlignment = TextAlignment.Left, autoResize = true, minWidth = 400 };
                var column2 = new MultiColumnHeaderState.Column() { headerContent = EditorGUIUtility.IconContent("ViewToolOrbit", ""), headerTextAlignment = TextAlignment.Left, autoResize = true, maxWidth = 25 };
                var columns = new MultiColumnHeaderState.Column[] { column1, column2 };
                multiColumnHeader = new SimplygonTreeViewHeader(new MultiColumnHeaderState(columns));
                multiColumnHeader.ResizeToFit();
            }
            if (materialCasterMultiColumnHeader == null)
            {
                var column1 = new MultiColumnHeaderState.Column() { headerContent = new GUIContent("Material Casters", ""), headerTextAlignment = TextAlignment.Left, autoResize = true, minWidth = 400 };
                var column2 = new MultiColumnHeaderState.Column() { headerContent = EditorGUIUtility.IconContent("ViewToolOrbit", ""), headerTextAlignment = TextAlignment.Left, autoResize = true, maxWidth = 25 };
                var columns = new MultiColumnHeaderState.Column[] { column1, column2 };
                materialCasterMultiColumnHeader = new SimplygonTreeViewHeader(new MultiColumnHeaderState(columns));
                materialCasterMultiColumnHeader.ResizeToFit();
            }
            if (treeView == null)
            {
                treeView = new SimplygonTreeView(treeViewState, multiColumnHeader);
                treeView.ToggleEdit();
            }
            if (materialCasterTreeView == null)
            {
                materialCasterTreeView = new SimplygonTreeView(materialCasterTreeViewState, materialCasterMultiColumnHeader);
                materialCasterTreeView.RenderMaterialCasters = true;
                materialCasterTreeView.ToggleEdit();
            }
            foreach (var cascadedPipeline in CascadedPipelines)
            {
                cascadedPipeline.OnUIEnable(ParentIntegration);
            }
        }

        public bool IsLODComponentDropdownEnabled()
        {
            return true;
        }
        public bool IsCascadedLODComponentDropdownEnabled()
        {
            return true;
        }
        public bool IsMaterialCasterComponentDropdownEnabled()
        {
            return true;
        }
        public bool IsPipelineMenuEnabled()
        {
            return false;
        }
        public bool IsRemoveButtonEnabled()
        {
            return true;
        }

        public bool IsGameObjectsSelected()
        {
            return ParentCallback.IsGameObjectsSelected();
        }
        public void NewLODComponentSelected(AdvancedDropdownItem item)
        {
        }
        public void NewMaterialCasterSelected(SimplygonMaterialCaster materialCaster)
        {
            if (materialCaster == null)
            {
                UpdateAutomaticMaterialCasters();
            }
            else
            {
                AddMaterialCaster(materialCaster.DeepCopy(PipelineType));
                materialCasterTreeView.Update(this, true);
            }
        }
        public void RemoveAllMaterialCasters()
        {
            MaterialCasters.Clear();
            materialCasterTreeView.Update(this, true);
        }

        public void NewCascadedLODComponentSelected(SimplygonPipeline pipeline)
        {
            if (!string.IsNullOrEmpty(pipeline.FilePath))
            {
                var newPipeline = new SimplygonPipeline(pipeline.FilePath, JObject.Parse(System.IO.File.ReadAllText(pipeline.FilePath)));

                if (newPipeline != null)
                {
                    if (newPipeline.PipelineType == ESimplygonPipeline.Passthrough)
                    {
                        foreach (var cascadedPipeline in newPipeline.CascadedPipelines)
                        {
                            cascadedPipeline.InitializeUI();
                            cascadedPipeline.SetParentCallback(this.ParentCallback);
                            cascadedPipeline.OnUIEnable(this.ParentIntegration);
                            AddCascadedPipeline(cascadedPipeline);
                        }
                    }
                    else
                    {
                        newPipeline.InitializeUI();
                        newPipeline.SetParentCallback(this.ParentCallback);
                        newPipeline.OnUIEnable(this.ParentIntegration);
                        AddCascadedPipeline(newPipeline);
                    }
                }
            }
            else
            {
                var newPipeline = pipeline.DeepCopy();
                newPipeline.InitializeUI();
                newPipeline.SetParentCallback(this.ParentCallback);
                newPipeline.OnUIEnable(this.ParentIntegration);
                AddCascadedPipeline(newPipeline);

                if (newPipeline.AutomaticMaterialCastersFromSelection)
                {
                    newPipeline.UpdateAutomaticMaterialCasters();
                }
            }
        }

        public void UpdateAutomaticMaterialCasters()
        {
            if (ParentIntegration != null)
            {
                List<KeyValuePair<string, ESimplygonMaterialCaster>> materialChannels = ParentIntegration.GetMaterialChannelsFromSelection();

                foreach (var materialChannel in materialChannels)
                {
                    var materialCaster = AddMaterialCaster(materialChannel.Value, materialChannel.Key, false);
                }

                List<SimplygonMaterialCaster> materialCastersToRemove = new List<SimplygonMaterialCaster>();
                foreach (var materialCaster in MaterialCasters)
                {
                    bool exist = materialChannels.Any(i => i.Key == materialCaster.MaterialChannelName);

                    if (!exist)
                    {
                        materialCastersToRemove.Add(materialCaster);
                    }
                }

                foreach (var materialCaster in materialCastersToRemove)
                {
                    RemoveMaterialCaster(materialCaster);
                }
                materialCasterTreeView.Update(this, true);
            }
        }
        public void RemovePipeline()
        {
            PendingPipelineRemoval = true;
        }

        public void ShowUI()
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.Space(15, false);
            var pipelineRect = EditorGUILayout.BeginVertical();
            CascadedPipelines.RemoveAll(i => i.PendingPipelineRemoval);
            GUILayout.BeginHorizontal();
            treeView.Update(this);
            var rect = EditorGUILayout.GetControlRect(false, treeView.totalHeight);
            rect.x += (float)EditorGUI.indentLevel * 25.0f;
            rect.width -= (float)EditorGUI.indentLevel * 25.0f;
            treeView.OnGUI(rect);
            if (GUILayout.Button(EditorGUIUtility.IconContent("_Popup", ""), GUILayout.Height(25.0f), GUILayout.Width(25.0f)))
            {
                GenericMenu menu = new GenericMenu();
                CascadedLODDropdownFactory.BuildItems(menu);
                menu.ShowAsContext();
            }
            if (GUILayout.Button(EditorGUIUtility.IconContent("TreeEditor.Trash", ""), GUILayout.Height(25.0f), GUILayout.Width(25.0f)))
            {
                RemovePipeline();
            }
            GUILayout.EndHorizontal();
            if (PipelineName != "OcclusionMeshPipeline")
            {
                bool forceMaterialCasterRefresh = false;
                if (materialCasterTreeView.PendingMaterialCasterRemoval != null)
                {
                    RemoveMaterialCaster(materialCasterTreeView.PendingMaterialCasterRemoval);
                    forceMaterialCasterRefresh = true;
                    materialCasterTreeView.PendingMaterialCasterRemoval = null;
                }
                GUILayout.BeginHorizontal();
                if (MaterialCasters.Count > 0)
                {
                    materialCasterTreeView.Update(this, forceMaterialCasterRefresh);
                    rect = EditorGUILayout.GetControlRect(false, materialCasterTreeView.totalHeight);
                    rect.x += (float)EditorGUI.indentLevel * 25.0f;
                    rect.width -= (float)EditorGUI.indentLevel * 25.0f;
                    materialCasterTreeView.OnGUI(rect);
                }
                else
                {
                    materialCasterTreeView.Update(this, forceMaterialCasterRefresh);
                    rect = EditorGUILayout.GetControlRect(false, 25.0f);
                    rect.x += (float)EditorGUI.indentLevel * 25.0f;
                    rect.width -= (float)EditorGUI.indentLevel * 25.0f;
                    materialCasterTreeView.OnGUI(rect);
                }
                if (GUILayout.Button(EditorGUIUtility.IconContent("_Popup", ""), GUILayout.Height(25.0f), GUILayout.Width(25.0f)))
                {
                    GenericMenu menu = new GenericMenu();
                    MaterialCastersDropdownFactory.BuildItems(menu);
                    menu.ShowAsContext();
                }
                GUILayout.EndHorizontal();
            }
            EditorGUILayout.Space(5, false);
            foreach (var cascadedPipeline in CascadedPipelines)
            {
                EditorGUI.indentLevel++;
                GUILayout.Space(15);
                cascadedPipeline.ShowUI();
                EditorGUI.indentLevel--;
            }
            EditorGUILayout.EndVertical();
            EditorGUILayout.EndHorizontal();
            EditorGUI.DrawRect(new Rect(pipelineRect.x - 10, pipelineRect.y, 5, pipelineRect.height), LODColor);
        }

        public void ToggleEdit()
        {
            treeView.ToggleEdit();
            treeView.Update(this, true);
            materialCasterTreeView.ToggleEdit();
            if (MaterialCasters.Count > 0)
            {
                materialCasterTreeView.Update(this, true);
            }
        }
    }
}
