using LiteDB.Engine;
using log4net;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Core;
using VIZ.Package.Domain;
using VIZ.Package.Service;
using VIZ.Package.Storage;

namespace VIZ.Package.Module
{
    /// <summary>
    /// ScrollElements类型编辑面板模型
    /// </summary>
    public class ScrollElementsEditPanelModel : EditPanelModelBase
    {
        /// <summary>
        /// 日志
        /// </summary>
        private readonly static ILog log = LogManager.GetLogger(typeof(ScrollElementsEditPanelModel));

        /// <summary>
        /// 支持的控制字段类型
        /// </summary>
        private readonly static List<VizControlFieldType> SUPPORT_CONTROL_FIELD_TYPE = new List<VizControlFieldType> { VizControlFieldType.text, VizControlFieldType.richtext, VizControlFieldType.image };

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

            // 初始化消息
            this.InitMessage();
        }

        /// <summary>
        /// 初始化命令
        /// </summary>
        private void InitCommand()
        {
            this.ApplyTemplateCommand = new VCommand(this.ApplyTemplate);
            this.AddCommand = new VCommand(this.Add);
            this.RemoveCommand = new VCommand(this.Remove);

            this.PreviewPlayCommand = new VCommand(this.PreviewPlay);
            this.PreviewContinueCommnad = new VCommand(this.PreviewContinue);
            this.PreviewStopCommand = new VCommand(this.PreviewStop);
            this.PreviewSetPosCommand = new VCommand(this.PreviewSetPos);
        }

        /// <summary>
        /// 初始化消息
        /// </summary>
        private void InitMessage()
        {
            ApplicationDomainEx.MessageManager.Register<PageOpenMessage>(this, this.OnPageOpenMessage);
            ApplicationDomainEx.MessageManager.Register<PageSaveMessage>(this, this.OnPageSaveMessage);
            ApplicationDomainEx.MessageManager.Register<PageSaveAsMessage>(this, this.OnPageSaveAsMessage);
        }

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

        /// <summary>
        /// 控制对象服务
        /// </summary>
        private ControlObjectService controlObjectService = new ControlObjectService();

        /// <summary>
        /// 控制对象命令服务
        /// </summary>
        private VizCommandControlObjectService vizCommandControlObjectService = new VizCommandControlObjectService();

        /// <summary>
        /// 底飞数据服务
        /// </summary>
        private ScrollElementService scrollElementService = new ScrollElementService();

        /// <summary>
        /// 底飞命令服务
        /// </summary>
        private VizCommandElementService vizCommandElementService = new VizCommandElementService();

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

        #region SceneTemplateModels -- 场景模板集合

        private ObservableCollection<PageTemplateModel> sceneTemplateModels;
        /// <summary>
        /// 场景模板集合
        /// </summary>
        public ObservableCollection<PageTemplateModel> SceneTemplateModels
        {
            get { return sceneTemplateModels; }
            set { sceneTemplateModels = value; this.RaisePropertyChanged(nameof(SceneTemplateModels)); }
        }

        #endregion

        #region SelectedSceneTemplateModel -- 当前选中的场景模板

        private PageTemplateModel selectedSceneTemplateModel;
        /// <summary>
        /// 当前选中的场景模板
        /// </summary>
        public PageTemplateModel SelectedSceneTemplateModel
        {
            get { return selectedSceneTemplateModel; }
            set { selectedSceneTemplateModel = value; this.RaisePropertyChanged(nameof(SelectedSceneTemplateModel)); }
        }

        #endregion

        #region Columns -- 列信息集合

        private ObservableCollection<GridColumnScrollElementFieldDefinition> columns;
        /// <summary>
        /// 列信息集合
        /// </summary>
        public ObservableCollection<GridColumnScrollElementFieldDefinition> Columns
        {
            get { return columns; }
            set { columns = value; this.RaisePropertyChanged(nameof(Columns)); }
        }

        #endregion

        #region ItemsSource -- 数据源

        private ObservableCollection<ExpandoObject> itemsSource;
        /// <summary>
        /// 数据源
        /// </summary>
        public ObservableCollection<ExpandoObject> ItemsSource
        {
            get { return itemsSource; }
            set { itemsSource = value; this.RaisePropertyChanged(nameof(ItemsSource)); }
        }

        #endregion

        #region SelectedValue -- 当前选中的数据项

        private ExpandoObject selectedValue;
        /// <summary>
        /// 当前选中的数据项
        /// </summary>
        public ExpandoObject SelectedValue
        {
            get { return selectedValue; }
            set { selectedValue = value; this.RaisePropertyChanged(nameof(SelectedValue)); }
        }

        #endregion

        #region SelectedValues -- 当前选中项的集合

        private ObservableCollection<ExpandoObject> selectedValues = new ObservableCollection<ExpandoObject>();
        /// <summary>
        /// 当前选中项的集合
        /// </summary>
        public ObservableCollection<ExpandoObject> SelectedValues
        {
            get { return selectedValues; }
            set { selectedValues = value; this.RaisePropertyChanged(nameof(SelectedValues)); }
        }

        #endregion

        #region ScrollElementPackage -- 底飞数据包 

        private ScrollElementPackageEntity scrollElementPackage;
        /// <summary>
        /// 底飞数据包
        /// </summary>
        public ScrollElementPackageEntity ScrollElementPackage
        {
            get { return scrollElementPackage; }
            set { scrollElementPackage = value; this.RaisePropertyChanged(nameof(ScrollElementPackage)); }
        }

        #endregion

        #region PreviewPosition -- 预览位置

        private double previewPosition;
        /// <summary>
        /// 预览位置
        /// </summary>
        public double PreviewPosition
        {
            get { return previewPosition; }
            set { previewPosition = value; this.RaisePropertyChanged(nameof(PreviewPosition)); }
        }

        #endregion

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

        #region ApplyTemplateCommand -- 应用模板命令

        /// <summary>
        /// 应用模板命令
        /// </summary>
        public VCommand ApplyTemplateCommand { get; set; }

        /// <summary>
        /// 应用模板
        /// </summary>
        private void ApplyTemplate()
        {
            if (this.SelectedSceneTemplateModel == null)
                return;

            if (this.ControlObject == null)
                return;

            ControlObjectEntity entity = this.controlObjectService.GetControlObject(this.SelectedSceneTemplateModel)?.FirstOrDefault();
            ControlObjectModel controlObject = new ControlObjectModel();
            this.vizCommandControlObjectService.UpdateControlObjectModel(controlObject, entity);

            // 只处理文本与图片类型
            List<ControlFieldNodeModel> scrollElementFields = controlObject.AllFiledNodes.Where(p => SUPPORT_CONTROL_FIELD_TYPE.Contains(p.Type)).ToList();

            // 保存底飞控制字段
            this.ScrollElementPackage = this.scrollElementService.GetScrollElementPackage(ApplicationDomainEx.CurrentPage, this.SelectedSceneTemplateModel, this.ControlField, scrollElementFields);
            this.Columns = this.scrollElementService.GetDynamicColumns(ApplicationDomainEx.CurrentPage, controlObject, scrollElementFields).ToObservableCollection();
            this.ItemsSource = this.scrollElementService.GetDynamicList(scrollElementFields, this.ControlField.Value).ToObservableCollection();
        }

        #endregion

        #region AddCommand -- 添加项命令

        /// <summary>
        /// 添加项命令
        /// </summary>
        public VCommand AddCommand { get; set; }

        /// <summary>
        /// 添加
        /// </summary>
        private void Add()
        {
            IDictionary<string, object> row = new ExpandoObject();
            if (this.Columns != null)
            {
                foreach (GridColumnScrollElementFieldDefinition field in this.Columns)
                {
                    if (field.Type == VizControlFieldType.system_index)
                        continue;

                    row[field.FieldName] = null;
                }
            }

            this.ItemsSource.Add(row as ExpandoObject);
        }

        #endregion

        #region RemoveCommand -- 移除命令

        /// <summary>
        /// 移除命令
        /// </summary>
        public VCommand RemoveCommand { get; set; }

        /// <summary>
        /// 移除
        /// </summary>
        private void Remove()
        {
            if (this.SelectedValues == null || this.SelectedValues.Count == 0)
                return;

            List<ExpandoObject> list = this.SelectedValues.ToList();
            foreach (ExpandoObject item in list)
            {
                this.ItemsSource.Remove(item);
            }
        }

        #endregion

        #region PreviewPlayCommand -- 预览播放命令

        /// <summary>
        /// 预览播放命令
        /// </summary>
        public VCommand PreviewPlayCommand { get; set; }

        /// <summary>
        /// 预览播放
        /// </summary>
        private void PreviewPlay()
        {
            this.vizCommandElementService.PreviewPlay(this.ControlField);
        }

        #endregion

        #region PreviewStopCommand -- 预览停止命令

        /// <summary>
        /// 预览停止命令
        /// </summary>
        public VCommand PreviewStopCommand { get; set; }

        /// <summary>
        /// 预览停止
        /// </summary>
        private void PreviewStop()
        {
            this.vizCommandElementService.PreviewStop(this.ControlField);
            this.PreviewPosition = this.vizCommandElementService.PreviewGetPos(this.ControlField) ?? 0;
        }

        #endregion

        #region PreviewContinueCommand -- 预览继续命令

        /// <summary>
        /// 预览继续命令
        /// </summary>
        public VCommand PreviewContinueCommnad { get; set; }

        /// <summary>
        /// 预览继续
        /// </summary>
        private void PreviewContinue()
        {
            this.vizCommandElementService.PreviewContinue(this.ControlField);
        }

        #endregion

        #region PreviewSetPosCommand -- 预览设置位置命令

        /// <summary>
        /// 预览设置位置命令
        /// </summary>
        public VCommand PreviewSetPosCommand { get; set; }

        /// <summary>
        /// 预览设置位置
        /// </summary>
        private void PreviewSetPos()
        {
            this.vizCommandElementService.PreviewSetPos(this.ControlField, this.PreviewPosition);
        }

        #endregion

        // ============================================================
        // Message
        // ============================================================

        /// <summary>
        /// 页打开消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageOpenMessage(PageOpenMessage msg)
        {
            this.ScrollElementPackage = null;
            this.SceneTemplateModels = null;
            this.SelectedSceneTemplateModel = null;
            this.Columns = null;
            this.ItemsSource = null;
            this.SelectedValue = null;
            this.PreviewPosition = 0;
        }

        /// <summary>
        /// 页保存消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageSaveMessage(PageSaveMessage msg)
        {
            if (this.ScrollElementPackage == null || ApplicationDomainEx.CurrentPage == null || this.ControlField == null)
                return;

            if (this.ScrollElementPackage.TemplateOrPageID != ApplicationDomainEx.CurrentPage.GetTemplateIdOrPageId())
                return;

            if (this.ScrollElementPackage.FieldIdentifier != this.ControlField.FieldIdentifier)
                return;

            this.scrollElementService.SaveScrollElementPackageToDB(this.ScrollElementPackage);
        }

        /// <summary>
        /// 页另存为消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageSaveAsMessage(PageSaveAsMessage msg)
        {
            if (this.ScrollElementPackage == null || ApplicationDomainEx.CurrentPage == null || this.ControlField == null)
                return;

            if (this.ScrollElementPackage.TemplateOrPageID != ApplicationDomainEx.CurrentPage.GetTemplateIdOrPageId())
                return;

            if (this.ScrollElementPackage.FieldIdentifier != this.ControlField.FieldIdentifier)
                return;

            this.scrollElementService.SaveScrollElementPackageToDB(this.ScrollElementPackage);
        }

        // ============================================================
        // Public Function
        // ============================================================

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="controlObject">控制对象</param>
        /// <param name="controlField">控制字段</param>
        public override void Update(ControlObjectModel controlObject, ControlFieldNodeModel controlField)
        {
            base.Update(controlObject, controlField);

            this.IsSendToPreview = false;

            string scrollElementValue = controlField?.Value?.ToString();
            this.TryUpdateScrollElementPackage();

            IPageTemplateService service = ApplicationDomainEx.ServiceManager.GetService<IPageTemplateService>(ViewServiceKeys.PAGE_TEMPLATE_SERVICE);

            this.SceneTemplateModels = service.SceneTemplateModels.Where(p => p.ScenePath != ApplicationDomainEx.CurrentPage?.ScenePath &&
                                                                              p.GetSceneParent() == ApplicationDomainEx.CurrentPage.GetSceneParent()).ToObservableCollection();

            if (this.ScrollElementPackage != null)
            {
                this.SelectedSceneTemplateModel = this.SceneTemplateModels.FirstOrDefault(p => p.ScenePath == this.ScrollElementPackage.TemplateScenePath);
            }

            // 只处理文本与图片类型
            List<ControlFieldNodeModel> fields = new List<ControlFieldNodeModel>();

            if (this.ScrollElementPackage != null && this.ScrollElementPackage.TemplateFields != null)
            {
                foreach (var field in this.ScrollElementPackage.TemplateFields)
                {
                    fields.Add(this.vizCommandControlObjectService.CreateControlFieldNodeModeFromEntity(field));
                }
            }

            this.Columns = this.scrollElementService.GetDynamicColumns(ApplicationDomainEx.CurrentPage, controlObject, fields).ToObservableCollection();
            this.ItemsSource = this.scrollElementService.GetDynamicList(fields, this.ControlField.Value).ToObservableCollection();

            this.IsSendToPreview = true;
        }

        /// <summary>
        /// 更新动态数据
        /// </summary>
        /// <param name="listCellEdit">列单元格编辑器</param>
        /// <param name="columnDefinition">列定义</param>
        /// <param name="rowHandle">行号</param>
        /// <param name="row">行数据</param>
        public override void UpdateDynamic(ListCellEditBase listCellEdit, GridColumnControlFieldDefinition columnDefinition, int rowHandle, ExpandoObject row)
        {
            base.UpdateDynamic(listCellEdit, columnDefinition, rowHandle, row);

            IDictionary<string, object> dic = row as IDictionary<string, object>;

            this.IsSendToPreview = false;

            string scrollElementValue = dic?[columnDefinition.FieldName]?.ToString();
            this.TryUpdateScrollElementPackage();

            IPageTemplateService service = ApplicationDomainEx.ServiceManager.GetService<IPageTemplateService>(ViewServiceKeys.PAGE_TEMPLATE_SERVICE);
            this.SceneTemplateModels = service.SceneTemplateModels.Where(p => p.ScenePath != ApplicationDomainEx.CurrentPage?.ScenePath).ToObservableCollection();
            if (this.ScrollElementPackage != null)
            {
                this.SelectedSceneTemplateModel = this.SceneTemplateModels.FirstOrDefault(p => p.ScenePath == this.ScrollElementPackage.TemplateScenePath);
            }

            // 只处理文本与图片类型
            List<ControlFieldNodeModel> fields = new List<ControlFieldNodeModel>();

            foreach (var field in this.ScrollElementPackage.TemplateFields)
            {
                fields.Add(this.vizCommandControlObjectService.CreateControlFieldNodeModeFromEntity(field));
            }
            this.Columns = this.scrollElementService.GetDynamicColumns(ApplicationDomainEx.CurrentPage, this.ControlObject, fields).ToObservableCollection();
            this.ItemsSource = this.scrollElementService.GetDynamicList(fields, this.ControlField.Value).ToObservableCollection();

            this.IsSendToPreview = true;
        }

        /// <summary>
        /// 获取字段值
        /// </summary>
        /// <returns>字段值</returns>
        public override string GetFieldValue()
        {
            if (this.ScrollElementPackage == null)
                return string.Empty;

            string value = this.scrollElementService.GetScrollElementValue(this.ScrollElementPackage.TemplateScenePath, this.ScrollElementPackage.TemplateFields, this.ItemsSource, VizScrollElementRootTag.entry);

            return value;
        }

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

        /// <summary>
        /// 尝试更新底飞元素数据包
        /// </summary>
        private void TryUpdateScrollElementPackage()
        {
            Guid teplateOrPageId = ApplicationDomainEx.CurrentPage.GetTemplateIdOrPageId();

            // 当前拥有模板且模板与当前选择的页和控制字段匹配则不处理
            if (this.ScrollElementPackage != null && this.ScrollElementPackage.TemplateOrPageID == teplateOrPageId &&
                this.ScrollElementPackage.FieldIdentifier == this.ControlField.FieldIdentifier)
                return;

            this.ScrollElementPackage = this.scrollElementService.GetScrollElementPackageFromDB(ApplicationDomainEx.CurrentPage, this.ControlField);
        }
    }
}
