using Newtonsoft.Json;
using Nodify.Calculator.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Shapes;

namespace Nodify.Calculator
{
    public class ApplicationViewModel : ObservableObject
    {
        public NodifyObservableCollection<EditorViewModel> Editors { get; } = new NodifyObservableCollection<EditorViewModel>();

        public ApplicationViewModel()
        {
            AddEditorCommand = new DelegateCommand(() => Editors.Add(new EditorViewModel
            {
                Name = $"Editor {Editors.Count + 1}"
            }));
            CloseEditorCommand = new DelegateCommand<Guid>(
                id => Editors.RemoveOne(editor => editor.Id == id),
                _ => Editors.Count > 0 && SelectedEditor != null);
            RunFlowCommand = new DelegateCommand(() =>
            {
                Executor ex = new Executor(Editors.First());
                var result = ex.PerformPreCheck();
                if (!string.IsNullOrEmpty(result))
                {
                    MessageBox.Show("Error occured while executing the request : " + result);
                }
                else
                {
                    FlowRunner runner = new FlowRunner(ex);
                    runner.ShowDialog();
                }
            });
            SaveFileCommand = new DelegateCommand(() =>
            {
                var firstEditor = Editors.First();
                var allNodes = firstEditor.Calculator.Operations;
                
                SaveGraphModel svm = new SaveGraphModel();
                foreach (var item in allNodes)
                {
                    SaveNodes svn = new SaveNodes()
                    {
                        Location = item.Location,
                    };
                    svm.Nodes.Add(svn);
                }


                var jsonEditors = JsonConvert.SerializeObject(svm, new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                });
                //var jsonEditors = JsonConvert.SerializeObject(Editors);
                File.WriteAllText("SaveFile.AEXN", jsonEditors);
            });
            OpenFileCommand = new DelegateCommand(() =>
            {
                if (File.Exists("SaveFile.AEXN"))
                {
                    var allText = File.ReadAllText("SaveFile.AEXN");
                    var edts = JsonConvert.DeserializeObject<SaveGraphModel>(allText);
                    var firstEditor = Editors.First();
                    var nodesToAdd = edts.Nodes;
                    foreach (var item in nodesToAdd)
                    {
                        firstEditor.Calculator.Operations.Add(new()
                        {
                            Location = item.Location,
                            NodeId = "H",
                            Title = "HHA"
                        });
                    }
                    
                }
            });
            Editors.WhenAdded((editor) =>
            {
                if (AutoSelectNewEditor || Editors.Count == 1)
                {
                    SelectedEditor = editor;
                }
                editor.OnOpenInnerCalculator += OnOpenInnerCalculator;
            })
            .WhenRemoved((editor) =>
            {
                editor.OnOpenInnerCalculator -= OnOpenInnerCalculator;
                var childEditors = Editors.Where(ed => ed.Parent == editor).ToList();
                childEditors.ForEach(ed => Editors.Remove(ed));
            });
            Editors.Add(new EditorViewModel
            {
                Name = $"Editor {Editors.Count + 1}"
            });
        }

        private void OnOpenInnerCalculator(EditorViewModel parentEditor, CalculatorViewModel calculator)
        {
            var editor = Editors.FirstOrDefault(e => e.Calculator == calculator);
            if (editor != null)
            {
                SelectedEditor = editor;
            }
            else
            {
                var childEditor = new EditorViewModel
                {
                    Parent = parentEditor,
                    Calculator = calculator,
                    Name = $"[Inner] Editor {Editors.Count + 1}"
                };
                Editors.Add(childEditor);
            }
        }

        public ICommand AddEditorCommand { get; }
        public ICommand CloseEditorCommand { get; }
        public ICommand RunFlowCommand { get; }
        public ICommand SaveFileCommand { get; }
        public ICommand OpenFileCommand { get; }

        private EditorViewModel? _selectedEditor;
        public EditorViewModel? SelectedEditor
        {
            get => _selectedEditor;
            set => SetProperty(ref _selectedEditor, value);
        }

        private bool _autoSelectNewEditor = true;
        public bool AutoSelectNewEditor
        {
            get => _autoSelectNewEditor;
            set => SetProperty(ref _autoSelectNewEditor, value);
        }
    }
}
