using DevExpress.Xpf.Core;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using VIZ.Framework.Core;
using VIZ.Package.Connection;
using VIZ.Package.Domain;
using VIZ.Package.Service;
using VIZ.Package.Storage;

namespace VIZ.Package.Module
{
    /// <summary>
    /// Viz预览视图模型
    /// </summary>
    public class VizPreviewViewModel : ViewModelBase
    {
        /// <summary>
        /// 日志
        /// </summary>
        private readonly static ILog log = LogManager.GetLogger(typeof(VizPreviewViewModel));

        public VizPreviewViewModel()
        {
            // 初始化控制器
            this.initController();

            // 初始化命令
            this.initCommand();

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

        /// <summary>
        /// 初始化命令
        /// </summary>
        private void initCommand()
        {
            this.LoadedCommand = new VCommand(this.Loaded);
            this.WindowHostSizeChangedCommand = new VCommand<SizeChangedEventArgs>(this.WindowHostSizeChanged);
            this.RestartPreviewCommand = new VCommand(this.RestartPreview);
            this.PlayCommand = new VCommand(this.Play);
            this.ContinueCommand = new VCommand(this.Continue);
            this.StopCommand = new VCommand(this.Stop);
            this.ShowRGBCommand = new VCommand(this.ShowRGB);
            this.ShowKeyCommand = new VCommand(this.ShowKey);
            this.ShowKeyPreviewCommand = new VCommand(this.ShowKeyPreview);
        }

        /// <summary>
        /// 初始化控制器
        /// </summary>
        private void initController()
        {
            this.vizPreviewController = new VizPreviewController(this);
        }

        /// <summary>
        /// 初始化消息
        /// </summary>
        private void initMessage()
        {
            ApplicationDomainEx.MessageManager.Register<PageOpenMessage>(this, this.OnPageOpenMessage);
            ApplicationDomainEx.MessageManager.Register<ApplicationClosedMessage>(this, this.OnApplicationClosedMessage);
            ApplicationDomainEx.MessageManager.Register<ControlFieldChangedMessage>(this, this.OnControlFieldChangedMessage);
            ApplicationDomainEx.MessageManager.Register<ControlListFieldChangedMessage>(this, this.OnControlListFieldChangedMessage);
            ApplicationDomainEx.MessageManager.Register<VizPreviewReadyMessage>(this, this.OnVizPreviewReadyMessage);
        }

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

        #region IsShowTS -- 是否显示安全框

        private bool isShowTS;
        /// <summary>
        /// 是否显示安全框
        /// </summary>
        public bool IsShowTS
        {
            get { return isShowTS; }
            set
            {
                isShowTS = value;
                this.RaisePropertyChanged(nameof(IsShowTS));
                this.IsShowTSChanged();
            }
        }

        #endregion

        #region IsShowSA -- 是否显示安全区域

        private bool isShowSA;
        /// <summary>
        /// 是否显示安全区域
        /// </summary>
        public bool IsShowSA
        {
            get { return isShowSA; }
            set
            {
                isShowSA = value;
                this.RaisePropertyChanged(nameof(IsShowSA));
                this.IsShowSAChanged();
            }
        }

        #endregion

        #region IsShowBB -- 是否显示安全框区域

        private bool isShowBB;
        /// <summary>
        /// 是否显示安全框区域
        /// </summary>
        public bool IsShowBB
        {
            get { return isShowBB; }
            set
            {
                isShowBB = value;
                this.RaisePropertyChanged(nameof(IsShowBB));
                this.IsShowBBChanged();
            }
        }

        #endregion

        #region IsVizPreviewReadly -- Viz预览是否准备完毕

        private bool isVizPreviewReadly;
        /// <summary>
        /// Viz预览是否准备完毕
        /// </summary>
        public bool IsVizPreviewReadly
        {
            get { return isVizPreviewReadly; }
            set { isVizPreviewReadly = value; this.RaisePropertyChanged(nameof(IsVizPreviewReadly)); }
        }

        #endregion

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

        /// <summary>
        /// Viz预览控制器
        /// </summary>
        private VizPreviewController vizPreviewController;

        /// <summary>
        /// VIZ命令服务
        /// </summary>
        private VizCommandService vizCommandService = new VizCommandService();

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

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

        #region LoadedCommand -- 加载命令

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

        /// <summary>
        /// 加载
        /// </summary>
        private void Loaded()
        {
            if (this.IsAlreadyLoaded)
                return;

            VizPreviewView view = this.GetView<VizPreviewView>();
            if (view == null)
                return;

            // 设置预览状态不可用
            ApplicationDomainEx.IsVizPreviewReadly = false;
            this.IsVizPreviewReadly = false;

            // 启动引擎嵌入线程
            ThreadHelper.SafeRun(() =>
            {
                // 等待能正确获取到界面宽度时再嵌入VIZ引擎
                double width = 0;
                while (width == 0)
                {
                    WPFHelper.Invoke(() =>
                    {
                        width = view.ActualWidth;
                    });

                    System.Threading.Thread.Sleep(500);
                }

                // 启动引擎
                this.StartVizEngine();
            });

            this.IsAlreadyLoaded = true;
        }

        #endregion

        #region WindowHostSizeChangedCommand -- 宿主容器大小改变命令

        /// <summary>
        /// 宿主容器大小改变命令
        /// </summary>
        public VCommand<SizeChangedEventArgs> WindowHostSizeChangedCommand { get; set; }

        /// <summary>
        /// 宿主容器大小改变
        /// </summary>
        private void WindowHostSizeChanged(SizeChangedEventArgs e)
        {
            VizConfigEntity config = ApplicationDomainEx.VizConfig;
            ConnModel conn = ApplicationDomainEx.PreviewConn;

            if (conn == null || !conn.IsConnected)
                return;

            var dpi = WPFHelper.GetDpiByGraphics();

            int width = (int)(e.NewSize.Width * (dpi.X / 96d));
            int height = (int)(e.NewSize.Height * (dpi.Y / 96d));

            ImageHelper.AdjustSize(width, height, 1920, 1080, out width, out height);

            if (config.EngineFullType == EngineFullType.VIZ_Eng3)
            {
                conn.EndpointManager.Send($"RENDERER WINDOW_RESIZE {width} {height}");
            }
            else
            {
                conn.EndpointManager.Send($"{ApplicationDomainEx.VizPreviewRenderer} WINDOW_RESIZE {width} {height}");
            }
        }

        #endregion

        #region RestartPreviewCommand -- 重启预览命令

        /// <summary>
        /// 重启预览命令
        /// </summary>
        public VCommand RestartPreviewCommand { get; set; }

        /// <summary>
        /// 重启预览
        /// </summary>
        private void RestartPreview()
        {
            // 设置预览引擎未准备完毕
            ApplicationDomainEx.IsVizPreviewReadly = false;
            this.IsVizPreviewReadly = false;
            // 清除预览渲染
            ApplicationDomainEx.VizPreviewRenderer = null;

            // 发送Viz引擎重启消息
            VizPreviewRestartMessage msg = new VizPreviewRestartMessage();
            ApplicationDomainEx.MessageManager.Send(msg);

            // 关闭引擎进程
            try
            {
                ApplicationDomainEx.VizPreviewProcess.Kill();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }

            // 启动引擎启动线程
            ThreadHelper.SafeRun(() =>
            {
                // 启动引擎
                this.StartVizEngine();
            });
        }

        #endregion

        #region PlayCommand -- 播放命令

        /// <summary>
        /// 播放命令
        /// </summary>
        public VCommand PlayCommand { get; set; }

        /// <summary>
        /// 播放
        /// </summary>
        private void Play()
        {
            this.Execute((obj, view, conn) =>
                {
                    this.vizCommandService.Start(conn, null, VizLayer.MAIN_LAYER);
                    view?.PreviewIn(conn);
                });
        }

        #endregion

        #region ContinueCommand -- 继续命令

        /// <summary>
        /// 继续命令
        /// </summary>
        public VCommand ContinueCommand { get; set; }

        /// <summary>
        /// 继续
        /// </summary>
        private void Continue()
        {
            this.Execute((obj, view, conn) =>
                {
                    this.vizCommandService.Continue(conn, null, VizLayer.MAIN_LAYER);
                    view?.PreviewContinue(conn);
                });
        }

        #endregion

        #region StopCommand -- 停止命令

        /// <summary>
        /// 停止命令
        /// </summary>
        public VCommand StopCommand { get; set; }

        /// <summary>
        /// 停止
        /// </summary>
        private void Stop()
        {
            this.Execute((obj, view, conn) =>
                {
                    this.vizCommandService.Stop(conn, null, VizLayer.MAIN_LAYER);
                    view?.PreviewOut(conn);
                });
        }

        #endregion

        // --------------------------------
        // 其他

        #region ShowRGBCommand -- 显示RGB命令

        /// <summary>
        /// 显示RGB命令
        /// </summary>
        public VCommand ShowRGBCommand { get; set; }

        /// <summary>
        /// 显示RGB
        /// </summary>
        private void ShowRGB()
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.ShowRGB(ApplicationDomainEx.PreviewConn);
        }

        #endregion

        #region ShowKeyCommand -- 显示键命令

        /// <summary>
        /// 显示键命令
        /// </summary>
        public VCommand ShowKeyCommand { get; set; }

        /// <summary>
        /// 显示键
        /// </summary>
        private void ShowKey()
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.ShowKey(ApplicationDomainEx.PreviewConn);
        }

        #endregion

        #region ShowKeyPreviewCommand -- 显示预览键命令

        /// <summary>
        /// 显示预览键命令
        /// </summary>
        public VCommand ShowKeyPreviewCommand { get; set; }

        /// <summary>
        /// 显示预览键
        /// </summary>
        private void ShowKeyPreview()
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.ShowKeyPreview(ApplicationDomainEx.PreviewConn);
        }

        #endregion

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

        /// <summary>
        /// 页打开消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnPageOpenMessage(PageOpenMessage msg)
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.SetObject(ApplicationDomainEx.PreviewConn, msg.Page.ScenePath, VizLayer.MAIN_LAYER);

            // 发送节目单项初始化完成消息
            WPFHelper.BeginInvoke(() =>
            {
                PageInitedMessage message = new PageInitedMessage();
                message.Page = msg.Page;

                ApplicationDomainEx.MessageManager.Send(message);
            });
        }

        /// <summary>
        /// 应用程序关闭消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnApplicationClosedMessage(ApplicationClosedMessage msg)
        {
            if (ApplicationDomainEx.VizPreviewProcess == null || ApplicationDomainEx.VizPreviewProcess.HasExited)
                return;

            try
            {
                ApplicationDomainEx.VizPreviewProcess.Kill();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        /// <summary>
        /// 控制字段改变时触发
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnControlFieldChangedMessage(ControlFieldChangedMessage msg)
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            // 缺少信息
            if (msg.ControlObject == null || msg.ControlField == null)
                return;

            // 不需要显示区域
            if (!this.IsShowBB)
                return;

            this.vizCommandControlObjectService.ShowFocus(ApplicationDomainEx.PreviewConn, msg.ControlObject, msg.ControlField);
        }

        /// <summary>
        /// 控制列字段改变时触发
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnControlListFieldChangedMessage(ControlListFieldChangedMessage msg)
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            // 缺少信息
            if (msg.ControlObject == null || msg.ControlField == null)
                return;

            // 不需要显示区域
            if (!this.IsShowBB)
                return;

            this.vizCommandControlObjectService.ShowFocus(ApplicationDomainEx.PreviewConn, msg.ControlObject, msg.ControlField, msg.ListLine, msg.FieldIdentifier);
        }

        /// <summary>
        /// 预览准备完毕消息
        /// </summary>
        /// <param name="msg">消息</param>
        private void OnVizPreviewReadyMessage(VizPreviewReadyMessage msg)
        {
            this.IsVizPreviewReadly = true;
        }

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

        /// <summary>
        /// 启动VIZ引擎
        /// </summary>
        public void StartVizEngine()
        {
            VizPreviewView view = this.GetView<VizPreviewView>();
            if (view == null)
                return;

            VizConfigEntity vizConfig = ApplicationDomainEx.VizConfig;
            ConnGroupModel connGroup = new ConnGroupModel();
            connGroup.Name = "预览";
            connGroup.IsEnabled = true;
            connGroup.IsLocalPreview = true;

            ConnModel conn = ApplicationDomainEx.PreviewConn;
            if (conn != null)
            {
                conn.Dispose();
            }

            conn = new ConnModel();
            conn.IP = vizConfig.VIZ_IP;
            conn.Port = vizConfig.VIZ_Port;
            conn.Remark = "预览";
            conn.IsEnabled = true;
            conn.InitEndpointManager(connGroup, new VizEndpointManager("local", vizConfig.VIZ_IP, vizConfig.VIZ_Port));

            connGroup.Items.Clear();
            connGroup.Items.Add(conn);

            ApplicationDomainEx.PreviewConnGroup = connGroup;
            ApplicationDomainEx.PreviewConn = conn;

            string path = null;

            switch (vizConfig.EngineFullType)
            {
                case EngineFullType.VIZ_Eng3: path = vizConfig.VIZ_Eng3Path; break;
                case EngineFullType.VIZ_Eng4: path = vizConfig.VIZ_Eng4Path; break;
            }

            this.vizPreviewController.StartVizEngine(view, path, conn);
        }

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

        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="action">行为</param>
        private void Execute(Action<ControlObjectModel, IPluginView, ConnModel> action)
        {
            // 是否拥有打开的页或模板页
            if (ApplicationDomainEx.CurrentPage == null)
                return;

            // 插件服务
            IPluginService pluginService = ApplicationDomainEx.ServiceManager.GetService<IPluginService>(ViewServiceKeys.PLUGIN_SERVICE);
            if (pluginService == null)
                return;

            // 控制字段树服务
            IFieldTreeService fieldTreeService = ApplicationDomainEx.ServiceManager.GetService<IFieldTreeService>(ViewServiceKeys.FIELD_TREE_SERVICE);
            if (fieldTreeService == null)
                return;

            ControlObjectModel controlObject = fieldTreeService.GetControlObject();

            // 模板
            if (ApplicationDomainEx.CurrentPage is PageTemplateModel template)
            {
                if (ApplicationDomainEx.PreviewConn != null && ApplicationDomainEx.PreviewConn.IsConnected)
                {
                    action(controlObject, null, ApplicationDomainEx.PreviewConn);
                }
            }
            // 页
            else if (ApplicationDomainEx.CurrentPage is PageModel page)
            {
                IPluginView view = pluginService.GetCurrentPluginView() as IPluginView;

                try
                {
                    if (ApplicationDomainEx.PreviewConn != null && ApplicationDomainEx.PreviewConn.IsConnected)
                    {
                        action(controlObject, view, ApplicationDomainEx.PreviewConn);
                    }
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                }
            }
        }

        /// <summary>
        /// 是否显示安全框改变
        /// </summary>
        private void IsShowTSChanged()
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.ShowTS(ApplicationDomainEx.PreviewConn, this.IsShowTS);
        }

        /// <summary>
        /// 是否显示安全区域改变
        /// </summary>
        private void IsShowSAChanged()
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.ShowSA(ApplicationDomainEx.PreviewConn, this.IsShowSA);
        }

        /// <summary>
        /// 是否显示边框改变
        /// </summary>
        private void IsShowBBChanged()
        {
            // 引擎未准备好 || 当前没有选中的节目单项目 则不处理
            if (!ApplicationDomainEx.IsVizPreviewReadly || ApplicationDomainEx.CurrentPage == null)
                return;

            this.vizCommandService.ShowBB(ApplicationDomainEx.PreviewConn, this.IsShowBB);
        }
    }
}