using DynamicData.Aggregation;
using mitoSoft.Workflows.Editor.Helpers.Enums;
using mitoSoft.Workflows.Editor.View;
using mitoSoft.Workflows.Editor.ViewModel;

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Printing;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Xml.Linq;
using static System.Windows.Forms.LinkLabel;

namespace mitoSoft.Workflows.Editor.Helpers.CodeGenerator
{
    public class CodeGenerator
    {
        public List<string> OutputFile;

        public WorkflowCode WfC;

        List<BaseNodeViewModel> SchemeNodes;

        List<string> ExistingCodeLines = new List<string>();

        List<string> ExistingWorkflowLines = new List<string>();

        List<string> Usings;

        string Namespace;

        string WorkflowName;

        string FilePath;

        string BaseStateMachine;

        int WFBodyStart;

        int WFBodyEnd;

        public CodeGenerator(List<string> _Usings, string _Namespace, string _WorkflowName, string _BaseStateMachine, string _FilePath, List<BaseNodeViewModel> _SchemeNodes)
        {
            Usings = _Usings;
            Namespace = _Namespace;
            WorkflowName = _WorkflowName;
            BaseStateMachine = _BaseStateMachine;
            FilePath = _FilePath;
            SchemeNodes = _SchemeNodes;
            LoadExistingFile();
        }

        private void LoadExistingFile()
        {
            if (File.Exists(FilePath))
            {
                ExistingCodeLines = File.ReadAllLines(FilePath).ToList();
                
                WFBodyStart = ExistingCodeLines.FindIndex(x => x.Contains($"#region AutoGenerated StateMachine - {WorkflowName}"));
                                
                if (WFBodyStart != -1)
                {
                    WFBodyEnd = ExistingCodeLines.FindIndex(WFBodyStart, x => x.Contains($"#endregion"));

                    ExistingWorkflowLines = ExistingCodeLines.GetRange(WFBodyStart + 1, WFBodyEnd - (WFBodyStart + 1)).ToList();                    
                }
            }
        }

        public void Generate()
        {
            GenerateUpdatedCode();

            if (!File.Exists(FilePath) || WFBodyStart == -1)
            {
                ExistingCodeLines.AddRange(WfC.Compile().Split(Environment.NewLine));
            }
            else
            {
                ExistingCodeLines.RemoveRange(WFBodyStart + 1, WFBodyEnd - (WFBodyStart + 1));

                ExistingCodeLines.InsertRange(WFBodyStart + 1, WfC.WFBody.Compile().Split(Environment.NewLine));
            }
            OutputFile = new List<string>(ExistingCodeLines);
        }

        private void GenerateUpdatedCode()
        {
            WfC = new WorkflowCode(Usings, Namespace, WorkflowName, BaseStateMachine, ExistingWorkflowLines);

            foreach (var node in SchemeNodes)
            {
                var NodeName = node.Name;

                var transitions = node.TransitionsForView.Where(y => !string.IsNullOrEmpty(y.Name)).ToList();

                var MultiCondi = false;                

                string NextNodeName = null;

                if (transitions.Count == 1)
                {                    
                    NextNodeName = transitions.First().GetTargetNode().Name;
                }
                else if (transitions.Count > 1)
                {
                    MultiCondi = true;
                }

                if (node is ParallelNodeViewModel)
                {
                    WfC.WFBody.AddParallelNode(NodeName, NextNodeName, ((ParallelNodeViewModel)node).ParallelStates.ToList());
                }
                else if (node is SequenceNodeViewModel)
                {
                    WfC.WFBody.AddSequenceNode(NodeName, NextNodeName, ((SequenceNodeViewModel)node).SequenceNodes.ToList());
                }
                else if (node is SubWorkflowNodeViewModel)
                {
                    WfC.WFBody.AddSubWorkflowNode(NodeName, NextNodeName, ((SubWorkflowNodeViewModel)node).SubStateMachine);
                }
                else if (node is NodeViewModel)
                {
                    WfC.WFBody.AddSingleNode(NodeName, NextNodeName);
                }

                if (MultiCondi)
                {
                    WfC.WFBody.AddOrUpdateCondis(NodeName, transitions);
                }
            }
        }
    }
}
