using Aitex.Core.RT.Log;
using Caliburn.Micro;
using DocumentFormat.OpenXml.EMMA;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.UI.Client.CenterViews.Configs.Roles;
using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
using MECF.Framework.UI.Core.Accounts;
using OpenSEMI.ClientBase;
using OpenSEMI.ClientBase.Command;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;

namespace MECF.Framework.UI.Client.CenterViews.Editors.Recipe
{
    public class RecipeCompareViewModel : UiViewModelBase, ISupportMultipleSystem
    {
        private readonly RecipeType _fileTypes;
        private readonly bool _isFolderOnly;
        private readonly bool _isShowRootNode;
        private FileNode _currentFileNode;
        private readonly RecipeProvider _recipeProvider;

        public object View { get; set; }

        public ObservableCollection<string> Chambers { get; set; }

        private string labSelectRecipeNames;

        public string LabSelectRecipeNames
        {
            get => labSelectRecipeNames;
            set
            {
                labSelectRecipeNames = value;
                NotifyOfPropertyChange();
            }
        }

        private RecipeData _recipeHeaders;

        /// <summary>
        /// Recipe表头
        /// </summary>
        public RecipeData RecipeHeaders
        {
            get => _recipeHeaders;
            set
            {
                _recipeHeaders = value;
                NotifyOfPropertyChange();
            }
        }

        private RecipeData _comparRecipeHeader;

        /// <summary>
        /// Recipe表头
        /// </summary>
        public RecipeData ComparRecipeHeader
        {
            get => _comparRecipeHeader;
            set
            {
                _comparRecipeHeader = value;
                NotifyOfPropertyChange();
            }
        }

        private RecipeData _comparRecipe1;

        /// <summary>
        /// 选择要Recipe-1
        /// </summary>
        public RecipeData ComparRecipe1
        {
            get => _comparRecipe1;
            set
            {
                _comparRecipe1 = value;
                NotifyOfPropertyChange();
            }
        }

        private RecipeData _comparRecipe2;

        /// <summary>
        /// 选择要Recipe-2
        /// </summary>
        public RecipeData ComparRecipe2
        {
            get => _comparRecipe2;
            set
            {
                _comparRecipe2 = value;
                NotifyOfPropertyChange();
            }
        }

        private double[] _scrollViewerOffset;

        /// <summary>
        /// ScrollViewer滑动偏移
        /// </summary>
        public double[] ScrollViewerOffset
        {
            get => _scrollViewerOffset;
            set
            {
                _scrollViewerOffset = value;
                NotifyOfPropertyChange();
            }
        }

        public RecipeHistory RecipeHistory { get; set; }

        private ICommand _recipeHistoryCommand;

        public ICommand RecipeHistoryCommand
        {
            get
            {
                if (_recipeHistoryCommand == null)
                    _recipeHistoryCommand = new BaseCommand(() => RecipeHistoryViewShow());
                return _recipeHistoryCommand;
            }
        }

        public int ProcessTypeIndexSelection { get; set; }
        public RecipeType CurrentProcessType => ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;

        public string CurrentChamberType { get; set; }

        public string SelectedChamber { get; set; }

        public ObservableCollection<FileNode> SelectRecipeNameList { get; set; } = new ObservableCollection<FileNode>();

        public FileNode DGSelectRecipeName { get; set; }

        public List<ProcessTypeFileItem> ProcessTypeFileList { get; set; }

        public RecipeCompareViewModel()
        {
            _fileTypes = RecipeType.Process | RecipeType.Routine;
            _isFolderOnly = false;
            _isShowRootNode = false;

            _recipeProvider = new RecipeProvider();
        }

        protected override void OnViewLoaded(object view)
        {
            View = view;
            
            base.OnViewLoaded(view);
        }

        protected override void OnActivate()
        {
            base.OnActivate();
            RefreshRecipe();
        }

        protected override void OnDeactivate(bool close)
        {
            base.OnDeactivate(close);

            // 锁定编辑器
            ((RecipeCompareView)View).editorLocker.Lock();
        }

        protected override void OnInitialize()
        {
            base.OnInitialize();
            
            CurrentChamberType = (string)QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedChamberType");
            
            BuildFileTree(_isShowRootNode, _isFolderOnly, _fileTypes);
            UpdateRecipeFormat();
        }

        public void RefreshRecipe()
        {
            ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, "", false);
        }

        private void ReloadRecipeFileList(string chamberType, RecipeType processType, string selectedFile,
            bool selectionIsFolder)
        {
            var item = ProcessTypeFileList.FirstOrDefault(x => x.ProcessType == processType);
            if (item == null)
            {
                LOG.Write("error reload recipe file list, type = " + processType);
            }

            var prefix = $"{CurrentChamberType}\\{SystemName}\\{item.ProcessType}";
            var recipes = _recipeProvider.GetXmlRecipeList(prefix);

            item.FileListByProcessType =
                RecipeSequenceTreeBuilder.BuildFileNode(prefix, selectedFile, selectionIsFolder, recipes)[0].Files;

            item.InvokePropertyChanged();
        }

        private void StoryboardClose()
        {
            var getString = (Storyboard)((RecipeCompareView)View).FindResource("MenuClose");
            getString.Begin();
        }

        private void RecipeHistoryViewShow()
        {
            if (_currentFileNode == null)
                return;
            var dialog = new RecipeHistoryViewModel(_currentFileNode.FullPath.Replace("\\", "-"));
            var wm = new WindowManager();

            dynamic settings = new ExpandoObject();
            settings.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            settings.Title = "Recipe历史数据对比，选择一个(选择项和当前使用项对比)，选择两个(两个选择项对比)";
            settings.ResizeMode = ResizeMode.NoResize;
            settings.ShowInTaskbar = false;
            StoryboardClose();
            var bret = wm.ShowDialog(dialog, null, settings);
            if ((bool)bret)
            {
                if (dialog.SelectRecipeMemorieList.Count == 1)
                    RecipeSelectAndHistory(dialog.SelectRecipeMemorieList[0]);
                else if (dialog.SelectRecipeMemorieList.Count == 2)
                    RecipeBothHistory(dialog.SelectRecipeMemorieList);
            }
        }

        private async void RecipeSelectAndHistory(RecipeHistory recipeHistory)
        {
            RecipeHistory = recipeHistory;
            LabSelectRecipeNames = _currentFileNode.FullPath + "   /   " + RecipeHistory.RecipeName + ": " + RecipeHistory.CreateTime;
            await LoadRecipe(ComparRecipe1, _currentFileNode.PrefixPath, _currentFileNode.FullPath);
            await LoadRecipe(ComparRecipe2, RecipeHistory);
            StartComper(ComparRecipe1, ComparRecipe2);
        }

        private async void RecipeBothHistory(List<RecipeHistory> recipeHistoryList)
        {
            LabSelectRecipeNames = recipeHistoryList[0].RecipeName + ": " + recipeHistoryList[0].CreateTime + "   /   " + recipeHistoryList[1].RecipeName + ": " + recipeHistoryList[1].CreateTime;
            await LoadRecipe(ComparRecipe1, recipeHistoryList[0]);
            await LoadRecipe(ComparRecipe2, recipeHistoryList[1]);
            StartComper(ComparRecipe1, ComparRecipe2);
        }

        public void TreeSelectChanged(FileNode file)
        {
            _currentFileNode = file;
            RecipeHistoryViewShow();
        }

        public void TreeRightMouseDown(MouseButtonEventArgs e)
        {
            var item = GetParentObjectEx<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
            if (item != null)
            {
                item.Focus();
            }
        }

        private TreeViewItem GetParentObjectEx<TreeViewItem>(DependencyObject obj) where TreeViewItem : FrameworkElement
        {
            var parent = VisualTreeHelper.GetParent(obj);
            while (parent != null)
            {
                if (parent is TreeViewItem)
                {
                    return (TreeViewItem)parent;
                }

                parent = VisualTreeHelper.GetParent(parent);
            }

            return null;
        }

        private void BuildFileTree(bool isShowRootNode, bool isFolderOnly, RecipeType fileType)
        {
            var recipeProvider = new RecipeProvider();
            
            var scProcessType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedProcessType").ToString();
            var ProcessType = new ObservableCollection<string>(((string)(scProcessType)).Split(','));

            var processTypeFileList = new List<ProcessTypeFileItem>();

            for (var i = 0; i < ProcessType.Count; i++)
            {
                Enum.TryParse(ProcessType[i], true, out RecipeType rType);
                var type = new ProcessTypeFileItem
                {
                    ProcessType = rType
                };
                var prefix = $"{CurrentChamberType}\\{SystemName}\\{ProcessType[i]}";
                var recipes = recipeProvider.GetXmlRecipeList(prefix);
                type.FileListByProcessType = RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes, isFolderOnly, isShowRootNode)[0].Files;
                processTypeFileList.Add(type);
            }

            this.ProcessTypeFileList = processTypeFileList;
        }
        
        public void UpdateRecipeFormat()
        {
            var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules");
            if (chamber == null)
            {
                chamber = "PM1";
            }

            Chambers = new ObservableCollection<string>(((string)chamber).Split(','));
            if (Chambers.Count > 1)
            {
                for (var i = 0; i < Chambers.Count; i++)
                {
                    var isPmInstall =
                        (bool)QueryDataClient.Instance.Service.GetConfig(
                            $"System.SetUp.Is{Chambers[i].ToString()}Installed");
                    {
                        if (!isPmInstall)
                        {
                            Chambers.RemoveAt(i);
                        }
                    }
                }
            }

            if (Chambers.Count == 0)
            {
                Chambers = new ObservableCollection<string>(new string[] { "PM1" });
            }

            SelectedChamber = Chambers[0];

            #region Create RecipeData

            ComparRecipeHeader = CreateRecipe();
            ComparRecipeHeader.AddStep();

            ComparRecipe1 = CreateRecipe();
            ComparRecipe2 = CreateRecipe();

            #endregion Create RecipeData
        }

        private RecipeData CreateRecipe()
        {
            var role = AccountClient.Instance.Service.GetRoleByID(BaseApp.Instance.UserContext.Role.RoleId);

            var recipeData = new RecipeData(null, CurrentProcessType);
            recipeData.BuildFormat($"{CurrentChamberType}\\{CurrentProcessType}", SystemName, role);

            //得到当前登录的RoleItem
            //var role = _roleManager.GetRoleByName(BaseApp.Instance.UserContext.RoleName);

            return recipeData;
        }

        private async Task LoadRecipe(RecipeData recipeData, string prefixPath, string recipeName)
        {
            recipeData.Clear();
            recipeData.Steps.Save(); // 重置为已保存状态

            var recipeContent = _recipeProvider.ReadRecipeFile(prefixPath, recipeName);

            if (string.IsNullOrEmpty(recipeContent))
            {
                MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.",
                    "Error",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            var role = AccountClient.Instance.Service.GetRoleByID(BaseApp.Instance.UserContext.Role.RoleId);
            await recipeData.LoadFile(prefixPath, recipeName, recipeContent, SelectedChamber, role,
                GetLoadingDispatcher());
        }

        private async Task LoadRecipe(RecipeData recipeData, RecipeHistory recipeHistory)
        {
            recipeData.Clear();
            recipeData.Steps.Save(); // 重置为已保存状态

            var role = AccountClient.Instance.Service.GetRoleByID(BaseApp.Instance.UserContext.Role.RoleId);
            await recipeData.LoadFile(recipeHistory, SelectedChamber, role,
                GetLoadingDispatcher());
        }

        private static Dispatcher GetLoadingDispatcher()
        {
            // 判断Step呈现方式
            var isCascadeLoading = (bool)QueryDataClient.Instance.Service.GetConfig("System.RecipeCascadeLoading");
            var dispatcher = isCascadeLoading ? Dispatcher.CurrentDispatcher : null;
            return dispatcher;
        }

        public async void ComperSelectRecipe()
        {
            SelectRecipeNameList.Clear();

            foreach (var ProcessTypeFile in ProcessTypeFileList)
            {
                GetSelectRecipeName(ProcessTypeFile.FileListByProcessType);
            }

            if (SelectRecipeNameList.Count != 2)
            {
                DialogBox.ShowError("Only 2 comparisons are supported");
                return;
            }
            StoryboardClose();
            LabSelectRecipeNames = SelectRecipeNameList[0].Name + "   /   " + SelectRecipeNameList[1].Name;

            await LoadRecipe(ComparRecipe1, GetRecipeFullPath(SelectRecipeNameList[0]), SelectRecipeNameList[0].Name);

            await LoadRecipe(ComparRecipe2, GetRecipeFullPath(SelectRecipeNameList[1]), SelectRecipeNameList[1].Name);

            StartComper(ComparRecipe1, ComparRecipe2);
        }

        /// <summary>
        /// 递归获取选择的Recipe
        /// </summary>
        /// <param name="fileNodes"></param>
        private void GetSelectRecipeName(ObservableCollection<FileNode> fileNodes)
        {
            foreach (var item in fileNodes)
            {
                if (item.Files != null && item.Files.Count > 0)
                    GetSelectRecipeName(item.Files);

                if (item.IsSelected)
                    SelectRecipeNameList.Add(item);
            }
        }

        private string GetRecipeFullPath(FileNode fileNodes)
        {
            return fileNodes.PrefixPath + (fileNodes.Parent.FullPath == "" ? "" : "\\" + fileNodes.Parent.FullPath);
        }

        public void StartComper(RecipeData recipeData1, RecipeData recipeData2)
        {
            int stepsCount = 0;//缓存较短Recipe步数
            RecipeData recipeDataExcess;//缓存较长步数Recipe
            if (recipeData1.Steps.Count <= recipeData2.Steps.Count)
            {
                stepsCount = recipeData1.Steps.Count;
                recipeDataExcess = recipeData2;
            }
            else
            {
                stepsCount = recipeData2.Steps.Count;
                recipeDataExcess = recipeData1;
            }

            for (int i = 0; i < stepsCount; i++)
            {
                RecipeStep recipe1step = recipeData1.Steps[i];
                RecipeStep recipe2step = recipeData2.Steps[i];

                for (int j = 0; j < recipe1step.Count; j++)
                {
                    object obj1 = GetValue(recipe1step[j]);//获取单元格中的数值，object类型
                    object obj2 = GetValue(recipe2step[j]);

                    if (!(Object.Equals(obj1, obj2)))
                    {
                        //recipe1step[j].Highlight();//不同部分高亮
                        //recipe2step[j].Highlight();

                        recipe1step[j].CompareDifferent();
                        recipe2step[j].CompareDifferent();
                    }
                }
            }

            //步数多余部分高亮显示   使用缓存步数和缓存Recipe
            for (int i = stepsCount; i < recipeDataExcess.Steps.Count; i++)
            {
                for (int j = 0; j < recipeDataExcess.Steps[i].Count; j++)
                {
                    recipeDataExcess.Steps[i][j].CompareDifferent();
                }
            }
        }

        private object GetValue(Param param)
        {
            object Value = null;
            if (param is IValueParam vp)
                Value = vp.GetValue();

            return Value;
        }
    }
}