

namespace Guru
{
    using System;
    using UnityEngine;
    using UnityEngine.UI;
    using G = GlobalVars;
    using System.Collections.Generic;
    using System.Linq;
    
    
    public class GuruDebugger
    {
        public const string Version = "1.0.0";    
        private static bool _initOnce = false;
        private static GuruDebugger _instance;
        public static GuruDebugger Instance
        {
            get
            {
                if (_instance == null)
                {
                    Init();
                }
                return _instance;
            }
        }

        public static event Action OnClosed
        {
            add => _onViewClosed += value;
            remove => _onViewClosed -= value;
        }

        private static Action _onViewClosed;

        private DebuggerViewRoot _viewRoot;
        private Dictionary<string, List<OptionLayout>> optionDicts;
        private string _curTabName;

        public static void Init()
        {
            if (_instance == null) _initOnce = false;

            if (_initOnce) return;
            _initOnce = true;
            _instance = new GuruDebugger();
            _instance.StartService();
        }
        
        private void StartService()
        {
            _viewRoot = DebuggerViewRoot.Instance;
            optionDicts = new Dictionary<string, List<OptionLayout>>(5);
            G.Events.OnUIEvent += OnUIEvent;
            
            AdStatus.Install(_viewRoot.AdStatusMonitor, OnMonitorClicked);
        }
        
        

        #region UIEvent

        private void OnUIEvent(string evt, object data = null)
        {
            switch (evt)
            {
                case G.Events.EventTabClicked:
                    OnSelectTab(data.ToString());
                    break;
                case G.Events.EventViewClosed:
                    // optionDicts?.Clear();
                    _onViewClosed?.Invoke();
                    ShowAdStatus();
                    break;
                case G.Events.EventMonitorClicked:
                    HideAdStatus();
                    ShowPage();
                    break;
            }
        }
        
        
        private void OnMonitorClicked()
        {
            OnUIEvent(G.Events.EventMonitorClicked);
        }
        

        #endregion
        
        #region UI Layout

        public OptionLayout AddOption(string uri, string content = "", Action clickHandler = null)
        {
            string tabName = G.Consts.DefaultTabName;
            string optName = G.Consts.DefaultOptionName;
            if (uri.Contains("/"))
            {
                var names = uri.Split('/');
                if (names.Length > 0)
                {
                    tabName = names[0];
                }
                if(names.Length > 1) optName = names[1];
            }

            if (!optionDicts.ContainsKey(tabName))
            {
                optionDicts[tabName] = new List<OptionLayout>(10);
            }
  
            OptionLayout opt = new OptionLayout();
            opt.tabName = tabName;
            opt.optName = optName;
            opt.content = content;
            opt.selfClickHandler = clickHandler;

            AddOptionLayout(tabName, opt);
            
            return opt;
        }

        private void AddOptionLayout(string tabName, OptionLayout layout)
        {
            TryToAddOption(tabName, layout);
        }

        private bool TryToAddOption(string tabName, OptionLayout opt)
        {
            if (!optionDicts.ContainsKey(tabName))
            {
                optionDicts[tabName] = new List<OptionLayout>(20);
                optionDicts[tabName].Add(opt);
                return true;
            }
            
            var options = optionDicts[tabName];
            var oldOpt = options.FirstOrDefault(c => c.IsEqual(opt));
            if (oldOpt == null)
            {
                options.Add(opt);
                return true;
            }

            return false;
        }


        public void ShowAdStatus()
        {
            _viewRoot.ShowAdStatusMonitor();
        }
        
        
        public void HideAdStatus()
        {
            _viewRoot.HideAdStatusMonitor();
        }


        public void ShowPage(string tabName = "")
        {
            if (string.IsNullOrEmpty(tabName) 
                && optionDicts != null && optionDicts.Count > 0)
            {
                tabName = optionDicts.Keys.First();
            }

            if (!string.IsNullOrEmpty(tabName))
            {
                RenderPage(tabName);
            }
            
            
        }

        /// <summary>
        /// 渲染页面
        /// </summary>
        /// <param name="tabName"></param>
        private void RenderPage(string tabName)
        {
            if (string.IsNullOrEmpty(tabName)) return;
            
            _viewRoot.ShowOptions();
            _viewRoot.RefreshTabs(tabName, optionDicts.Keys.ToList());
            _viewRoot.CleanOptions();
            if (optionDicts.TryGetValue(tabName, out var opts))
            {
                OptionLayout ol;
                UIOptionItem ui;
                for (int i = 0; i < opts.Count; i++)
                {
                    ol = opts[i];
                    ui = _viewRoot.RegisterOption(ol.optName, ol.content);

                    if (ol.selfClickHandler != null)
                    {
                        var btnName = ol.content;
                        if (string.IsNullOrEmpty(btnName)) btnName = ol.optName;
                        var btn = _viewRoot.AddOptionButton(ui, btnName, ol.selfClickHandler);
                        ui.Clickable = true;
                        continue;
                    }
                    
                    foreach (var item in ol.items)
                    {
                        switch (item.type)
                        {
                            case "button":
                                var btn = _viewRoot.AddOptionButton(ui, item.name, item.clickHandler);
                                if (!item.size.Equals(Vector2.zero)) btn.Size = item.size;
                                break;
                            
                            case "label":
                                var lb = _viewRoot.AddOptionLabel(ui, item.name, item.align);
                                if (!item.size.Equals(Vector2.zero)) lb.Size = item.size;
                                break;
                        }
                    }
                }
            }
            else
            {
                Debug.LogError($"Tab [{tabName}] not found!");
            }

        }


        private void OnSelectTab(string tabName)
        {
            if (_curTabName == tabName) return;
            Instance.ShowPage(tabName);
        }

        #endregion

        #region Display
        
        public static void Show(string tabName = "")
        {
            Instance.ShowPage(tabName);
        }

        public static void Hide()
        {
            Instance._viewRoot.HideOptions();
        }

        #endregion
        
        #region DebuggerOption
        
        public class OptionLayout
        {
            public string optName;
            public string content;
            public string tabName;
            public Action selfClickHandler;

            internal List<OptionItemLayout> items;


            public OptionLayout()
            {
                items = new List<OptionItemLayout>(10);
            }


            public OptionLayout AddLabel(string labelName)
            {
                items.Add(new OptionItemLayout()
                {
                    name = labelName,
                    type = "label",
                });
                return this;
            }
            
            public OptionLayout AddButton(string btnName, Action onClick)
            {
                items.Add(new OptionItemLayout()
                {
                    name = btnName,
                    type = "button",
                    clickHandler = onClick
                });
                return this;
            }
            
            public bool IsEqual(OptionLayout other)
            {
                var res = other.tabName == tabName
                          && other.optName == optName
                          // && other.content == content
                          && IsItemsEqual(other);
                return res;
            }


            private bool IsItemsEqual(OptionLayout other)
            {
                if (items == null && other.items == null) return true;
                if (items != null && other.items == null || items == null && other.items != null) return false;
                if (items != null && other.items != null)
                {
                    if (items.Count != other.items.Count)
                    {
                        return false;
                    }
                    
                    for (int i = 0; i < items.Count; i++)
                    {
                        if (!items[i].IsEqual(other.items[i]))
                        {
                            return false;
                        }
                    }
                }

                return true;
            }
        }

        

        internal class OptionItemLayout
        {
            public string type;
            public Action clickHandler;
            public string name;
            public string content;
            public TextAnchor align = TextAnchor.MiddleCenter;
            public Vector2 size = Vector2.zero;
            
            public bool IsEqual(OptionItemLayout other)
            {
                return other.type == type 
                       && other.name == name; 
                       // && other.content == content;
            }
            
        }

        #endregion
        
    }


    public static class OptionLayoutExtension
    {
        public static GuruDebugger.OptionLayout AddCopyButton(this GuruDebugger.OptionLayout layout, Action onClick = null)
        {
            layout.AddButton("Copy", ()=>
            {
                GUIUtility.systemCopyBuffer = layout.content;
                onClick?.Invoke();
            });
            return layout;
        }
    }



}