namespace TagFighter.UI.Editor
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using TagFighter.Effects;
    using TagFighter.Effects.Steps;
    using UnityEditor;
    using UnityEditor.Callbacks;
    using UnityEngine;
    using UnityEngine.UIElements;

    public class RuneEditor : EditorWindow
    {
        RuneEffectView _runeView;
        ListView _runeEffects;
        public RuneRef SelectedRuneRef;

        [SerializeField]
        RuneEffect _selectedRuneEffect;

        [SerializeField]
        EffectStepNodeView _selectedNodeView;

        [NonSerialized]
        bool _visualElementsReady = false;

        [MenuItem("TagFighter/RuneEditor")]
        public static void ShowEditorWindow() {
            var window = GetWindow<RuneEditor>();
            window.titleContent = new GUIContent("RuneEditor");
            window.SelectedRuneRef = Selection.activeObject as RuneRef;
            window.UpdateEditorView();
        }

        [OnOpenAsset(1)]
        public static bool OnOpenAsset(int instanceID, int line) {
            var selectedRuneRef = EditorUtility.InstanceIDToObject(instanceID) as RuneRef;
            if (selectedRuneRef != null) {
                ShowEditorWindow();
                return true;
            }
            return false;
        }

        public void CreateGUI() {
            var root = rootVisualElement;
            var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/Rune/RuneEditor.uss");
            root.styleSheets.Add(styleSheet);

            var splitView = new TwoPaneSplitView(0, 250, TwoPaneSplitViewOrientation.Horizontal);
            var leftPane = new VisualElement();
            splitView.Add(leftPane);
            var rightPane = new VisualElement();
            splitView.Add(rightPane);

            var runeEffectsControl = new VisualElement() {
                name = "runeEffectsControl"
            };
            leftPane.Add(runeEffectsControl);

            var addRuneEffect = new Button() {
                name = "addRuneEffect",
                text = "+",
            };
            addRuneEffect.clicked += OnAddRuneEffect;
            runeEffectsControl.Add(addRuneEffect);

            var removeRuneEffect = new Button() {
                name = "removeRuneEffect",
                text = "-",
            };
            removeRuneEffect.clicked += OnRemoveRuneEffect;
            runeEffectsControl.Add(removeRuneEffect);


            _runeEffects = new ListView() {
                itemsSource = null,
                makeItem = () => new Label(),
                bindItem = (e, i) => (e as Label).text = SelectedRuneRef.RuneEffects[i].DisplayName,
            };
            _runeEffects.onSelectionChange += OnRuneEffectSelectionChanged;
            _runeEffects.reorderable = true;

            leftPane.Add(_runeEffects);

            _runeView = new RuneEffectView();
            rightPane.Add(_runeView);


            var scrollView = new ScrollView(ScrollViewMode.VerticalAndHorizontal);


            scrollView.Add(splitView);

            root.Add(scrollView);

            _runeView.OnNodeSelected = OnNodeSelectionChanged;
            _visualElementsReady = true;
            UpdateEditorView();
        }

        void OnRuneEffectSelectionChanged(IEnumerable<object> enumerable) {
            Selection.activeObject = enumerable.First() as RuneEffect;
        }

        void OnRemoveRuneEffect() {
            var runeEffect = _runeEffects.selectedItem as RuneEffect;
            if (runeEffect == null) {
                return;
            }

            if (SelectedRuneRef.RuneEffects.Remove(runeEffect)) {
                foreach (var step in runeEffect.Nodes) {
                    AssetDatabase.RemoveObjectFromAsset(step);
                }
                AssetDatabase.RemoveObjectFromAsset(runeEffect);
                UpdateEditorView();
            }
        }

        void OnAddRuneEffect() {
            var runeEffect = ScriptableObject.CreateInstance<RuneEffect>();
            runeEffect.name = runeEffect.DisplayName;
            SelectedRuneRef.RuneEffects.Add(runeEffect);
            AssetDatabase.AddObjectToAsset(runeEffect, SelectedRuneRef);
            _runeEffects.RefreshItems();
        }

        void UpdateEditorView() {
            if (_visualElementsReady) {
                if (SelectedRuneRef != null) {
                    _runeEffects.itemsSource = SelectedRuneRef.RuneEffects;
                    _runeEffects.RefreshItems();
                    _selectedRuneEffect = _runeEffects.selectedItem as RuneEffect;
                    if (_selectedRuneEffect == null && SelectedRuneRef.RuneEffects.Count > 0) {
                        _runeEffects.SetSelection(0);
                        _selectedRuneEffect = _runeEffects.selectedItem as RuneEffect;
                    }
                }
                _runeView.PopulateView(_selectedRuneEffect);
            }
        }

        void OnSelectionChanged() {
            // AssetDatabase.CanOpenAssetInEditor(dialogueCandidate.GetInstanceID())

            switch (Selection.activeObject) {
                case RuneRef rune:
                    SelectedRuneRef = rune;
                    UpdateEditorView();
                    break;
                case EffectStepNode node: {
                        var runeRefCandidate = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GetAssetPath(node)) as RuneRef;
                        if (SelectedRuneRef != runeRefCandidate) {
                            SelectedRuneRef = runeRefCandidate;
                            UpdateEditorView();
                        }

                    }
                    break;
                case RuneEffect runeEffect: {
                        var runeRefCandidate = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GetAssetPath(runeEffect)) as RuneRef;
                        if (SelectedRuneRef != runeRefCandidate) {
                            SelectedRuneRef = runeRefCandidate;
                        }
                        _selectedRuneEffect = runeEffect;
                        UpdateEditorView();
                    }
                    break;
                default:
                    if (SelectedRuneRef == null) {
                        UpdateEditorView();
                    }
                    break;
            }
        }

        void OnNodeSelectionChanged(EffectStepNodeView nodeView) {
            if (_selectedNodeView != null) {
                _selectedNodeView.Node.EffectStepValidated -= OnEffectStepValidated;
            }
            _selectedNodeView = nodeView;
            _selectedNodeView.Node.EffectStepValidated += OnEffectStepValidated;
            Selection.activeObject = nodeView.Node;
        }

        void OnEffectStepValidated(object sender, EffectStepValidatedEventArgs e) {
            _selectedNodeView.RefreshDisplay(e);
        }

        void OnUndoRedo() {
            _runeView.PopulateView(_runeEffects.selectedItem as RuneEffect);
        }

        void OnEnable() {
            Undo.undoRedoPerformed += OnUndoRedo;
            Selection.selectionChanged += OnSelectionChanged;
        }

        void OnDisable() {
            Undo.undoRedoPerformed -= OnUndoRedo;
            Selection.selectionChanged -= OnSelectionChanged;
            if (_selectedNodeView != null) {
                _selectedNodeView.Node.EffectStepValidated -= OnEffectStepValidated;
            }
        }
    }

}