using DevExpress.Data.Helpers;
using DevExpress.Xpf.Core;
using log4net;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using VIZ.Framework.Core;
using VIZ.Package.Common;
using VIZ.Package.Domain;
using VIZ.Package.Service;

namespace VIZ.Package.Module
{
    /// <summary>
    /// 项目树面板模型
    /// </summary>
    public class ProjectTreePanelModel : ViewModelBase
    {
        /// <summary>
        /// 日志
        /// </summary>
        private readonly static ILog log = LogManager.GetLogger(typeof(ProjectTreePanelModel));

        public ProjectTreePanelModel()
        {
            // 初始化命令
            this.InitCommand();
        }

        /// <summary>
        /// 初始化命令
        /// </summary>
        private void InitCommand()
        {
            this.LoadedCommand = new VCommand(this.Loaded);
            this.FolderExpandCommand = new VCommand<DevExpress.Xpf.Grid.TreeList.NodeDoubleClickEventArgs>(this.FolderExpand);
            this.FolderExpandingCommand = new VCommand<DevExpress.Xpf.Grid.TreeList.TreeViewNodeAllowEventArgs>(this.FolderExpanding);

            this.FolderContentMenuOpendCommand = new VCommand(this.FolderContentMenuOpend);
            this.CreateFolderCommand = new VCommand(this.CreateFolder, this.CanCreateFolder);
            this.DeleteFolderCommand = new VCommand(this.DeleteFolder, this.CanDeleteFolder);
            this.RefreshFolderCommand = new VCommand(this.RefreshFolder);

            this.FileContentMenuOpendCommand = new VCommand(this.FileContentMenuOpend);
            this.DeleteFileCommand = new VCommand(this.DeleteFile, this.CanDeleteFile);
            this.RefreshFileCommand = new VCommand(this.RefreshFile, this.CanRefreshFile);
            this.FileDoubleClickCommand = new VCommand(this.FileDoubleClick);
        }

        // ==========================================================================
        // Config
        // ==========================================================================

        /// <summary>
        /// 项目根路径
        /// </summary>
        private static readonly string PROJECT_ROOT_FOLDER = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Projects");

        // ==========================================================================
        // Controller & Service
        // ==========================================================================

        /// <summary>
        /// 文件服务
        /// </summary>
        private FileService fileService = new FileService();

        // ==========================================================================
        // Property
        // ==========================================================================

        #region IsFolderLoading -- 文件夹是否处于加载中

        private bool isFolderLoading;
        /// <summary>
        /// 文件夹是否处于加载中
        /// </summary>
        public bool IsFolderLoading
        {
            get { return isFolderLoading; }
            set { isFolderLoading = value; this.RaisePropertyChanged(nameof(IsFolderLoading)); }
        }

        #endregion

        #region IsFileLoading -- 文件是否处于加载中

        private bool isFileLoading;
        /// <summary>
        /// 文件是否处于加载中
        /// </summary>
        public bool IsFileLoading
        {
            get { return isFileLoading; }
            set { isFileLoading = value; this.RaisePropertyChanged(nameof(IsFileLoading)); }
        }

        #endregion

        #region IsFilePanelEnabled -- 文件面板是否可用

        private bool isFilePanelEnabled = true;
        /// <summary>
        /// 文件面板是否可用
        /// </summary>
        public bool IsFilePanelEnabled
        {
            get { return isFilePanelEnabled; }
            set { isFilePanelEnabled = value; this.RaisePropertyChanged(nameof(IsFilePanelEnabled)); }
        }

        #endregion

        #region RootFolder -- 根文件夹目录

        private FolderModel rootFolder;
        /// <summary>
        /// 根文件夹目录
        /// </summary>
        public FolderModel RootFolder
        {
            get { return rootFolder; }
            set { rootFolder = value; this.RaisePropertyChanged(nameof(RootFolder)); }
        }

        #endregion

        #region FolderModels -- 文件夹列表

        private ObservableCollection<FolderModel> folderModels;
        /// <summary>
        /// 文件夹列表
        /// </summary>
        public ObservableCollection<FolderModel> FolderModels
        {
            get { return folderModels; }
            set { folderModels = value; this.RaisePropertyChanged(nameof(FolderModels)); }
        }

        #endregion

        #region FileModels -- 文件列表

        private ObservableCollection<FileModel> fileModels;
        /// <summary>
        /// 文件列表
        /// </summary>
        public ObservableCollection<FileModel> FileModels
        {
            get { return fileModels; }
            set { fileModels = value; this.RaisePropertyChanged(nameof(FileModels)); }
        }

        #endregion

        #region SelectedFolderModel -- 当前选中的文件夹

        private FolderModel selectedFolderModel;
        /// <summary>
        /// 当前选中的文件夹
        /// </summary>
        public FolderModel SelectedFolderModel
        {
            get { return selectedFolderModel; }
            set
            {
                selectedFolderModel = value;
                this.RaisePropertyChanged(nameof(SelectedFolderModel));

                this.FileModels = value?.Files;
                this.SelectedFileModel = null;

                this.TryLoadFolders(value, false);
                this.TryLoadFiles(value, false);
            }
        }

        #endregion

        #region SelectedFileModel -- 当前选中的文件

        private FileModel selectedFileModel;
        /// <summary>
        /// 当前选中的文件
        /// </summary>
        public FileModel SelectedFileModel
        {
            get { return selectedFileModel; }
            set
            {
                FileModel oldValue = this.selectedFileModel;
                FileModel newValue = value;
                selectedFileModel = newValue;
                this.RaisePropertyChanged(nameof(SelectedFileModel));
                this.OnSelectedFileModelChanged(oldValue, newValue);
            }
        }

        #endregion

        #region SelectedFileModels -- 当前选中的文件列表

        private IList selectedFileModels;
        /// <summary>
        /// 当前选中的文件列表
        /// </summary>
        public IList SelectedFileModels
        {
            get { return selectedFileModels; }
            set { selectedFileModels = value; this.RaisePropertyChanged(nameof(SelectedFileModels)); }
        }

        #endregion

        #region WaitCopyFileModels -- 待拷贝文件集合

        private ObservableCollection<FileModel> waitCopyFileModels;
        /// <summary>
        /// 待拷贝文件集合
        /// </summary>
        public ObservableCollection<FileModel> WaitCopyFileModels
        {
            get { return waitCopyFileModels; }
            set { waitCopyFileModels = value; this.RaisePropertyChanged(nameof(WaitCopyFileModels)); }
        }

        #endregion

        // ==========================================================================
        // Command
        // ==========================================================================

        #region LoadedCommand -- 加载命令

        /// <summary>
        /// 加载命令
        /// </summary>
        public VCommand LoadedCommand { get; set; }

        /// <summary>
        /// 加载
        /// </summary>
        private void Loaded()
        {
            if (!System.IO.Directory.Exists(PROJECT_ROOT_FOLDER))
            {
                System.IO.Directory.CreateDirectory(PROJECT_ROOT_FOLDER);
            }

            this.RootFolder = new FolderModel(PROJECT_ROOT_FOLDER);
            this.FolderModels = new ObservableCollection<FolderModel> { this.RootFolder };
            this.TryLoadFolders(this.RootFolder, true);
        }

        #endregion

        #region FolderExpandCommand -- 文件夹展开命令

        /// <summary>
        /// 文件夹展开命令
        /// </summary>
        public VCommand<DevExpress.Xpf.Grid.TreeList.NodeDoubleClickEventArgs> FolderExpandCommand { get; set; }

        /// <summary>
        /// 文件夹展开
        /// </summary>
        private void FolderExpand(DevExpress.Xpf.Grid.TreeList.NodeDoubleClickEventArgs e)
        {
            if (this.SelectedFolderModel == null || e.ChangedButton != System.Windows.Input.MouseButton.Left)
                return;

            this.SelectedFolderModel.IsExpand = !this.SelectedFolderModel.IsExpand;
        }

        #endregion

        #region FolderExpandingCommand -- 文件夾打开前命令

        /// <summary>
        /// 文件夾打开前命令
        /// </summary>
        public VCommand<DevExpress.Xpf.Grid.TreeList.TreeViewNodeAllowEventArgs> FolderExpandingCommand { get; set; }

        /// <summary>
        /// 文件夾打开前
        /// </summary>
        /// <param name="e">事件参数</param>
        private void FolderExpanding(DevExpress.Xpf.Grid.TreeList.TreeViewNodeAllowEventArgs e)
        {
            FolderModel folder = e.Node?.Content as FolderModel;
            if (folder == null || folder.IsLoadedFolder)
                return;

            this.TryLoadFolders(folder, false);
        }

        #endregion

        // -------------------------------------------------
        // 文件夹

        #region FolderContentMenuOpendCommand -- 文件夹右键菜单打开命令

        /// <summary>
        /// 文件夹右键菜单打开命令
        /// </summary>
        public VCommand FolderContentMenuOpendCommand { get; set; }

        /// <summary>
        /// 文件夹右键菜单打开
        /// </summary>
        private void FolderContentMenuOpend()
        {
            this.CreateFolderCommand?.RaiseCanExecute();
            this.DeleteFolderCommand?.RaiseCanExecute();
        }

        #endregion

        #region CreateFolderCommand -- 新建文件夹命令

        /// <summary>
        /// 新建文件夹命令
        /// </summary>
        public VCommand CreateFolderCommand { get; set; }

        /// <summary>
        /// 是否可以创建文件夹
        /// </summary>
        /// <returns>是否可以创建文件夹</returns>
        private bool CanCreateFolder()
        {
            return this.SelectedFolderModel != null;
        }

        /// <summary>
        /// 新建文件夹
        /// </summary>
        private void CreateFolder()
        {
            if (this.SelectedFolderModel == null)
                return;

            TextInputWindow window = new TextInputWindow();
            window.Owner = this.GetWindow();
            TextInputControlModel vm = window.DataContext as TextInputControlModel;
            vm.Label = "文件夹名：";
            window.ShowDialog();

            if (window.DialogResult != true)
                return;

            try
            {
                FolderModel folder = this.fileService.CreateFolder(this.SelectedFolderModel, vm.Text);
                this.SelectedFolderModel.Folders.Add(folder);
            }
            catch (Exception ex)
            {
                DXMessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region DeleteFolderCommand -- 删除文件夹命令

        /// <summary>
        /// 删除文件夹命令
        /// </summary>
        public VCommand DeleteFolderCommand { get; set; }

        /// <summary>
        /// 是否可以删除文件夹
        /// </summary>
        /// <returns>是否可以删除文件夹</returns>
        private bool CanDeleteFolder()
        {
            return this.SelectedFolderModel != null && this.SelectedFolderModel != this.RootFolder;
        }

        /// <summary>
        /// 删除文件夹
        /// </summary>
        private void DeleteFolder()
        {
            if (this.SelectedFolderModel == null || this.SelectedFolderModel == this.RootFolder)
                return;

            var result = DXMessageBox.Show($"确定删除文件夹: \"{this.SelectedFolderModel.Path}\" ?", "提示", System.Windows.MessageBoxButton.YesNo);
            if (result != System.Windows.MessageBoxResult.Yes)
                return;

            this.fileService.DeleteFolder(this.SelectedFolderModel);
            this.SelectedFolderModel.Parent.Folders.Remove(this.SelectedFolderModel);
            this.SelectedFolderModel = null;
        }

        #endregion

        #region RefreshFolderCommand -- 刷新文件夹命令

        /// <summary>
        /// 刷新文件夹命令
        /// </summary>
        public VCommand RefreshFolderCommand { get; set; }

        /// <summary>
        /// 刷新文件夹
        /// </summary>
        private void RefreshFolder()
        {
            this.TryLoadFolders(this.RootFolder, true);
        }

        #endregion

        // -------------------------------------------------
        // 文件

        #region FileContentMenuOpendCommand -- 文件右键菜单打开命令

        /// <summary>
        /// 文件右键菜单打开命令
        /// </summary>
        public VCommand FileContentMenuOpendCommand { get; set; }

        /// <summary>
        /// 文件右键菜单打开
        /// </summary>
        private void FileContentMenuOpend()
        {
            this.DeleteFileCommand.RaiseCanExecute();
        }

        #endregion

        #region DeleteFileCommand -- 删除文件命令

        /// <summary>
        /// 删除文件命令
        /// </summary>
        public VCommand DeleteFileCommand { get; set; }

        /// <summary>
        /// 是否可以删除文件
        /// </summary>
        /// <returns>是否可以删除文件</returns>
        private bool CanDeleteFile()
        {
            return this.SelectedFileModels != null && this.SelectedFileModels.Count > 0;
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        private void DeleteFile()
        {
            try
            {
                if (this.SelectedFileModels == null || this.SelectedFileModels.Count == 0)
                    return;

                var result = DXMessageBox.Show($"确定删除项 ?", "提示", System.Windows.MessageBoxButton.YesNo);
                if (result != System.Windows.MessageBoxResult.Yes)
                    return;

                foreach (FileModel file in this.SelectedFileModels)
                {
                    this.fileService.DeleteFile(file);
                }

                this.TryLoadFiles(this.SelectedFolderModel, true);
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        #endregion

        #region RefreshFileCommand -- 刷新文件命令

        /// <summary>
        /// 刷新文件命令
        /// </summary>
        public VCommand RefreshFileCommand { get; set; }

        /// <summary>
        /// 是否可以刷新文件
        /// </summary>
        /// <returns>是否可以刷新文件</returns>
        private bool CanRefreshFile()
        {
            return this.SelectedFolderModel != null;
        }

        /// <summary>
        /// 刷新文件
        /// </summary>
        private void RefreshFile()
        {
            if (this.SelectedFolderModel == null)
                return;

            this.TryLoadFiles(this.SelectedFolderModel, true);
        }

        #endregion

        #region FileDoubleClickCommand -- 文件双击命令

        /// <summary>
        /// 文件双击命令
        /// </summary>
        public VCommand FileDoubleClickCommand { get; set; }

        /// <summary>
        /// 文件双击命令
        /// </summary>
        private void FileDoubleClick()
        {
            this.OnFileDoubleClick();
        }

        #endregion

        // ==========================================================================
        // Private Function
        // ==========================================================================

        /// <summary>
        /// 选中的文件改变时触发
        /// </summary>
        /// <param name="oldValue">旧值</param>
        /// <param name="newValue">新值</param>
        protected virtual void OnSelectedFileModelChanged(FileModel oldValue, FileModel newValue)
        {

        }

        /// <summary>
        /// 文件双击时触发
        /// </summary>
        protected virtual void OnFileDoubleClick()
        {

        }

        // ==========================================================================
        // Private Function
        // ==========================================================================

        /// <summary>
        /// 尝试加载文件夹
        /// </summary>
        /// <param name="folder">文件夹</param>
        /// <param name="isForce">是否强制刷新</param>
        private void TryLoadFolders(FolderModel folder, bool isForce)
        {
            if (folder == null)
                return;

            // 如果文件夹已经加载过文件 & 不需要强制刷新 那么不处理 
            if (folder.IsLoadedFolder && !isForce)
                return;

            this.IsFolderLoading = true;

            ThreadHelper.SafeRun(() =>
            {
                var folders = this.fileService.GetFolders(folder.Path);

                folders.ForEach(p =>
                {
                    p.Parent = folder;
                });

                WPFHelper.BeginInvoke(() =>
                {
                    folder.Folders.Clear();
                    folder.Folders.AddRange(folders);
                    folder.IsLoadedFolder = true;
                    this.IsFolderLoading = false;
                });
            });
        }

        /// <summary>
        /// 尝试加载文件
        /// </summary>
        /// <param name="folder">文件夹</param>
        /// <param name="isForce">是否强制刷新</param>
        private void TryLoadFiles(FolderModel folder, bool isForce)
        {
            if (folder == null)
                return;

            // 如果文件夹已经加载过文件 & 不需要强制刷新 那么不处理 
            if (folder.IsLoadedFiles && !isForce)
                return;

            this.IsFileLoading = true;

            ThreadHelper.SafeRun(() =>
            {
                var files = this.fileService.GetFiles(folder.Path, $"*{ApplicationConstants.PROJECT_FILE_EXTENSION}");
                // 排除数据库日志文件
                files = files.Where(p => !p.Name.ToLower().EndsWith(ApplicationConstants.PROJECT_FILE_LOG_NAME_SUFFIX)).ToList();
                files.ForEach(p =>
                {
                    p.Parent = folder;
                });

                WPFHelper.BeginInvoke(() =>
                {
                    folder.Files.Clear();
                    folder.Files.AddRange(files);
                    folder.IsLoadedFiles = true;
                    this.IsFileLoading = false;
                });
            });
        }
    }
}